how to using dynamic database connection with middlewere laravel passport - laravel

I removed the database connection information from the env file and database.php file.
And I set the database dynamically with each request from the client.
I do this in main middleware
$origin = $request->header('Origin');
\Config::set(['database.default' => 'mysql']);
\Config::set(['database.connections.mysql.host' => '127.0.0.1']);
\Config::set(['database.connections.mysql.database' => $origin]);
\Config::set(['database.connections.mysql.username' => 'root']);
\Config::set(['database.connections.mysql.port' => '3306']);
I have no problem with the login and the token is created. But in other actions, I get a 401 error
In fact, the passport calls the connection information to the database from the env file or database.php. But we want to do this through middleware, or we can set the database information for it before checking auth: api.

By default, Passport access default DB. If you would like to use dynamic database add below code in the boot method of your app/Providers/AppServiceProvider.php:
public function boot()
{
Config::set('database.connections.pgsql.database', 'newdatabase');
DB::purge('pgsql');
DB::reconnect('pgsql');
}

Related

Using Laravel Test 7 and Laravel Passport 9.3 with Personal Access Client gives exception "Trying to get property 'id' of non-object"

I am designing a custom authentication scheme (based on public keys) alongside a stateless API, and decided Passport would fulfill the need for post-authentication requests.
Assuming the authentication succeeds, and the user is authenticated, they would receive a Personal Access Token, and use the token for all further requests. The trouble I'm experiencing (still after much searching through various forums and Stack Overflow) is that when using Laravel's built in testing suite, on the createToken() method, it generates an (admittedly common) exception:
"ErrorException : Trying to get property 'id' of non-object".
I am able to manually create a user through Tinker, and create a token through Tinker. However I'm experiencing problems when attempting to automate this process after authenticating.
Here is the relevant code snippet post-authentication:
Auth::login($user);
$user = Auth::user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
$token->expires_at = Carbon::now()->addWeeks(1);
$token->save();
return response()->json([
"access_token" => $tokenResult->accessToken,
"token_type" => "Bearer",
"expires_at" => Carbon::parse(
$tokenResult->token->expires_at)->toDateTimeString()
],
200);
I've manually called Auth::login on the user, to ensure the user is logged in, and Auth::user() returns the user (not null). Upon executing the third line of code, the exception is thrown with the following mini stack-trace (I can provide a full stack-trace if requested).
laravel\passport\src\PersonalAccessTokenFactory.php:100
laravel\passport\src\PersonalAccessTokenFactory.php:71
laravel\passport\src\HasApiTokens.php:67
app\Http\Controllers\Auth\LoginController.php:97
laravel\framework\src\Illuminate\Routing\Controller.php:54
laravel\framework\src\Illuminate\Routing\ControllerDispatcher.php:45
From running this through debug a few times- even though the class is called and loaded, and it appears the Client is found through ControllerDispatcher -> Client::find(id) and found in ClientRepository, when it gets to PersonalAccessTokenFactory, the $client passed in is null (which explains why the $client->id can't be found, though I have no idea why the $client is null at this point).
protected function createRequest($client, $userId, array $scopes)
{
$secret = Passport::$hashesClientSecrets ? Passport::$personalAccessClientSecret : $client->secret;
return (new ServerRequest)->withParsedBody([
'grant_type' => 'personal_access',
'client_id' => $client->id,
...
}
Things I have done/tried with some guidance from the documentation and other posts:
Manually created a user in Tinker, and created the token through Tinker- this does work.
Ensured the user is logged in before attempting to generate token.
passport:install (and adding the --force option)
Ensured Personal Access Client is generated with passport:client --personal
Ensured the AuthServiceProvider::boot() contains the ClientID and Client Secret (in the .env).
migrate:refresh followed by passport:install --force
Complete removal of Passport, removing all files, keys, migrations, and DB entries, followed with a migrate:refresh and reinstallation of Passport, along with generating an additional personal access client (even though one is generated during passport:install).
I'm not sure where else to look/what else to try at this point, so any help or guidance would be much appreciated!
I eventually discovered the solution. The problem is multi-layered, in part having to do with outdated Laravel documentation in regards to testing and Passport Personal Access Clients.
The first part of the problem had to do with using the trait RefreshDatabase on my unit test. Since this creates a mock database with empty datasets, although the clients themselves exist in the real database and the .env file, when the test is run, the test does not see those clients as existing in the mock database. To solve this problem, you must create a client in the setup function before the test is run.
public function setUp() : void
{
parent::setUp();
$this->createClient(); //Private method->Full code below
}
This solves the issue about having a null client during testing, but starting in Laravel 7, Laravel added a requirement for Personal Access Clients that the id and the client secret has to be kept inside the .env file. When running the test, the test will see the actual client id and secret in the .env, and fail to validate these with the client that was created and stored in the mock database, returning another exception: "Client Authentication Failed".
The solution to this problem is to create a .env.testing file in your main project directory, copying your .env file contents to it and ensuring that the keys below exist with values for either your main created Personal Access Client, or copying the secret from a client generated just for testing (I would advise the latter).
PASSPORT_PERSONAL_ACCESS_CLIENT_ID=1
PASSPORT_PERSONAL_ACCESS_CLIENT_SECRET=unhashed-client-secret-value
Then using the code below, make sure the $clientSecret value is the same as the key value in your .env.testing file.
private function createClient() : void
{
$clientRepository = new ClientRepository();
$client = $clientRepository->createPersonalAccessClient(
null, 'Test Personal Access Client', 'http://localhost'
);
DB::table('oauth_personal_access_clients')->insert([
'client_id' => $client->id,
'created_at' => new DateTime,
'updated_at' => new DateTime,
]);
$clientSecret = 'unhashed-client-secret-value';
$client->setSecretAttribute($clientSecret);
$client->save();
}
This will create a new client, set the attribute secret to the value in the variable and update the mock database secret to contain the same value. Hopefully this helps anyone with the same issue.
Another way to prevent copy/paste source code is to just call artisan command in the setup method.
public function setUp() {
parent::setUp();
$this->artisan('passport:install');
}
original here
Just use the facade
public function setUp() {
parent::setUp();
Artisan::call('passport:install');}

Laravel and GraphQL : How to use Passport of Laravel for Authentication when using laravel-graphql?

I want to use GraphQL in Laravel,I chose the package laravel-graphql ,my question is:
How to use Passport of Laravel for Authentication when using laravel-graphql?
I haven't used the package myself before, but from looking at the code I would say you can add a middleware in the configuration file config/graphql.php that performs the authentication and/or permission check:
/*
* Any middleware for the 'graphql' route group
*/
'middleware' => ['auth:api'], // or 'auth' for normal authentication
If this doesn't work for you, there is also the possibility to override the controller used by the package. The configuration for this is also in the same configuration file. You could for example extend the existing controller to achieve what you want. Or you write an entirely new one.
at first you have to install laravel passport step by step after install passport then you have to use
#middleware(checks:["auth:api"])
in schema.graphql file

Laravel Passport Password Reset API route

I'm all set up with Passport in 5.5 and have the auto generated Auth\ForgotPasswordController and Auth\ResetPasswordController controllers.
However whereas /oauth/token was provided magically for me, there don't appear to be such routes for password reset when using the API.
What should my API routes look like?
Currently I've experimented with
Route::group(['prefix' => 'password'], function () {
Route::post('/email', 'Auth\ForgotPasswordController#sendResetLinkEmail');
Route::post('/reset', 'Auth\ResetPasswordController#reset');
});
but I found these in the vendor files when looking at the traits and aren't sure if this is the correct way.
The /password/email route also fails with "message": "Route [password.reset] not defined."
since you don't see any route other then 2 custom, therefore i am assumin you havn't run artisan auth command. First run that. it will add lot of routes in ur project.
Then set api driver to passport.

Auth0 Login ServiceProvider

I follow up this tutorial using Laravel 5.4 Creating your first Laravel app and adding authentication
But I can't retrieve Auth0 users, the registration works fine in my dashboard new users are created in Auth0 server, but not in my local database and also I can't dd(Auth0::getUser());
I get this error:
Class 'Auth0\Login\LoginServiceProvider' not found
I've added this
Auth0\Login\LoginServiceProvider::class
in my provider array and
'Auth0' => Auth0\Login\Facade\Auth0::class
in my aliases.
I did all steps on configuration from Auth0 docs: Auth0 PHP (Laravel) SDK
I'm out off option now!
Ok, figure it out now.
The error was coming from 'AppServiceProvider.php'
Just import those two classes in AppServiceProvider.php as:
use Auth0\Login\Contract\Auth0UserRepository as Auth0UserRepositoryContract;
use Auth0\Login\Repository\Auth0UserRepository as Auth0UserRepository;
And then your Register method should look like this:
public function register()
{
$this->app->bind( Auth0UserRepositoryContract::class, Auth0UserRepository::class );
$this->app->bind( Auth0UserRepositoryContract::class, Auth0UserRepository::class );
}
if you want to persist data in your database then Create your own Repository and update the bind method YourCustomerRepositoryContract::class, YourCustomerRepository::class
Just like that.
For more info about creating your own Repository
Auth0 PHP (Laravel) SDK Quickstarts: Login

Where does Laravel's Artisan get session config info from?

My session config file says to use memcached, but all artisan commands are loading the "array" driver instead. I'm writing a web sockets application with Ratchet and need to connect to Memcached to get the user's session information, but seems to ignore my config.
Where and how does Laravel determine which session drivers to use for Artisan commands?
According to Illuminate\Support\ServiceProvider\SessionServiceProvider::setupDefaultDriver() Laravel will set the session driver to array if running in console.
You can easily override this by registering your custom service provider. Create a custom service provider, extend the default session service provider and override the method setupDefaultDriver). Here is my custom service provider for example:
<?php namespace App\Console;
use Illuminate\Session\SessionServiceProvider as DefaultSessionProvider;
class SessionServiceProvider extends DefaultSessionProvider
{
protected function setupDefaultDriver() {}
}
Then open up config/app.php and replace 'Illuminate\Session\SessionServiceProvider' with 'App\Console\SessionServiceProvider'.
Now artisan will also use the same session storage as Laravel app.
Since you are trying to attach the session to Ratchet, You can directly inject this session instance into Ratchet app:
$session = new \Ratchet\Session\SessionProvider(
new MyCustomRatchetApp(),
$this->getLaravel()['session.store']
);
$server = new \Ratchet\App('localhost');
$server->route('/sessDemo', $session);
$server->run();
Gufran posted a good answer, but another solution which doesn't involve swapping out a service provider, it just to set the default driver manually in your artisan command (or tests).
Like so: Session::setDefaultDriver('memcached');. You can do the same for cache: Cache::setDefaultDriver('memcached');. You do this before doing any other commands, of course, so that it doesn't start using the array.
If you need to, you can manually put in connection information: Config::set('cache.memcached', array(array('host' => '127.0.0.1', 'port' => 12345, 'weight' => 100)));

Resources