Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to change the ResponseType #94

Closed
alexjose opened this issue Sep 19, 2016 · 65 comments
Closed

How to change the ResponseType #94

alexjose opened this issue Sep 19, 2016 · 65 comments

Comments

@alexjose
Copy link

Hi,

I want to add some user info into my JWT. It can be done by changing the response type of the authorization server with bearer token supporting extra params.

Ref: https://github.com/thephpleague/oauth2-server/blob/master/tests/ResponseTypes/BearerTokenResponseWithParams.php

But I am not sure how can I change the response type inside the passport.

@craigpaul
Copy link

craigpaul commented Sep 22, 2016

Passport can't really set additional (private) claims the way it is now. In fact, Passport makes use of the php league's League\OAuth2\Server\Entities\Traits\AccessTokenTrait to convert the token to a trait.

/**
 * Generate a JWT from the access token
 *
 * @param CryptKey $privateKey
 *
 * @return string
 */
public function convertToJWT(CryptKey $privateKey)
{
    return (new Builder())
        ->setAudience($this->getClient()->getIdentifier())
        ->setId($this->getIdentifier(), true)
        ->setIssuedAt(time())
        ->setNotBefore(time())
        ->setExpiration($this->getExpiryDateTime()->getTimestamp())
        ->setSubject($this->getUserIdentifier())
        ->set('scopes', $this->getScopes())
        ->sign(new Sha256(), new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase()))
        ->getToken();
}

You'll notice the ->set('scopes', $this->getScopes()) call, that is how a private claim is set using Lcobucci\JWT\Builder. So, short of a pull request to override convertToJWT() on Laravel\Passport\Bridge\AccessToken with some method of adding custom claims, there is no way currently to do so.

@alexjose
Copy link
Author

Thank you for the reply @craigpaul.

Is there any plans to do this implementation any soon?

@craigpaul
Copy link

Wouldn't know, you'd have to ask one of the contributors I suppose? @taylorotwell ?

@wayne5w
Copy link

wayne5w commented Nov 4, 2016

Have the same need. League\OAuth2 provides for extra params (see below) but I don't see how I can override AuthorizationServer::getResponseType since that is in the PassportServiceProvider.

/**
* Add custom fields to your Bearer Token response here, then override
* AuthorizationServer::getResponseType() to pull in your version of
* this class rather than the default.
*
* @param AccessTokenEntityInterface $accessToken
*
* @return array
*/
protected function getExtraParams(AccessTokenEntityInterface $accessToken)
{
return [];
}

@themsaid
Copy link
Member

Hello everyone, looking into this issue but I'm curious to know what type of custom claims can be attached to a token also how do you normally attach those claims while creating the token?

Thank you

@craigpaul
Copy link

craigpaul commented Nov 16, 2016

@themsaid Private claims can be anything that two parties agree on using, they are not limited to a predefined set of keys. Read more about the payload here.

Private claims: These are the custom claims created to share information between parties that agree on using them.

As for how they are normally attached, I'm not sure what you mean, if you're talking about how they are represented in the payload, then here is an example.

{
  "aud": "1",
  "jti": "4ee513a9e858b3b47d09bd5bd522af6bc463fdeb47b6b036b2a2f28ba5b022039f5fe1be61b24aea",
  "iat": 1479267759,
  "nbf": 1479267759,
  "exp": 1480563759,
  "sub": "1",
  "scopes": [],
  // private claims below
  "name": "Taylor Otwell",
  "admin": true,
}

As for how to attach them to the token, we can either attach parameters to the response or attach custom claims to the JWT as they are two different things. To attach parameters to the response we can override the getExtraParams() method like @wayne5w mentioned. If the goal is to attach custom claims to the JWT, then overriding the convertToJWT() method as I've shown above would be the route to take. Personally the convertToJWT() method makes much more sense as it actually attaches it as a claim on the token.

