How can we determine if our stored credential’s refresh token has expired? I have found that getCredentials will throw the error RENEW_FAILED: An error occurred while trying to use the Refresh Token to renew the Credentials when the refresh token is expired; is that error specific to refresh token expiry?
We want to log and treat refresh token expiry separate to a legitimate error. From what I can tell the credentials expiresAt is for the access token, not the refresh token. If it helps this is a react native app using the react-native-auth0 sdk.
I am sorry about the delayed response to your inquiry!
RENEW_FAILED is a generic catch-all error which is thrown by the react-native-auth0 SDK whenever the background attempt to get a new access token fails. This can happen if:
The refresh token is expired
It was manually revoked
Arotated token was reused
The user was deleted/blocked
As you have mentioned, the expiresAt property returned by getCredentials corresponds only to the short-lived Access Token, not the Refresh Token.
In order to separate a legitimate refresh token expiry from a transient error, you need to inspect the underlying payload of the error thrown by getCredentials.
When a refresh token is expired or revoked, the Auth0 server specifically returns an invalid_grant error, and the message usually containing the phrase "Unknown or invalid refresh token".
An example on handling these specific errors as you have mentioned above would be:
const fetchValidCredentials = async () => {
try {
const credentials = await getCredentials();
return credentials;
} catch (error) {
if (error.code === 'RENEW_FAILED') {
const errorMessage = error.message?.toLowerCase() || '';
if (
errorMessage.includes('invalid_grant') ||
errorMessage.includes('unknown or invalid refresh token')
) {
console.warn('Refresh token has explicitly expired or been revoked.');
await clearCredentials();
return null;
}
console.error('Credential renewal failed for another reason:', error);
}
throw error;
}
Please bare in mind that some of the errors above can also be thrown by your application if there is a misconfiguration or other underlying causes(race conditions when using Refresh Token Rotation, malicious replay attempts. reuse of refresh tokens etc.)