joselfonseca / lighthouse-graphql-passport-auth

Add GraphQL mutations to get tokens from passport for https://lighthouse-php.com/
https://lighthouse-php-auth.com/
MIT License
231 stars 55 forks source link

Functionality to seed db with password grant client #83

Closed nelsonea closed 4 years ago

nelsonea commented 4 years ago

Is there a way to seed the oauth_clients table with my password grant client information? That way when I re-migrate and re-seed my database, I can automatically populate the password client and secret in the oauth_clients table.

joselfonseca commented 4 years ago

This is something I also want to explore, however in all of our apps we do that as part of the seed in the app not the package. The only annoying thing about that right now for us is changing the env vars when we re seed. Any PR for make that process easy is welcome! I still don't have a clear idea how to change that.

nelsonea commented 4 years ago

Sounds good, thanks for the quick response! I will provide any updates if I come across a solution myself.

MrRobu commented 4 years ago

This is something I also want to explore, however in all of our apps we do that as part of the seed in the app not the package. The only annoying thing about that right now for us is changing the env vars when we re seed. Any PR for make that process easy is welcome! I still don't have a clear idea how to change that.

I don't think this is a really good solution because it's based on the command output and this may change (probably not) but it works for now.

<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            // Production seeders
        ]);

        if ($this->command->confirm('Do you want to add dummy data?', config('app.env') != 'production')) {
            $this->call([
                // Development seeders
            ]);
        }

        if ($this->command->confirm('Do you want to install Passport?', config('app.env') != 'production')) {
            Artisan::call('passport:install');
            $this->command->info("Passport successfully installed.\n");

            $output = Artisan::output();
            $passwordGrantClientOutput = substr($output, strpos($output, "Password grant client"));
            $clientID = $this->getStringBetween($passwordGrantClientOutput, 'Client ID: ', "\n");
            $clientSecret = $this->getStringBetween($passwordGrantClientOutput, 'Client secret: ', "\n");
            $this->setEnvironmentFileVariable(
                'PASSPORT_CLIENT_ID',
                $clientID
            );
            $this->setEnvironmentFileVariable(
                'PASSPORT_CLIENT_SECRET',
                $clientSecret
            );
            $this->command->info('The env file was successfully updated with the new client id and client secret:');
            $this->command->line("PASSPORT_CLIENT_ID=$clientID");
            $this->command->line("PASSPORT_CLIENT_SECRET=$clientSecret\n");
        }
    }

    /**
     * Set Environment File Variable
     *
     * @param string $key
     * @param string $value
     * @return void
     */
    private function setEnvironmentFileVariable(string $key, string $value)
    {
        $path = base_path('.env');

        if (file_exists($path)) {
            file_put_contents($path, str_replace(
                "$key=" . env($key),
                "$key=" . $value,
                file_get_contents($path)
            ));
        }
    }

    /**
     * Get string between two strings
     *
     * @param string $string
     * @param string $start
     * @param string $end
     * @return string
     */
    private function getStringBetween(string $string, string $start, string $end): string
    {
        $string = ' ' . $string;
        $ini = strpos($string, $start);
        if ($ini == 0) return '';
        $ini += strlen($start);
        $len = strpos($string, $end, $ini) - $ini;
        return substr($string, $ini, $len);
    }
}
joselfonseca commented 4 years ago

@MrRobu Thanks for you input. In our case we don't use the env file but actual environment variables set in the container. So this may work if you use the .env file which is fine but in my case it would not work. I'll def think about something for this. @nelsonea maybe this works for you?

MrRobu commented 4 years ago

@MrRobu Thanks for you input. In our case we don't use the env file but actual environment variables set in the container. So this may work if you use the .env file which is fine but in my case it would not work. I'll def think about something for this. @nelsonea maybe this works for you?

@joselfonseca, actually, now I'm trying to find a clean way of injecting these variables in the container as well so the solution I provide doesn't help me either. This solution I use only for development where I share the project code with the container. But in production the project code is copied in container and the .env file is not in part of the image (for security, of course), so I injected the file in docker-compose.yml with the attribute env_file. For now, I create the container, run php artisan passport:install, add the variables to the .env file and than I recreate the container to receive the new variables from the file. Which it's not nice at all. Did you find a good solution to this or you have other kind of setup?

joselfonseca commented 4 years ago

After we deploy to staging or production that does not really change that often and if it does we just update the secret mounted to the container and that is it. @MrRobu