How to understand the relationship between Id, Access and Refresh tokens
Hello, we are trying to track down an issue with our app where users appear to be logged out after an hour of inactivity. I say "appear" since I don't believe they are actually being logged out, but rather there is a mismatch with token refreshing.
FWIW we are using the Kinde default expiry values
ID token 3600
Access token 86400
Refresh token 1296000
We are using the Kinde JavaScript client @kinde-oss/kinde-auth-pkce-js
Since the ID token has the shortest TTL what triggers its refresh? I assume one of the Kinde client methods must do that and does the refresh happen within the client or does it trigger an outbound call to Kinde to obtain the new token?
We are more familiar with Access and Refresh token behaviour than ID. Is the Access token refreshed if it falls within the Refresh TTL when we make a call to
getUserProfile()
which travels over the web. Our understanding is that getUser()
returns similar information but from within the client and not by going across the network to check directly with the Kinde server.
Is there a sequence diagram that illustrates the relationship and activity of the three tokens?15 Replies
Hey @tforster,
Hope you been well! It's been a while since we last spoke.
Based on the details you've provided, it seems like the issue might be related to the ID token's expiration and its refresh mechanism within the Kinde JavaScript client.
1. ID Token Refresh: The ID token, with its default expiry of 3600 seconds (1 hour), does not automatically refresh itself like an access token. The refresh of an ID token typically occurs when a new authentication request is made through the client. This can be triggered by re-authenticating the user or by using a refresh token to request new tokens.
2. Access Token and Refresh Token: The access token, with a longer TTL of 86400 seconds (24 hours), and the refresh token, with an even longer TTL of 1296000 seconds (15 days), are managed differently. The Kinde JavaScript client uses the refresh token to automatically obtain a new access token when the existing one is about to expire. This process is handled internally by the client and does not require manual intervention.
3. getUserProfile() vs getUser(): The
getUserProfile()
method makes a network call to Kinde's servers to fetch the latest user profile information, which ensures that you are getting the most up-to-date data directly from the server. On the other hand, getUser()
typically retrieves the user information stored locally within the client, which might not always reflect the latest changes until a new token is fetched or the user re-authenticates.
To address the issue of users appearing to be logged out, you might want to ensure that:
- The client is correctly configured to use refresh tokens for obtaining new access tokens.
- There are no issues with the client's internal handling of token expiration and refresh mechanisms.
- Consider implementing a mechanism to periodically re-authenticate the user or manually trigger a token refresh using the client methods available.If the problem persists, reviewing the client's configuration for token management and ensuring that the refresh token process is working as expected would be beneficial. Additionally, checking the network requests made by
getUserProfile()
could provide insights into whether the tokens are being refreshed as expected.
For more detailed information on token handling and configuration, you can refer to the Kinde documentation on refresh tokens and managing token and session expiry.Please let me know if you are still having issues.
Thanks @Oli - Kinde for the quick response. It was the ID token that was throwing us as we were not sure how it figured into the refresh mix. Everything else you said more or less aligns with what we thought we knew already LOL.
From a debugging perspective, what would be a definitive way of determining if the user is authenticated or not? Should we depend upon the Access token expiry timestamp from getToken()? Or should we issue a getUserProfile()?
Let me get back to you on this.
Hey @tforster,
From a debugging perspective, the most definitive way to determine if a user is authenticated in the Kinde JavaScript SDK is to use the
getUserProfile()
method. This method not only checks the current state of the user's tokens but also makes a network call to fetch the latest user profile information directly from the Kinde server. This ensures that the authentication state is up-to-date and valid.
Depending solely on the access token expiry timestamp from getToken()
is less reliable because it only tells you if the token has technically expired. It does not account for other factors that might affect the user's session, such as token revocation or changes in the user's authentication state on the server side.
Therefore, for a more accurate and secure check, getUserProfile()
is recommended. This method will also automatically handle the refresh of tokens if necessary, ensuring that the user's session remains active without manual intervention.
Please let me know if you have any further questions.@Oli - Kinde Are there any other methods that trigger an automatic refresh token check? I am using getUserProfile() but if the user is not authenticated then the client throws a 403, BUT, the 403 is trapped and console.errored by the Kinde client. I cannot successfully wrap a try/catch around that so I cannot execute any code specific to that condition. Moreover, the 403 is logged to the console along with a second JSON parse error.
Could the Kinde client just throw the 403 so that the implementation (in this case, my code in my Auth class) can properly handle it?
Possibly related to line 424 of https://github.com/kinde-oss/kinde-auth-pkce-js/blob/main/src/createKindeClient.ts.
Ill get a member of my team to look into this.
Thanks @Oli - Kinde
@Oli - Kinde Were you able to find anything out? Should I file a bug report?
Hey @tforster,
I will speak to my team on Monday as to where they are at with investigating this issue.
No need to file a bug report.
Apologies for the inconvenience.
No worries, thanks for keeping me updated.
Ah shoot. I can see no one from my team has got back to you here.
Are you still experiencing this issue?
If so, I will make sure a member of my team looks into this on Monday.
Let me know.
Hi @tforster
You can isAuthenticated() to check whether the user has authed, which will potentially do a token exchange behind the scenes, based on the code here https://github.com/kinde-oss/kinde-auth-pkce-js/blob/main/src/createKindeClient.ts#L236 - then depending on the response, proceed to do whatever needs a valid token.
About ID token expiry, I think just getting the fresh profile with getUserProfile() would be the best way.
GitHub
kinde-auth-pkce-js/src/createKindeClient.ts at main · kinde-oss/kin...
Kinde vanilla JavaScript authentication for SPAs using PKCE flows. Can be used with Vue / Angular or any JS framework - kinde-oss/kinde-auth-pkce-js
Thanks @viv (kinde) and @Oli - Kinde. We unblocked ourselves a little while ago but the official context above is still valuable and appreciated. We have also seen the 403 disappear since refactored. However, I still think that all errors should be rethrown from the Kinde client so that any developer can catch in their code. The console log of the 403 from the Kinde client added another layer of challenge when we're trying to identify and resolve our issue.
Hey @tforster,
Good to hear you unlocked yourself.
I agree with your feedback and have passed it onto my team.
Please don't hesitate to reach out if you come across any other issues.