Hope that answers your question, if not let me know and I'll help with whatever I can.

@themsaid
Copy link
Member

@craigpaul thank you for the detailed explanation, that answers my questions :)

I believe the desired behaviour here is to attach custom claims to the JWT, I just need some real world example so that I can work on a proposal with a valid use case, do you have any in mind?

@craigpaul
Copy link

@themsaid I've never personally had a use case for this so I have no idea what a valid example would be. Hopefully @alexjose or @wayne5w have an idea of what they were looking for.

@i906
Copy link

i906 commented Nov 22, 2016

In my use case, my app user has resources that can be accessed through devices or APIs.
The user then can set which resources would be available to which devices.

Let say the user has 3 resources: A, B, C and 2 devices: 1, 2.
Device 1 can access A and B, device 2 can only access C.

I was hoping a token can be created like:

$scopes = [
  'get-resources',
];

$claims = [
  'resources' => ['A', 'B'],
];

// Pass token to device
$token = $user->createToken('Device 1', $scopes, $claims)->accessToken;

Then I would get the claims from the token and validate them in policies, requests or controllers.

$claims = $user->token()->claims;

@chris-rs
Copy link

chris-rs commented Dec 7, 2016

I think this feature is really interesting if the token is consumed by a distant resource service, which relies on valid tokens from the authorization service.
With custom claims the authorization service can inform the resource service about the user. The resource service can act based on the claims. For instance user roles, but user data could also be provided to create a user record at the resource service.

@frankmichel
Copy link

I would love to use this feature as well when consuming my own API.

@lloy0076
Copy link

I've managed to duplicate this code and test that I can see 'dsl' = 'rules' appears in the resulting JWT.

I'm thinking if we add a:

public function __construct($userIdentifier, array $scopes = [], other_claims = [])

...that simply iterated through those claims we're somewhat there.

IF someone thinks this is a good idea, then I'll fork this and fiddle about.

IF someone would be willing to help me figure out how to get a test rig setup and to make the test to test this (there are tests I'm sure and I wouldn't want to introduce a change without them), I'd be really appreciative.

@RDelorier
Copy link
Contributor

I think allowing custom claims would really make the access token much more useful. Rather than only being able to authenticate requests to the api it would allow us to display additional user information without pounding the api for the same simple information over and over.

Static website use case

My user interface is a single page application which is build and served from a cdn. All authentication is handled by my auth service which is running on passport.

Each time the page loads I want to show the current users name and avatar in the header, as well as limit some ui elements based on the roles of the user. Currently I make an ajax call with the token to fetch the user data. With custom claims that ajax call would go away and I could just use something like jwt-decode to get the information I need from the access token itself.

Resource server use case

In addition to the auth service and the front end I have multiple resource servers that must all authorize requests using the auth service as the source of truth.

When a user wants to update a restricted resource I must verify the user has the correct permission to do so. This means I need to make a request to the auth service to retrieve the users permissions before I can proceed. If the permissions were available on the access token then I could use the public key from my auth service to verify and decode the access token then I would have all the information I needed to continue.

Websockets

When users connect to my site I want to connect them to a web socket once they are authenticated, I also want to add their name to a list of online users. Given only the access token I need to again requests the users basic info (name, avatar) from my auth service. If this information were on the access token that would not be necessary. Just like the resource server my socket server could use my auth services public key to validate and decode the token giving me all the information necessary.

@themsaid I hope these use cases are helpful. I'm currently accomplishing this by registering a custom AccessTokenRepository but it would be nice If someone could find a clean way to implement this as a core feature. Here is a gist of my current setup in case it helps https://gist.github.com/RDelorier/9ec45bbb595b7e21c30df80c34b03cac

@rickshawhobo
Copy link

@themsaid It's been 8 months since this was raised. Are there any plans on supporting this? I would prefer a native passport jwt solution versus going with another jwt package.

@JannieT
Copy link

