PHP-Open-Source-Saver / jwt-auth

🔐 JSON Web Token Authentication for Laravel & Lumen
MIT License
729 stars 113 forks source link

setToken (and possibly setRequest) return the previously logged in user #264

Open carvefx opened 3 months ago

carvefx commented 3 months ago

setToken (and possibly setRequest) return the previously logged in user

JwtGuard::setToken and JwtGuard::setRequest, if used in a long-running environment (a la octane etc, or a websockets server in my case) will not reset the user, but simply overwrite the token.

This leads to a behaviour where if there exists a cached user, and you reset the token, and call

$user = auth()->setToken('eyJhb...')->user();

# taken from official docs https://laravel-jwt-auth.readthedocs.io/en/latest/auth-guard/#set-the-token-explicitly

you will get the cached user, instead of the user represented by the new token.

Your environment:

Q A
Bug? yes
New Feature? no
Framework Laravel
Framework version 10.x
Package version 2.7.§
PHP version 8.2

Steps to reproduce

In a loop, log in a user via setting the token, and then do it again with a new token, the user() method will return the original user.

Expected behaviour

setting a token should invalidate the user cache

Actual behaviour

setting a token returns the "previous" / "cached" user

mahdimirhendi commented 2 months ago

Description

Yes I tested and it's serious problem. Here’s a test that demonstrates the problem:


test('user token returns correct user profile', function () {
    // Create and authenticate the first user
    $userOne = User::factory()->create()->refresh();
    $tokenOne = auth('User')->tokenById($userOne->id);
    $responseOne = $this->getJson(route('users.profile'), [
        'Authorization' => "Bearer {$tokenOne}",
    ]);

    // Create and authenticate the second user
    $userTwo = User::factory()->create()->refresh();
    $tokenTwo = auth('User')->tokenById($userTwo->id);
    $responseTwo = $this->getJson(route('users.profile'), [
        'Authorization' => "Bearer {$tokenTwo}",
    ]);

    // Extract user details from the responses
    $userOneDetails = [
        'name' => $userOne->name,
        'token' => $tokenOne,
        'profile' => $responseOne->json(),
    ];

    $userTwoDetails = [
        'name' => $userTwo->name,
        'token' => $tokenTwo,
        'profile' => $responseTwo->json(),
    ];

    // Assert that profiles of different users are not equal
    $this->assertNotEquals(
        $userOneDetails['profile'],
        $userTwoDetails['profile'],
        'The profiles for different users should not be equal.'
    );
});
Messhias commented 2 months ago

The JWT use context to generate tokens, it's not a database token based. So if the state is the same, user will be the same.