jwt-auth
jwt-auth copied to clipboard
Token provides wrong user
I created 2 accounts with different email addresses and passwords. I have a HTTP request that sends the token (stored in local storage after signin) like this:
http://apiurl/api/projects/getProjects?token=tokenString
Inside the method, I used the following line to retrieve the authenticated user based on the token:
$authenticatedUser = JWTAuth::parseToken()->authenticate();
This retrieves the email address for the first account I created, even if I sign in on the second account. For each account the token in the request is different but the authenticatedUser is for the same account every time.
This only ever happens for one specific account, where it thinks I am logged in as a different user. If I remove all my users from the database and create some new accounts, then one of them will have this same issue.
I've seen this problem intermittently but have not yet figured it out.
@aldyson do you have any extra info on this?
@darrynten I have noticed that it only ever happens with one account - i.e. if I create 10 accounts, just one of them will retrieve the incorrect user id, emai land all other details from the token.
Clearing the database and re-creating the accounts doesn't resolve the issue, as it re-occurs on another random account.
It could be version related, as I believe i'm running an older version of the package, but i'm not sure about this.
@darrynten The version shown in my composer.json file is "tymon/jwt-auth": "0.5.*",
@darrynten Do you know anything else about this issue? It's a really big blocker for me at the minute.
I have the same problem, I was testing my API and some tests were failing. At the end these issues seemed to originate in a problem of jwt-auth when it comes to distinguish users.
I wrote a test to verify this assumption and jwt-auth seems indeed to return the wrong user for the provided credentials.
My test is doing something like this:
// 1. Create a db user
$dbUser;
// 2. Get a JWT token
$jwtToken = JWTAuth::attempt([
'email' => $user->email,
'password' => 'secret'
]);
// 3. Call the API that returns the user uuid based on the authorisation bearer
$apiUuid = JWTAuth::toUser()->uuid;
// 4. Compare uuid from db with the one returned by the API
$this->assertEquals($dbUser->uuid, $apiUuid);
I run this test multiple times in a loop. On the first iteration, it works, both uuids are equal, but on the second iteration the uuid returned by jwt-auth is the uuid of the first iteration.
The issue is independent of the number of users in the database: the first iteration works on an empty user table as well as on a populated one.
The tests seem ok, I have no idea how jwt-auth could make such an error. Is there some kind of cache that could be involved?
I had a serious problem with JWT. Following sctoch.io's tutorial for using mongodb with passport.js, I found that out of around 3000 users that I had, some of them were logging in with wrong user info and they could see other user's dashboards. I tried every thing, no clue, then I found one more victime like me. 1-2 times in thousand, people would open wrong user's Id. Finally I decided to remove this json web token thing altogether, and the problem was gone. :( strange that no info is there on the whole internet regarding this weird problem.
I found a solution to this problem:
- If you are on version 0.5.*, update to 1.0.0-rc.3.
- Replace
JWTAuth::toUser()
byauth()->user()
.
I did not try to find out why, but the jwt-auth returns the wrong user when using JWTAuth::toUser()
, at least during tests.
@ntopulos Thank you! I'll try this out and see if it solve the issue for me too. I was hoping that updating the version may solve it so I'll give it a go :)
@aldyson Sorry, but I noticed afterwards that this update caused the authentication to fail elsewhere. Then trying to fix one bug, created a another one and so on. If you give it a try, let us know if you are luckier.
Official documentation for the development version
Anyways, at the end Passport seems to be a wise alternative.
@ntopulos No problem, I'll let you know how it goes.
A quick update on this issue:
I followed steps suggests by @ntopulos and for now (at least) the issue seems to have been resolved. I will test this over the next few days / weeks as the issue wasn't very common in the first place.
For me at least, what seemed to solve this was the following approach -
- Updating
tymon/jwt-auth
from"0.5.*"
to"0.5.12"
- Following the documentation here https://jwt-auth.readthedocs.io/en/develop/laravel-installation/. (Including generating a new secret key).
- In
/config/jwt.php
I made the following changes: -'jwt' => 'Tymon\JWTAuth\Providers\JWT\NamshiAdapter',
to'jwt' => 'Tymon\JWTAuth\Providers\JWT\Namshi',
-'auth' => 'Tymon\JWTAuth\Providers\Auth\IlluminateAuthAdapter',
to'auth' => 'Tymon\JWTAuth\Providers\Auth\Illuminate',
-'storage' => 'Tymon\JWTAuth\Providers\Storage\IlluminateCacheAdapter',
to'storage' => 'Tymon\JWTAuth\Providers\Storage\Illuminate',
- Changed the AuthGuards in
/config/auth.php
to the following:'guards' => [
'web' => [ 'driver' => 'api', 'provider' => 'users', ],
'api' => [ 'driver' => 'jwt', 'provider' => 'users', ],
],
- Replaced
JWTAuth::parseToken()->authenticate()
withauth()->user()
- Applied the
auth:api
middleware on all routes requiring authentication.
I'll update this issue with any potential further issues I find, or if I find that these changes have resolved the issue.
An update on this - The above changes didn't solve the issue and I've given up trying to resolve it. Since it's too much of a blocker I'll be using Firebase which is probably a much better solution based on my own requirements anyway. Hopefully someone can get to the bottom of this though.
still have this issue?if anyone has overcome this problem please provide solution
just have this issue on prod app.. i switch to passport immediately
Had the same issue with mine too. Apparently looking at the payload using JWTAuth::payload(), the "sub" claim was null. The sub claim is the value which contains the user id that matches the user primary key in the database. Since it was null, Laravel picked the first value that existed in the Database. First you need to fix this by adding
public function getKey(){ return $this->ID; }
In your user Model file.
Also make sure you set getJWTIdentifier like this
/** * Get the identifier that will be stored in the subject claim of the JWT. * * @return mixed */ public function getJWTIdentifier() { return $this->getKey(); }
see Documentation
Now if you check the payload using JWTAuth::payload() it should contain a value for "sub" which will be the primary key for the authenticated user.
But mostly likely you'll get an error like this Column not found: 1054 Unknown column '' in 'where clause' (SQL: select * from ... when you try to access a protected route
This is because in Illuminate\Auth\EloquentUserProvider->retrieveById, Laravel tries to get the getAuthIdentifierName from the model but it doesn't exist. so you need to set the getAuthIdentifierName to the name of the primary Key field in your user Model file like this
public function getAuthIdentifierName() { return 'ID'; }
Or you could set it in the config/jwt.php file and get if from the provider/guard whichever suits your coding style. Personally i prefer the simple version above
Hope this helps
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 I do the following,
$user = User::where("email", $email_or_username)->where("email", "!=", "")
->orWhere('username', $email_or_username)->first();
if ($user != null) {
if (Hash::check($password, $user->password)) {
$token = auth('api')->login($user);
return $this->respondWithToken($token);
}
}
$token seems to be a token for the first user example if you put a jwt token in there from this function it returns a sub of 1 every time.
I managed to fix it by doing the following, but it still does not work on the other side,
protected function respondWithToken($token)
{
// JWT Auth provides wrong token, this fixes that problem.
$token = auth('api')->tokenById(auth('api')->user()->id);
// JWT sub is wrong id on send, this fixes that.
return response()->json([
'status' => 'Success',
'message' => 'Authentication was successful, welcome back ' . auth('api')->user()->name . '.',
'access_token' => $token,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60,
'user_name' => auth('api')->user()->username
]);
}
If in a middleware I do the following after,
if (auth('api')->user()) {
$payload = auth('api')->payload();
dd($payload->toArray());
}
the payload sub is 1 again :(
The following fixed the sub being 1 again, but obviously this is not an ideal fix as the header is not validated properly.
if (auth('api')->user()) {
$sub = json_decode(base64_decode(explode(".", $request->header('Authorization'))[1]))->sub;
auth('api')->login(User::where("id", $sub)->first());
}
I encountered a similar error.
I use auth()->user()
, and the user serial number appears intermittently.
There are about 100,000 users in my online project. After logging in to the generated jwt base and decrypting it, I found that the user id of sub is correct. However, the users obtained after parsing by the guards are randomly changed.