JannieT commented Nov 15, 2017

If you are not too concerned with stuffing the extra parameters inside the token, we have this brittle workaround:

<?php

namespace App;

use League\OAuth2\Server\ResponseTypes\BearerTokenResponse;
use League\OAuth2\Server\Entities\AccessTokenEntityInterface;

class UserMetaBearerTokenResponse extends BearerTokenResponse
{
    protected function getExtraParams(AccessTokenEntityInterface $accessToken)
    {
        $user = User::find($this->accessToken->getUserIdentifier());
        $meta = $user->toArray();
        $meta['club_id'] = 'whatever';
        return $meta;
    }
}

Then this:

<?php
/**
 *  --------------------------------------------------------------------------
 *   NOTE:
 *  --------------------------------------------------------------------------

 *   We are using this override to provide custom response fields that gets
 *   sent with the token when a user is authenticated
 *
 */

namespace App\Providers;

use League\OAuth2\Server\AuthorizationServer;

class PassportServiceProvider extends \Laravel\Passport\PassportServiceProvider
{

    /**
     * Make the authorization service instance.
     * This should keep in step with upgrades to the parent (yikes!):
     *
     * @link https://github.com/laravel/passport/blob/master/src/PassportServiceProvider.php#L196
     *
     * @return League\OAuth2\Server\AuthorizationServer
     */
    public function makeAuthorizationServer()
    {
        return new AuthorizationServer(
            $this->app->make(\Laravel\Passport\Bridge\ClientRepository::class),
            $this->app->make(\Laravel\Passport\Bridge\AccessTokenRepository::class),
            $this->app->make(\Laravel\Passport\Bridge\ScopeRepository::class),
            $this->makeCryptKey('oauth-private.key'),
            app('encrypter')->getKey(),
            $this->app->make(\App\UserMetaBearerTokenResponse::class)  // we add this line
        );
    }
}

@austinjherman
Copy link

Jumping on the bandwagon because I also have a need for custom claims. I'm working on a multi-tenant SaaS application and it would be great if I could store the user's group ID in the token. Especially because my users can belong to multiple groups, so checking which group they currently have access to has been a major challenge so far.

@josh9060
Copy link

Custom claims still haven't been added. At this moment, I have to make a request for a token and then make a request to get my users information - this hurts my feelings.

@lumineida
Copy link

looking for the same feature here... :-(

@jmorey7
Copy link

jmorey7 commented Feb 20, 2018

Need this too.

@bigyanshr
Copy link

bigyanshr commented Mar 19, 2018

I needed this too. I don't know whether my way is recommended but I did the following.

  1. Created an AccessToken class (overrides convertToJWT)
<?php
namespace App\Auth\Model;

use Laravel\Passport\Bridge\AccessToken as PassportAccessToken;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Rsa\Sha256;
use League\OAuth2\Server\CryptKey;

class AccessToken extends PassportAccessToken {
    public function convertToJWT(CryptKey $privateKey)
    {
        return (new Builder())
            ->setAudience($this->getClient()->getIdentifier())
            ->setId($this->getIdentifier(), true)
            ->setIssuedAt(time())
            ->setNotBefore(time())
            ->setExpiration($this->getExpiryDateTime()->getTimestamp())
            ->setSubject($this->getUserIdentifier())
            ->set('scopes', $this->getScopes())
            ->set('roles', $this->getRoles()) // my custom claims
            ->sign(new Sha256(), new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase()))
            ->getToken();
    }

   // my custom claims for roles
   // Just an example. 
    public function getRoles() {
        return [
            'admin',
            'super admin'
        ];
    }
}
  1. Created an AccessTokenRepository class (overrides getNewToken)
<?php
namespace App\Auth\Repository;

use App\Auth\Model\AccessToken; // AccessToken from step 1
use League\OAuth2\Server\Entities\ClientEntityInterface;
use Laravel\Passport\Bridge\AccessTokenRepository as PassportAccessTokenRepository;

