Jwt-auth: Adding custom claims not working

Created on 25 Jul 2018  路  17Comments  路  Source: tymondesigns/jwt-auth

Subject of the issue

How to add custom claims?

Your environment

| Q | A
| ----------------- | ---
| Bug? | no?
| New Feature? | no
| Framework | Laravel
| Framework version | 5.6
| Package version | 1.0.0-rc.2
| PHP version | 7.1.3

Steps to reproduce

Trying to add custom claims to my token:
$token = JWTAuth::attempt($credentials, ['role' => 'test']);
result - not working,

$user = User::first();
$token = JWTAuth::fromUser($user, ['role' => 'test']);
result - not working,

$token = JWTAuth::customClaims(['foo' => 'bar'])->attempt($credentials);
result - not working

Expected behaviour

this should work

Actual behaviour

I'm getting user data only.

Most helpful comment

Have you tested this?
$token = JWTAuth::customClaims(['role' => 'test'])->fromUser($user);

Seems to be the way to go.

All 17 comments

I believe that in rc2, custom claims must be implemented via the JWTSubject interface in the User model with the getJWTCustomClaims method. That allows for claims on the User model if needed which was not available having it tied to attemptin prior versions.

It is still not working, I've set inside User model:

    public function getJWTCustomClaims()
    {
        return [
            'foo' => 'bar',
        ];
    }

and then trying many ways:

        $token = JWTAuth::attempt($credentials);
        $token = JWTAuth::getPayload();

and it's giving error:

"message": "A token is required",
    "exception": "Tymon\\JWTAuth\\Exceptions\\JWTException",
    "file": "C:\\www2\\medpraca2\\vendor\\tymon\\jwt-auth\\src\\JWT.php",
    "line": 331,

Why there is no documentation how to use it?

I get one step closer, using this:

$user = User::first();
$token = JWTAuth::fromUser($user);
$payload = JWTAuth::setToken($token)->getPayload();

it gives my new $payload, but now I cannot access to user from the token, because calling
http://127.0.0.1:8000/api/auth/user
gives me:

exception:"Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException"
file:"C:\www2\medpraca2\vendor\tymon\jwt-auth\src\Http\Middleware\BaseMiddleware.php"
line:74
message:"Wrong number of segments"

and my header is like:

Authorization: Bearer {"iss":"http://127.0.0.1:8000/api/auth/login","iat":1532569847,"exp":1532571647,"nbf":1532569847,"jti":"efkS4XcSM4llfrAX","sub":1,"prv":"87e0af1ef9fd15812fdec97153a14e0b047546aa","foo":"bar"}

instead of:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vMTI3LjAuMC4xOjgwMDAvYXBpL2F1dGgvbG9naW4iLCJpYXQiOjE1MzI1NzAzNjUsImV4cCI6MTUzMjU3MjE2NSwibmJmIjoxNTMyNTcwMzY1LCJqdGkiOiJ6YklPZjQyM2hTQ2pwZ1l3Iiwic3ViIjoxLCJwcnYiOiI4N2UwYWYxZWY5ZmQxNTgxMmZkZWM5NzE1M2ExNGUwYjA0NzU0NmFhIiwiZm9vIjoiYmFyIn0.gPVIGR_vSC6iAOrfxoVLS2amYdYoETi1FNNShX0j7RU

when I was using simple:

$user = User::first();
$token = JWTAuth::fromUser($user);
$payload = $token;

I made it this way:

$user = User::first();
$token = JWTAuth::fromUser($user);
$payload = JWTAuth::setToken($token)->getPayload();
$newToken = JWTAuth::encode($payload);
return response(['status' => 'success'])->header('Authorization', $newToken);

and this is still not working :disappointed:

only primary user data is available, without 'foo': 'bar', despite adding this to User model

    public function getJWTCustomClaims()
    {
        return [
            'foo' => 'bar',
        ];
    }

Why it is not working?

It looks like you are mixing and matching version calls. If you install using"

