Hi,
In my code, has refresh access token functionality but it requires regular interval of polling to trigger the refresh mechanism
here is the code
import NextAuth, { NextAuthOptions } from “next-auth”;
import KeycloakProvider from “next-auth/providers/keycloak”;
import jwt_decode from ‘jwt-decode’;
export const authOptions: NextAuthOptions = {
providers: [
KeycloakProvider({
clientId: process.env.KEYCLOAK_ID || ‘’,
clientSecret: process.env.KEYCLOAK_SECRET || ‘’,
issuer: process.env.KEYCLOAK_ISSUER || ‘’,
profile(profile) {
return {
id: profile.sub,
name: profile.name ?? profile.preferred_username,
email: profile.email,
image: profile.picture,
acr: profile.acr,
familyName: profile.family_name,
givenName: profile.given_name,
preferredUsername: profile.preferred_username
}
}
})
],
pages: {
signIn: ‘/signin’,
signOut: ‘/?logout=true’
},
callbacks: {
async jwt({ token, account }: any) {
if (account) {
return {
…token,
accessToken: account.access_token,
accessTokenExpires: Date.now() + account.expires_at * 1000,
id_token_hint: account.id_token,
refreshToken: account.refresh_token,
}
}
//current time calculation
const currentTimestamp = Math.floor(Date.now() / 1000);
const tokens = token.accessToken;
const decoded: any = jwt_decode(tokens);
const threshold = Number(process.env.REFRESH_TOKEN_THRESHOLD) || 120;
// trigger refreshtoken function based on threshold value
if (currentTimestamp > (decoded.exp - threshold)) {
try {
// if access token is invalid fetch new token
const refreshedToken = await refreshAccessToken(token);
console.log(“refresh access token success”)
if (refreshedToken.accessToken) {
return {
accessToken: refreshedToken.accessToken,
accessTokenExpires: refreshedToken.accessTokenExpires,
refreshToken: refreshedToken.refreshToken ?? token.refreshToken,
}
}
} catch (error) {
// Handle failure (e.g., redirect to login, notify the user, etc.)
return {
…token,
error: “Failed to refresh token”,
};
};
} else {
// else return original valid token
return token;
}
},
async session({ session, token }: any) {
// Send properties to the client, like an access_token from a provider.
session.accessToken = token.accessToken;
session.refreshToken = token.refreshToken
session.id_token = token.id_token_hint
return session;
}
}
};
// fetching new accesstoken using refresh token, ticket no E20-1015
async function refreshAccessToken(token: any) {
try {
const url = ${process.env.KEYCLOAK_ISSUER}/protocol/openid-connect/token;
const response = await fetch(url, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/x-www-form-urlencoded’,
},
body: new URLSearchParams({
client_id: process.env.KEYCLOAK_ID || ‘’,
client_secret: process.env.KEYCLOAK_SECRET || ‘’,
grant_type: ‘refresh_token’,
refresh_token: token.refreshToken,
}),
});
const refreshedTokens = await response.json();
if (!response.ok) {
throw refreshedTokens;
}
// return refreshed token
return {
accessToken: refreshedTokens.access_token,
accessTokenExpires: Date.now() / 1000 + (refreshedTokens.expires_in),
refreshToken: refreshedTokens.refresh_token ?? token.refreshToken, // Fall back to old refresh token
};
} catch (error) {
console.error(‘RefreshAccessTokenError’, error);
// return error if failed to fetch access token
return {
…token,
error: ‘RefreshAccessTokenError’,
};
}
}
export default NextAuth(authOptions);
here the problem is without that polling the current timestamp value is not getting changed as live value
is there any fix for this?
Securing applications authentication client-configuration oidc Tips and tricks.