class AccessTokenRepository extends PassportAccessTokenRepository
{
    public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null)
    {
        return new AccessToken($userIdentifier, $scopes); // AccessToken from step 1
    }
}
  1. Created a PassportServiceProvider class (overrides makeAuthorizationServer)
<?php

namespace App\Auth\Providers;

use League\OAuth2\Server\AuthorizationServer;

class PassportServiceProvider extends \Laravel\Passport\PassportServiceProvider
{
    public function makeAuthorizationServer()
    {
        return new AuthorizationServer(
            $this->app->make(\Laravel\Passport\Bridge\ClientRepository::class),
            $this->app->make(\App\Auth\Repository\AccessTokenRepository::class), // AccessTokenRepository from step 2
            $this->app->make(\Laravel\Passport\Bridge\ScopeRepository::class),
            $this->makeCryptKey('oauth-private.key'),
            app('encrypter')->getKey()
        );
    }

}
  1. Updated config/app.php
'providers' => [
       ...
      App\Auth\Providers\PassportServiceProvider::class // PassportServiceProvider from step 3
 ],

The resulting JWT created should be something like below:

{
  "aud": "2",
  "jti": "844d6e40f67aff3082db669b54ac5e02d0307f98d7724e5db266faa94fcaff9712570847c782978a",
  "iat": 1521428436,
  "nbf": 1521428436,
  "exp": 1552964436,
  "sub": "1",
  "scopes": [],
  "roles": [
    "admin",
    "super admin"
  ]
}

@atrauzzi
Copy link

atrauzzi commented Jul 2, 2018

Claims support is a fairly essential part of any stateless identity framework. Would love to know when this is going to be implemented.

Basic gist here would be that some time after successful authentication, we need a place to hook code that returns a dictionary of claims.

As I mention in the issue I link below, my use case is including more than the user's ID in the token. Specifically the tenant the token applies to as well as the current organization.

cc. #676

@yavuzkoca
Copy link

In 3rd step, there is use App\Auth\TokenServer; What is it?

@bigyanshr
Copy link

@yavuzkoca you can remove that line.

@bkvishe
Copy link

bkvishe commented Aug 25, 2018

@JannieT Your answer worked for me but i suggest a change; pass only 'private' keyword rather than 'oauth-private.key' to 'makeCryptKey' function.

@anasmorahhib
Copy link

@onamfc
It works well for me in Laravel 6.
thank you all.

@m1stermanager
Copy link

if this ever does get implemented, it would be outstanding to have a way to check claims as easily as you can check scopes via middleware, helper methods etc. I got really far with @onamfc's gist (thank you so much) but needing to check the claim values in middleware and still wanting to use Passport::actingAs in my tests made me fallback to scopes.

Might be for the best? But I would love to have the option of doing one or both.... my experience with past oauth/jwt implementations have not made this difficult at all, though obviously the advantages of laravel as a whole outweigh this particular concern.

@m1stermanager
Copy link

in the future i may abandon scopes for this and add in the custom claim stuff above and supply my own token model to include those claims in the DB somewhere so I can build a middleware around it that checks for a combination of feature set the user has access to and scope granted to a token? I hate that I can't just get at the claims on the token (unless i can and i don't know how). as of now the scopes drive the whole thing in what feels like a very unnatural way

@corbosman
Copy link

We've been extending Passport to add custom claims for a while now. We currently use a method similar to the gist a few posts up. Today I had a look if it would be possible to extract claims support into a package. I made a quick proof-of-concept. It seems to work in our Passport setup, but feel free to play with it and maybe report back on the package issue tracker. I'd love to hear people's ideas about it. This is for the current version of Passport, it likely won't work for previous versions yet.

https://github.com/corbosman/laravel-passport-claims

@corbosman
Copy link

