Home > Blockchain >  Verify third party JWT with Laravel
Verify third party JWT with Laravel

Time:12-20

I'm using external identity provider to authenticate users, created a SPA client (got client_id & client_secret), configured API with audience & scope, so once users authenticated they will get access_token (will be authorized) to access multiple custom micro-services (APIs).

When my custom API receives a request with a bearer Access Token (JWT) the first thing to do is to validate the token. In order to validate JWT I need to follow these steps:

  1. Check that the JWT is well formed (Parse the JWT)
  2. Check the signature. My external identity provider only supports RS256 via the JWKS (JSON Web Key Set) URL (https://{domain}/.well-known/jwks.json), so I can get my public key following this URL.
  3. Validate the standard claims
  4. Check the Application permissions (scopes)

There are a lot of packages/libraries (i.e. https://github.com/tymondesigns/jwt-auth) to create JWT tokens but I can't find any to validate it using those steps above. Could anyone please help to find suitable Laravel/PHP package/library or move me to the right direction in order to achieve my goals (especially point #2).

CodePudding user response:

I did something similar in the past, I don't know if this may help but I'll give it a try. To use a public key, you should download it, put it somewhere on the disk (storage/jwt/public.pem for example) and then link it in the jwt config config/jwt.php with the ALGO (you can see supported algorithms here

    'keys' => [
        // ...    
        'public' => 'file://'.storage_path('jwt/public.pem'),
        // ...
    ],
    'algo' => 'RS256', 

Then, you should have a custom Guard, let's call it JWTGuard:

<?php
namespace App\Guard;use App\Models\User;
use Illuminate\Auth\GuardHelpers;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Tymon\JWTAuth\JWT;class JWTGuard implements Guard
{
    use GuardHelpers;       
    /**
     * @var JWT $jwt
     */
    protected JWT $jwt;       
    /**
     * @var Request $request
     */
    protected Request $request;    
    /**
     * JWTGuard constructor.
     * @param JWT $jwt
     * @param Request $request
     */
    public function __construct(JWT $jwt, Request $request) {
        $this->jwt = $jwt;
        $this->request = $request;
    }       
    public function user() {
        if (! is_null($this->user)) {
            return $this->user;
        }           
        if ($this->jwt->setRequest($this->request)->getToken() && $this->jwt->check()) {
            $id = $this->jwt->payload()->get('sub');               
            $this->user = new User();
            $this->user->id = $id;
            // Set data from custom claims               
            return $this->user;
        }
        return null;
    }       
    public function validate(array $credentials = []) {    }
}

This should do all your logic of validation, I used a custom user implementation, the class signature was like:

use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
class User extends Model implements AuthenticatableContract {
    // custom implementation
}

Finally, you should register the guard in the AuthServiceProvider and in the auth config

public function boot()
{
  $this->registerPolicies();  
  $this->app['auth']->extend(
    'jwt-auth', 
    function ($app, $name, array $config) {
      $guard = new JWTGuard(
        $app['tymon.jwt'],
        $app['request']
      );      
      $app->refresh('request', $guard, 'setRequest');      
      return $guard;
    }
  );
}

then allow it in the config

<?php
return [
 'defaults' => [
        'guard' => 'jwt',
        'passwords' => 'users',
    ],
 'guards' => [
        // ...
        'jwt' => [
            'driver' => 'jwt-auth',
            'provider' => 'users'
        ],
    ],
 // ...
];

You can then use it as a middleware like this:

Route::middleware('auth:jwt')->get('/user', function() {
    return Auth::user();
}

Does this sound good to you?

CodePudding user response:

In the end I've used the Auth0 SDK for Laravel - https://auth0.com/docs/quickstart/backend/laravel/01-authorization. Nice and clean solution.

  • Related