On the old auth0-js tutorial, you could renew the token until the user session expires. How would one implement it in the auth0-spa-js?
@philippendrulat There's no need to do token renewal. We do it automatically for you. Every time you call getTokenSilently, you'll get a valid token.
Hey @luisrudge , I'm building a SPA and the session that I set in the Auth0 configuration page is 5 mins. So in 5 mins after successful login, auth0-spa-js will automatically refresh token every time I call getTokenSilently.
1 - Can I call this function to get a new token after 5 mins (session in auth0 is timeout)?
2- In 5 mins after login, if the expired time of token is 1 min, so I have to call getTokenSilently every 1 min? Do we have the function to schedule it or I have to implement it?
As I understood, you are not able to use token refresh in a SPA. You are only able to renew the token until the session expires.
I would also like to know the answer to your second question.
@jackmercy the Auth0 session has nothing to do with your token. Your token can expire before the session (that's pretty common). If you have an active session at Auth0, when you call getTokenSilently, you'll always get a non-expired token, either from cache or by fetching a new token from Auth0.
@philippendrulat correct. we're not using refresh tokens. We're just asking for fresh tokens from the server.
2- In 5 mins after login, if the expired time of token is 1 min, so I have to call getTokenSilently every 1 min? Do we have the function to schedule it or I have to implement it?
That's precisely what we do. Once we put a token in the cache, we schedule its removal once it expires:
https://github.com/auth0/auth0-spa-js/blob/master/src/cache.ts#L35-L41
So, next time you ask for a token, if it's not in the cache, it will just fetch remotely (if you have an active session)
Just to be clear here, when your referring to the session expiring, are you meaning the access token?
Hello, I'm also interested in a little more guidance on this.
I have implemented a recursive async function to scheduleRenewal like this:
const scheduleRenewal = async (token, delay) => {
let jwt = parseJwt(token)
let expiresAt = jwt.exp * 1000
if (!delay) {
delay = expiresAt - Date.now()
delay -= 60000
}
await new Promise(f => setTimeout(f, delay))
try {
const newToken = await auth0.getTokenSilently()
window.localStorage.setItem('access_token', newToken)
// schedule the next renewal
scheduleRenewal(newToken)
} catch (e) {
console.log('error renewing token silently')
console.log(e)
// retry
scheduleRenewal(token, 3000)
}
}
Is this the best practice? Should we build in a delay like I have done or wait until exactly when the JWT expires? It seems like we would want to renew the token a little bit earlier than the actual expiration.
@freeman-g Yes there are a few things going on here that we deal with on your behalf:
cacheLocation: 'localstorage' when setting up the SDKAlso, you are decoding and inspecting the JWT access token on the client, which it has no business doing (only the resource server consuming the access token should do that). The main reason is that there is effectively a contract between the resource server (to which the access token is issued) and the IdP - that contract could change without the client's knowledge, which may break the application. Just something to be aware of. It's not best practise, to answer your question.
Considering those things, given that we manage a small leeway for you, you should be able to get away with not parsing that JWT, removing the leeway logic and potentially stop storing the token. Does that help?
@stevehobbsdev
Yes, this is very helpful. If I don't parse the JWT on the client, how do I determine the expiration time (exp property) to set the timeout function?
Thank you
@freeman-g what's the use case for scheduling that renewal? Are you trying to sync up some operation with the renewal of the access token?
Otherwise, we handle the renewal of the access token for you inside the SDK, there's no need to do that manually.
I'm just trying to make sure that I have a current token for API calls. I'm using Axios, so I'm doing this:
// configured-axios.js
import axios from 'axios'
const jwt = () => {
return window.localStorage.getItem('access_token')
}
axios.interceptors.request.use((config) => {
config.headers['Authorization'] = `Bearer ${jwt()}`
return config
})
export default axios
Then I'll use Axios like this:
```
import axios from 'configured-axios'
axios.get('https://mysecuredapi')
````
Therefore, I want to schedule background renewal so that the token is current when I need it.
Are you suggesting that I should just call await auth0.getTokenSilently() any time I need to make an API call? I think this might have two challenges:
1) getTokenSilently is async, so I'll have to figure out how to wrap that in an async function and await it
2) The user may have been idle and the token may be completely expired. In this case, my API call would incur a delay while waiting for a network based renewal via Auth0. I think I would rather "pre-renew" the token so that it's already done when I need to make an API call.
Thanks again
getTokenSilently is async, so I'll have to figure out how to wrap that in an async function and await it
Keep in mind that interceptors in axios can be async: https://github.com/axios/axios/blob/master/index.d.ts#L126
So you should be able to just use
// configured-axios.js
import axios from 'axios'
axios.interceptors.request.use(async (config) => {
const token = await getTokenSilently();
config.headers['Authorization'] = `Bearer ${token}`
return config
})
export default axios
The user may have been idle and the token may be completely expired. In this case, my API call would incur a delay while waiting for a network based renewal via Auth0. I think I would rather "pre-renew" the token so that it's already done when I need to make an API call.
You can still implement some kind of renewal elsewhere, e.g. call our SDK's checkSession() on a specific interval. This does the same as getTokenSilently , with the only difference that it doesnt return a token:
Calling checkSession() with { ignoreCache: true } will ensure it will ignore the cache and always get a new token, even if not expired. It will also update the cache. But I think you might not need that and will be able to get away with relying on the cache.
@frederikprijck
Very cool! I will give it a try the way you described with an async interceptor and just rely on the SDK and not worry about "pre-renewing".
Most helpful comment
@frederikprijck
Very cool! I will give it a try the way you described with an async interceptor and just rely on the SDK and not worry about "pre-renewing".