We are currently running the above package in production, and I know of 2 others that do as well, so I guess it's all working fine. I'll keep it updated as newer versions of Passport appear and this issue hasn't been resolved in Laravel Passport itself in some way.

@achetronic
Copy link

achetronic commented May 14, 2020

We are currently running the above package in production, and I know of 2 others that do as well, so I guess it's all working fine. I'll keep it updated as newer versions of Passport appear and this issue hasn't been resolved in Laravel Passport itself in some way.

I did an article for who that want to do this and don't know how to. Overloading some classes (less as I can). I hope this help others in the future
The post about it

I have done and tested it with Laravel 6 y Passport 7.5

@p-jk
Copy link

p-jk commented May 21, 2020

@onamfc It worked in Laravel 5.8. Thanks! <3

@Exotelis
Copy link

Exotelis commented Jun 2, 2020

We are currently running the above package in production, and I know of 2 others that do as well, so I guess it's all working fine. I'll keep it updated as newer versions of Passport appear and this issue hasn't been resolved in Laravel Passport itself in some way.

Tested it with laravel 7.10.x and laravel passport 8.5.0 and it is working. Great job. Thanks a lot :)
However, this should be supported by default!

@corbosman
Copy link

I don't expect laravel to support this anytime soon, mostly because the league-server package does not really allow for an easy way to do this. Laravel probably does not want to overwrite league trait methods like we're forced to do. There's also plenty of issues about this on the league repo. For now my package gives people a really easy way to add claims to passport JWTs.

@festusiyere
Copy link

For Laravel 8
https://gist.github.com/onamfc/0422da15743918e653888441ba6226ca

This worked perfectly well for me

@corbosman
Copy link

@ifeanyi2667 you can just use my package, see link a few posts up

@festusiyere
Copy link

@ifeanyi2667 you can just use my package, see link a few posts up

Thank you

@avosalmon
Copy link

For Laravel 8 and Passport 10.

<?php

declare(strict_types=1);

namespace App\Auth;

use DateTimeImmutable;
use App\Models\User;
use Laravel\Passport\Bridge\AccessToken as PassportAccessToken;
use League\OAuth2\Server\Entities\Traits\AccessTokenTrait;

class AccessToken extends PassportAccessToken
{
    use AccessTokenTrait;

    /**
     * Generate a JWT from the access token
     *
     * @return Token
     */
    private function convertToJWT()
    {
        $this->initJwtConfiguration();

        return $this->jwtConfiguration->builder()
            ->permittedFor($this->getClient()->getIdentifier())
            ->identifiedBy($this->getIdentifier())
            ->issuedAt(new DateTimeImmutable())
            ->canOnlyBeUsedAfter(new DateTimeImmutable())
            ->expiresAt($this->getExpiryDateTime())
            ->relatedTo((string) $this->getUserIdentifier())
            ->withClaim('scopes', $this->getScopes())
            ->withClaim('user', $this->getUserClaim())
            ->getToken($this->jwtConfiguration->signer(), $this->jwtConfiguration->signingKey());
    }

    /**
     * Get the user claim for the JWT.
     *
     * @return array
     */
    private function getUserClaim()
    {
        $user = User::find($this->getUserIdentifier());

        return [
            'id' => $user->id,
            'name' => $user->name,
            'email' => $user->email,
            'roles' => $user->roles->pluck('name'),
        ];
    }
}

@driesvints
Copy link
Member

Hey all. I've taken some time today to look into this. I agree with @corbosman that atm it's unfeasible for us to overwrite the functionality from league/oauth2-server. If they make changes which we miss we can end up with broken functionality. Therefor we want to wait until they offer us an API for us to easily add custom claims to JWT tokens.

However, @corbosman was so nice to provide a package for this: https://github.com/corbosman/laravel-passport-claims

