laravel / passport

Laravel Passport provides OAuth2 server support to Laravel.
https://laravel.com/docs/passport
MIT License
3.28k stars 777 forks source link

Laravel Passport Personal Token failing Validation (exp=0) #47

Closed gbdematos closed 7 years ago

gbdematos commented 8 years ago

I'm trying to create a Personal Access Token to use on Postman.

I followed the same steps as the video from "What's new in Laravel 5.3" where Taylor does that, but I keep getting "Unauthorized" on Postman...

By copying and pasting the generated token on jwt.io, I'm getting "exp" value = 0. Trying to get to the root of the error, I found out that on the "validation" process, it fails exactly on the "exp" validation.

Does anyone have any idea what is happening?

My topic on Laracasts: https://laracasts.com/discuss/channels/laravel/laravel-passport-personal-token-failing-validation-exp0

Another user with the same problem: https://laracasts.com/discuss/channels/laravel/laravel-passport-and-postman-gets-all-the-time-unauthorised

Jonastouw commented 8 years ago

I ran into the same issue, and finally figured out how to make it work. The expiry date is set to now + 100 years in Passport.php, line 167.

return static::$tokensExpireAt
? Carbon::now()->diff(static::$tokensExpireAt)
: new DateInterval('P100Y');

If you set it to, i.e., P1Y, it is working. Something like:

return static::$tokensExpireAt
? Carbon::now()->diff(static::$tokensExpireAt)
: new DateInterval('P1Y');

The same holds true for the refresh token a few lines below:

return static::$refreshTokensExpireAt
? Carbon::now()->diff(static::$refreshTokensExpireAt)
: new DateInterval('P1Y');

And also in PassportServiceProvider.php line 84, concerning the Personal Tokens:

$server->enableGrantType(new PersonalAccessGrant, new DateInterval('P1Y'));

I guess the 100 years DateInterval yields an int (seconds) somewhere along the way that the exp value is not expecting, setting it to zero and invalidating it. Or it might be some Windows only issue. With these edits it's working and we can move on with this awesome package!

gbdematos commented 8 years ago

@Jonastouw I'm trying to do this you described, but no success... Even after altering P100Y to P1Y, the generated tokens are being set to 2116 on the database (and exp to 0).

Is your issue also with Personal Tokens?

I'm thinking how on earth are people not having this issue? I found no reports except mine and another user's. Is it something I did that caused this?

Jonastouw commented 8 years ago

@gbdematos I just updated my post to include the personal tokens. Have you tried setting those as well?

gbdematos commented 8 years ago

@Jonastouw it worked now, modifying PassportServiceProvider.php line 84!! Can't believe it, after two days of headache! Thank you so much!

But I'm still curious, is this normal behavior or something I did or my environment maybe? :/

Should I let this Issue open for verification?

nueko commented 8 years ago

Hmm, is this the Y2038 fx :1234: ?

roulendz commented 8 years ago

I did as needed, and OAuth client started to work! But still Personal Access Tokens Does not authorise me :(

Also I can not self consume API :(

nueko commented 8 years ago

make sure you run php artisan passport:client --personal, try add

Passport::tokensExpireIn(Carbon::now()->addDays(15));
Passport::refreshTokensExpireIn(Carbon::now()->addDays(30));
ryanhungate commented 8 years ago

I've managed to figure out where the problem is coming from ( or it seems )... I just don't know if this will break anything else. I'm sure this is not recommended but at first glance this is what fixed my problem.

inside the \Laravel\Passport\Guards\TokenGuard :

protected function validCsrf($token, $request)
{
    $compare_token = (string) $request->header('X-CSRF-TOKEN');
    if (empty($compare_token)) {
        $compare_token = (string) $request->header('X-XSRF-TOKEN');
    }
    return isset($token['csrf']) && hash_equals(
        $token['csrf'], $this->encrypter->decrypt($compare_token)
    );
}
taftse commented 8 years ago

The best way I have found to bypass this issue without changing any files in the vendor folder is by adding the following 2 lines to the boot method of my AuthServiceProvider after Passport::routes();

Passport::tokensExpireIn(Carbon::now()->addYears(20));

Passport::refreshTokensExpireIn(Carbon::now()->addYears(20));

The longest I was able to create a token for was 21 years before I started getting expiry dates starting with a - (minus) which was unable to be validated

Please see https://laravel.com/docs/5.3/passport#configuration for details on the above code

ryanhungate commented 8 years ago

yeah I had tried something similar where I only added like 30 days, but it still failed when I only had that. I don't know if this is environment related, i'm just using the new Laravel Valet on my mac to test things out. I wonder if I was using Homestead or an Ubuntu box if we get the same results?

gholol commented 8 years ago

Changing the expiration dates did the trick for me, this needs to be fixed asap. :)

jampot5000 commented 8 years ago

@nueko This is exactly the reason, this happens when using a 32bit version of PHP, the solution is to use the 64bit version of PHP instead.

gholol commented 8 years ago

@jampot5000 this can't be the reason as I'm currently using 64bit version of PHP 7.1 and I had the same problem.

erdmenchen commented 8 years ago

Changing the expiration time for private access tokens in the PassportServiceProvider.php $server->enableGrantType(new PersonalAccessGrant, new DateInterval('P100Y')); to e.g. P10Y did the trick for me.

Thanks @Jonastouw !

How can this be changed, so that we don't need to change any code in the vendors files? Maybe a custom Passport::tokensExpireIn for private access tokens is needed?

gholol commented 8 years ago

@erdmenchen A pull request would be sufficient, as at this stage it's not working out of the box.

jampot5000 commented 8 years ago

@gholol odd as switching to the latest 64bit version of PHP resolved the issue for me, is there another PHP in your path?

at the very least x64 php is required with the default configuration maybe the composer file should be updated or the 100y diff reduced to something before 2038.

hari03 commented 8 years ago

Doing the changeover from P100Y to P1Y did the trick for me, however, it's was weird to notice auth:api not mentioned in my api middlewaregroup in app\Http\Kernel.php during installation. I had to fix that as well.

If it helps, your 'api' inside 'middlewaregroups' in app\Http\kernel.php should look like:

'api' => [
'throttle:60,1',
 'bindings',
  'auth:api',
  ],
luiz-brandao commented 8 years ago

It does seem to be the Y2038 problem like @nueko mentioned. On line 25 of \vendor\league\oauth2-server\src\ResponseTypes\BearerTokenResponse.php we have this:

$expireDateTime = $this->accessToken->getExpiryDateTime()->getTimestamp();

In my environment running the 32bit version of PHP, getTimestamp() returns false for dates over 2037.

haseebeqx commented 8 years ago

i think a better a option is to change new DateInterval('P100Y')) to Passport::tokensExpireIn() and specify Passport::tokensExpireIn(Carbon::now()->addDays(15)); inside boot() in authServiceProvider