composer require tymon/jwt-auth:1.0.0-rc.2

... then follow the rest of the installation guide here and quick start here EXACTLY, it should work with any payload. It does for us using Laravel 5.5 or 5.6. If not check the Laravel log and make sure nothing else is going on.

I'm pretty sure I'm doing it correctly (for my level of experience).

As I can see:
Authorization: Bearer {"iss":"http://127.0.0.1:8000/api/auth/login","iat":1532569847,"exp":1532571647,"nbf":1532569847,"jti":"efkS4XcSM4llfrAX","sub":1,"prv":"87e0af1ef9fd15812fdec97153a14e0b047546aa","foo":"bar"}

'foo':'bar' is in correct place (?). Then I encode it and return it to spa app. My plugin is reading user data, but without "foo":"bar".

Maybe there is a problem with websanova/vue-auth plugin that is recovering my token, but I'm not so experienced to check this out...

@gileneusz
I tried this, you write in the User model

public function getJWTCustomClaims()
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email
        ];
    }

with

protected $fillable = [
        'id',
        'name',
        'email',
    ];

result:
screen shot 2018-07-31 at 2 56 15 am

What version of JWT AUth shows in your composer.json file? Also, where and how are you creating and returning the token?

@genyded
"tymon/jwt-auth": "^1.0.0-rc.2",
Do not do anything other than the above

Follow this guide. If you followed the above example, it does not actually invoke Auth which is what sets this. You need to either call attempt() or login() per the guide. There is some stuff in the code above from older versions.

@genyded exactly
Change code in file config/auth.php

'defaults' => [
    'guard' => 'api',
    'passwords' => 'users',
],

.....

'guards' => [
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

Login API

public function login(LoginRequest $request)
{
    $credentials = $request->only('email', 'password');
    try {
            if (!JWTAuth::attempt($credentials)) {
                return response()->json([
                    'message' => 'invalid_credentials',
                    'data' => null
                ], 401);
            }
        } catch (JWTException $e) {
            return response()->json([
                'message' => 'could_not_create_token',
                'data' => null
            ], 500);
        }
        $user = auth()->user();
        $data['token'] = auth()->claims([
            'user_id' => $user->id,
            'name' => $user->name,
            'email' => $user->email,
        ])->attempt($credentials);
        $data['user'] =  $user;
        return response()->json([
            'message' => 'Success',
            'data' => $data
        ]);
}

Have you tested this?
$token = JWTAuth::customClaims(['role' => 'test'])->fromUser($user);

Seems to be the way to go.

I use -v 1.0
You have test :
encode: auth()->claims(['foo' => 'bar'])->login($user);
decode $payload = auth()->payload(); $payload->toArray();
use auth()->userOrFail() only decode $user don`t claims(['foo' => 'bar'])
My english is bad , haha.

@gileneusz
In User Model define method if not

 public function getJWTCustomClaims()
 {
        return ['payload_name' => 'payload_value'];
 }

If you want to add some user information to the payload, you can simply add this in the User model:

public function getJWTCustomClaims()
    {
        return [
            'role' => $this->role
        ];
    }

This way you will be able to take and pass user role through the token

Is this still relevant? If so, what is blocking it? Is there anything you can do to help move it forward?

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

If you want to add some user information to the payload, you can simply add this in the User model:

public function getJWTCustomClaims()
    {
        return [
            'role' => $this->role
        ];
    }

This way you will be able to take and pass user role through the token

Solved the issue for me, even if i don't understand why the customClaims way which is described here is not working (anymore?). It would be a nicer solution in my case as i have mutliple "user" models which all have the same getJWTCustomClaims content (share a global var now).

Was this page helpful?
0 / 5 - 0 ratings

Related issues

harveyslash picture harveyslash  路  3Comments

johncloud200 picture johncloud200  路  3Comments

marciomansur picture marciomansur  路  3Comments

gandra picture gandra  路  3Comments

lloy0076 picture lloy0076  路  3Comments