I've sent in a PR to the docs to include his package so people can find their way to it. Please just remember that you're overriding league/oauth2-server behaviour and can potentially miss any bug fixes or such that they could provide in future releases. I also recommend to advocate and request this feature in league/oauth2-server. After it's been added, we can provide this in Passport natively.

Thanks!

@driesvints
Copy link
Member

The sent in PR to the docs was unfortunately rejected. This means that we're going to hold off until league/oauth2-server offers an API for us to make this possible.

@fredsal
Copy link

fredsal commented Apr 20, 2022

@Bobach22
Copy link

Bobach22 commented May 18, 2022

I needed this too. I don't know whether my way is recommended but I did the following.

  1. Created an AccessToken class (overrides convertToJWT)
<?php
namespace App\Auth\Model;

use Laravel\Passport\Bridge\AccessToken as PassportAccessToken;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Rsa\Sha256;
use League\OAuth2\Server\CryptKey;

class AccessToken extends PassportAccessToken {
    public function convertToJWT(CryptKey $privateKey)
    {
        return (new Builder())
            ->setAudience($this->getClient()->getIdentifier())
            ->setId($this->getIdentifier(), true)
            ->setIssuedAt(time())
            ->setNotBefore(time())
            ->setExpiration($this->getExpiryDateTime()->getTimestamp())
            ->setSubject($this->getUserIdentifier())
            ->set('scopes', $this->getScopes())
            ->set('roles', $this->getRoles()) // my custom claims
            ->sign(new Sha256(), new Key($privateKey->getKeyPath(), $privateKey->getPassPhrase()))
            ->getToken();
    }

   // my custom claims for roles
   // Just an example. 
    public function getRoles() {
        return [
            'admin',
            'super admin'
        ];
    }
}
  1. Created an AccessTokenRepository class (overrides getNewToken)
<?php
namespace App\Auth\Repository;

use App\Auth\Model\AccessToken; // AccessToken from step 1
use League\OAuth2\Server\Entities\ClientEntityInterface;
use Laravel\Passport\Bridge\AccessTokenRepository as PassportAccessTokenRepository;

class AccessTokenRepository extends PassportAccessTokenRepository
{
    public function getNewToken(ClientEntityInterface $clientEntity, array $scopes, $userIdentifier = null)
    {
        return new AccessToken($userIdentifier, $scopes); // AccessToken from step 1
    }
}
  1. Created a PassportServiceProvider class (overrides makeAuthorizationServer)
<?php

namespace App\Auth\Providers;

use League\OAuth2\Server\AuthorizationServer;

class PassportServiceProvider extends \Laravel\Passport\PassportServiceProvider
{
    public function makeAuthorizationServer()
    {
        return new AuthorizationServer(
            $this->app->make(\Laravel\Passport\Bridge\ClientRepository::class),
            $this->app->make(\App\Auth\Repository\AccessTokenRepository::class), // AccessTokenRepository from step 2
            $this->app->make(\Laravel\Passport\Bridge\ScopeRepository::class),
            $this->makeCryptKey('oauth-private.key'),
            app('encrypter')->getKey()
        );
    }

}
  1. Updated config/app.php
'providers' => [
       ...
      App\Auth\Providers\PassportServiceProvider::class // PassportServiceProvider from step 3
 ],

The resulting JWT created should be something like below:

{
  "aud": "2",
  "jti": "844d6e40f67aff3082db669b54ac5e02d0307f98d7724e5db266faa94fcaff9712570847c782978a",
  "iat": 1521428436,
  "nbf": 1521428436,
  "exp": 1552964436,
  "sub": "1",
  "scopes": [],
  "roles": [
    "admin",
    "super admin"
  ]
}