Chathula commented 8 years ago

it gives another error.. you can't delete the public client token from ui genarated by Vue and Passport.

Console Error

Failed to load resource: the server responded with a status of 500 (Internal Server Error) http://localhost:8000/oauth/personal-access-tokens/fb1173acdafdecdba0d2732025b0cbdb692986982c1900bea70aed73134fdaa75d0fabfebac99091

chris-rs commented 8 years ago

The solution that worked for me was the one proposed by @ryanhungate . But this solution seems to be totally different from the proposed solutions about the 'expirydates'.

Although the solution from @ryanhungate makes sense, I still don't understand why laravel tokens (with embedded csrf token) successfully validate, since the original code in TokenGuard->validCsrf compares an unencrypted CSRF token (included in decrypted laravel token) against an encrypted CSRF token (in header). I guess this comparison will always fail...

themsaid commented 7 years ago

a PR was submitted to solve the issue: https://github.com/laravel/passport/pull/185

rockers007 commented 7 years ago

downloaded latest code which already solved P100Y ,but still I am facing Unauthorized. check details here https://github.com/dusterio/lumen-passport/issues/17#issuecomment-268990764

jnaxo commented 7 years ago

My problem : Laravel Passport Personal Token failing Validation. I had problems with globals scopes. When i turn them off i solved the problem

PieterjanDeClippel commented 6 years ago

I forgot to add the auth:api middleware to my routes. Route::post()->middleware("auth:api")

tisuchi commented 5 years ago

Actually, @hari03 solution works for me.

I just add 'auth:api' in the app\Http\Kernel.php and it works for me perfectly.

aonurdemir commented 5 years ago
public function enableGrantType(GrantTypeInterface $grantType, \DateInterval $accessTokenTTL = null)
    {
        if ($accessTokenTTL instanceof \DateInterval === false) {
            $accessTokenTTL = new \DateInterval('PT1H');
        }

        $grantType->setAccessTokenRepository($this->accessTokenRepository);
        $grantType->setClientRepository($this->clientRepository);
        $grantType->setScopeRepository($this->scopeRepository);
        $grantType->setDefaultScope($this->defaultScope);
        $grantType->setPrivateKey($this->privateKey);
        $grantType->setEmitter($this->getEmitter());
        $grantType->setEncryptionKey($this->encryptionKey);

        $this->enabledGrantTypes[$grantType->getIdentifier()] = $grantType;
        $this->grantTypeAccessTokenTTL[$grantType->getIdentifier()] = $accessTokenTTL;
    }

In above lines of code in AuthorizationServer.php, $accessTokenTTL comes to function from PassportServiceProvider:: registerAuthorizationServer() like

  $server->enableGrantType(
        $this->makePasswordGrant(), Passport::tokensExpireIn()
  );

before AuthServiceProvider::boot() method is called. Hence, Passport::tokensExpireIn(now()->addMinutes(1)); line has no effect on TTLs. As a result, Passport::tokensExpireIn() returns the default value which is 1 year. This is the problem and cannot solve it. Continuing to digging.

JamieCee20 commented 1 year ago

https://github.com/laravel/passport/issues/47#issuecomment-442375531

This comment issue still seems to exist in 2023.