Oidc-client-js: Error when authorize response is missing expires_in response parameter

Created on 25 Apr 2018  路  12Comments  路  Source: IdentityModel/oidc-client-js

I'm getting a strange issue where upon receiving my id_token and access_token, I get the following log messages:

access token present, remaining duration: undefined
oidc-client.min.js?93dc:1 registering expired timer in: NaN
oidc-client.min.js?93dc:1 Timer.init timer Access token expired for duration: NaN
...
Timer._callback; Access token expired timer expires in: NaN
3oidc-client.min.js?93dc:1 unchanged message from check session op iframe

This effectively prevents any refreshing of the tokens from my IdP. (Which is still Keycloak)

As far as I can track it down, here is where it is trying to get the "expires_in" parameter from the url? According to the OIDC docs, "expires_in" should be an OPTIONAL param. Would it make more sense to harvest that value directly from the access_token?

Or did I miss something extremely obvious again?
Thank you

bug

Most helpful comment

Thanks for your response. I have tried the same thing and it works. Anyway, KeyCloak is working on bringing back the expires_in and token_type attributes in the next release.

https://issues.jboss.org/browse/KEYCLOAK-7695

All 12 comments

As far as I can track it down, here is where it is trying to get the "expires_in" parameter from the url? According to the OIDC docs, "expires_in" should be an OPTIONAL param. Would it make more sense to harvest that value directly from the access_token?

It's really OAuth2's expires_in that we care about, since it's the access token we're talking about. And yes, it's only marked as recommended. https://tools.ietf.org/html/rfc6749#section-4.2.2

So if the token server doesn't supply it, your client is SOL. Get a better token server :)

Would it make more sense to harvest that value directly from the access_token?

No, as access tokens are opaque to the client.

I'll mark this as a bug to deal with the absent expires_in, which means the client can't proactively know when to renew the access token.

That make sense, I didn't realize the access_token should be otherwise ignored on the client except when thrown in a header.

This only came up when I switched to using SAML as the IdP for my IdP, which supplies 2 tokens only in the return URL.

Thanks for checking in on it.

I'll reopen this -- again, I think there's a bug in the sense that the code expects an expires_in.

Alright, so in the interim, any danger in doing something like this, provided my tokens expire >900s?

```
//TODO remove hack when lib gets updated
let hack = '&expires_in=900';

this.mgr.signinPopupCallback(window.location.href + hack).then((response) => {...
```

PS; sorry for closing the ticket, browser only showed your first response when I closed it.

yea, i guess hacking it for now might work. try it and let me know :)

It certainly seems to kill the NaN bug in the refresh timers:

access token present, remaining duration: 860
registering expiring timer in: 800
Timer.init timer Access token expiring for duration: 800
registering expired timer in: 861
Timer.init timer Access token expired for duration: 861

But, it leads to this issue when it actually tries to refresh:

WebStorageStateStore.remove 3d4c516b06404439a366c93fd9b61b14
No matching state found in storage
Error from signinSilent: No matching state found in storage

So, I don't believe it to be work-around.

I added a check that prevents loading the timers if there's no or undefined expiration.

@bakedog417 Where you able to send the expires_in attribute with KeyCloak? We are having the same issue with implicit grant type. Without it, the automatic silent refresh does not work.

@gitterchris No I was not able to get KeyCloak to send the expires_in parameter back-- it seems to have lost that functionality after version 3.3. What I ended up doing was defining it into a config object. Assuming you own the KeyCloak instance, you will know when the access token expires, so you can do something like this:

let config = {
            ...
            loadUserInfo: true,
            automaticSilentRenew:true,
            //Store user token in localstorage to stay logged in between tabs
            userStore: new WebStorageStateStore({store: window.localStorage}),
            //Not a real oidc-client param
            expires_in:900
        };

Then, later:

this.mgr.signinSilentCallback(window.location.href+`&expires_in=${config.expires_in}`)

and

this.mgr.signinRedirectCallback(window.location.href+`&expires_in=${config.expires_in}`)

Obviously, this is not the cleanest solution but it works. oidc-client will add the expires_in time to the current time to produce a "expires_at" attribute that is persisted in sessionStorage (or somewhere else if you like). This has worked out so far in that silent refreshes are working.

Hope this helps!

Thanks for your response. I have tried the same thing and it works. Anyway, KeyCloak is working on bringing back the expires_in and token_type attributes in the next release.

https://issues.jboss.org/browse/KEYCLOAK-7695

Looks like KEYCLOAK-7695 has been merged and is part of Keycloak 4.4.0 :)

Was this page helpful?
0 / 5 - 0 ratings