Thanks for the code samples, it really worked, but in my case I encountered some problems . I have 2 resource servers, say I am making a getToken request to Authorization server from server A and want to include custom claims to the token payload ( organizations: [] ), at the same time I need to get that info from server B , but ,say, if I create Personal Access Token for current user (after request want to invalidate/delete, actually other solutions didn't come to my mind for now) to make request to server B (which verifies with public key taken from Authorization server) and server B finds organization info related to current user . But that way it goes into loop . If passport provided a way to include claims to token payload, this way may anyway go into loop. Do you guys have any idea to solve this problem or ever had a similar case in the past?

@AMoktar
Copy link

AMoktar commented Oct 26, 2022

hey guys, any official solution yet ?

@chaotic98
Copy link

@AMoktar not yet #1614

@FreedomArt
Copy link

App\Auth\Providers\PassportServiceProvider::class

У меня не сработало. Вот декодированный токен.
Что делаю не так?

{
"aud": "90",
"jti": "f46
875",
"iat": 1639,
"nbf": 16
42,
"exp": 16**94,
"sub": "1",
"scopes": []
}

@AnissBoua
Copy link

AnissBoua commented Apr 14, 2024

For people tring to do this in 2024 +, Laravel 10.48.

I found an easier way to do this; you still need to create a class that extends from Laravel\Passport\Bridge\AccessToken, like this one :

<?php

namespace App\Passport;

use DateTimeImmutable;
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Rsa\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use Laravel\Passport\Bridge\AccessToken as BaseToken;
use League\OAuth2\Server\CryptKey;

class AccessToken extends BaseToken {

    private $privateKey;
    private $jwtConfiguration;

    public function setPrivateKey(CryptKey $privateKey)
    {
        $this->privateKey = $privateKey;
    }

    public function initJwtConfiguration()
    {
        $this->jwtConfiguration = Configuration::forAsymmetricSigner(
            new Sha256(),
            InMemory::plainText($this->privateKey->getKeyContents(), $this->privateKey->getPassPhrase() ?? ''),
            InMemory::plainText('empty', 'empty')
        );
    }

    public function __toString()
    {
        return $this->convertToJWT()->toString();
    }

    public function convertToJWT() {
        $this->initJwtConfiguration();

        // ID of the user : $this->getUserIdentifier()
        // You can get your user like this : $user = User::find($this->getUserIdentifier()); 

        return $this->jwtConfiguration->builder()
            ->permittedFor($this->getClient()->getIdentifier())
            ->identifiedBy($this->getIdentifier())
            // Removing milliseconds
            ->issuedAt(DateTimeImmutable::createFromFormat('Y-m-d H:i:s', (new DateTimeImmutable())->format('Y-m-d H:i:s')))
            ->canOnlyBeUsedAfter(DateTimeImmutable::createFromFormat('Y-m-d H:i:s', (new DateTimeImmutable())->format('Y-m-d H:i:s')))
            ->expiresAt(DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $this->getExpiryDateTime()->format('Y-m-d H:i:s')))
            ->relatedTo((string) $this->getUserIdentifier())
            ->withClaim('scopes', $this->getScopes())
            // ->withClaim('custom-claims', $this->getUserIdentifier())
            ->getToken($this->jwtConfiguration->signer(), $this->jwtConfiguration->signingKey());
    }
}

Then, the only thing you need to do is modify the app\Providers\AuthServiceProvider.php and set the new AccessTokenEntity with the one you just created :

<?php

namespace App\Providers;

// use Illuminate\Support\Facades\Gate;

use App\Passport\AccessToken;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Laravel\Passport\Passport;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The model to policy mappings for the application.
     *
     * @var array<class-string, class-string>
     */
    protected $policies = [
        //
    ];

    /**
     * Register any authentication / authorization services.
     */
    public function boot(): void
    {
        Passport::useAccessTokenEntity(AccessToken::class);
    }
}

Now Passport will generate tokens using the class you created.

@amsanket22
Copy link

@AnissBoua how do we update the token with new claims?

@AnissBoua
Copy link

@amsanket22 In the convertToJWT method, you just add the claim you want with this line as an example:
->withClaim('<some-claim>', <some-value>)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests