Search code examples
laravellaravel-passport

How do I get the client id in a Laravel app?


I've set up a laravel app with client authentification. I send it my client id and client secret and it gives me a token. I'm able to log in to my laravel app, but I can't figure out how to get the id of the client that's been authorized.

I've seen hints to use auth()->user()->Token()->getAttribute('client_id') to get the client id, but since I'm only using clients there is no user and I get an error about trying to call Token() on a null object. Auth::id() also returned nothing. I grabbed the token from the header with Request::header('Authorization'), but it didn't match anything in the database.


Solution

  • I'm assuming you're using client credentials grant tokens, and the CheckClientCredentials middleware.

    You can get this information from the bearer token, but it's not that straightforward. You would need to create a new PSR7 request with the token, and send it off to the oauth server to have it converted to readable data.

    This is already done inside the CheckClientCredentials middleware provided by Passport. So, one way to do this would be to extend the CheckClientCredentials middleware and just manually set the needed fields on the request object from inside the middleware.

    First, create app/Http/Middleware/MyCheckClientCredentials.php:

    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Auth\AuthenticationException;
    use League\OAuth2\Server\Exception\OAuthServerException;
    use Symfony\Bridge\PsrHttpMessage\Factory\DiactorosFactory;
    use Laravel\Passport\Http\Middleware\CheckClientCredentials;
    
    class MyCheckClientCredentials extends CheckClientCredentials
    {
        /**
         * The Resource Server instance.
         *
         * @var \League\OAuth2\Server\ResourceServer
         */
        private $server;
    
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @param  mixed  ...$scopes
         * @return mixed
         * @throws \Illuminate\Auth\AuthenticationException
         */
        public function handle($request, Closure $next, ...$scopes)
        {
            $psr = (new DiactorosFactory)->createRequest($request);
    
            try {
                $psr = $this->server->validateAuthenticatedRequest($psr);
    
                // This is the custom line. Set an "oauth_client_id" field on the
                // request with the client id determined by the bearer token.
                $request['oauth_client_id'] = $psr->getAttribute('oauth_client_id');
    
            } catch (OAuthServerException $e) {
                throw new AuthenticationException;
            }
    
            $this->validateScopes($psr, $scopes);
    
            return $next($request);
        }
    }
    

    Next, update your app/Http/Kernel.php to use your custom middleware instead of the build in Passport middleware:

    protected $routeMiddleware = [
        'client' => \App\Http\Middleware\MyCheckClientCredentials::class,
    ];
    

    Apply the middleware to your route as normal:

    Route::get('/user', function(Request $request) {
        // Should show "oauth_client_id" field.
        dd($request->all());
    })->middleware('client');
    

    If you don't want to do this inside a middleware, you can study how the Passport middleware works and reuse this code in some type of service if you'd like.

    NB: all untested.