Ajout de la gestion du rafraîchissement des tokens d'accès et de rafraîchissement dans NextAuth. Mise à jour des types pour inclure les tokens et les erreurs. Modification de la configuration de session pour gérer les erreurs de rafraîchissement.

This commit is contained in:
Kevin 2025-02-21 16:01:09 +01:00
parent 6018b853a0
commit cf6ea26879
3 changed files with 56 additions and 7 deletions

View File

@ -5,3 +5,4 @@ KEYCLOAK_CLIENT_ID=front
KEYCLOAK_CLIENT_SECRET=Klsbm7hzyXscypXU0wUPPVBrttFPt6Pn KEYCLOAK_CLIENT_SECRET=Klsbm7hzyXscypXU0wUPPVBrttFPt6Pn
KEYCLOAK_REALM=master KEYCLOAK_REALM=master
KEYCLOAK_ISSUER=http://172.16.32.141:8090/realms/master KEYCLOAK_ISSUER=http://172.16.32.141:8090/realms/master
KEYCLOAK_BASE_URL=http://172.16.32.141:8090

View File

@ -22,23 +22,69 @@ export const authOptions: NextAuthOptions = {
], ],
callbacks: { callbacks: {
async jwt({ token, account, profile }) { async jwt({ token, account, profile }) {
console.log("Token", token);
console.log("Account", account);
console.log("Profile", profile);
// Au moment de la première connexion, sauvegarde de l'access token et du rôle dans le JWT // Au moment de la première connexion, sauvegarde de l'access token et du rôle dans le JWT
if (account && profile) { if (account && profile) {
token.accessToken = account.access_token; token.accessToken = account.access_token;
token.refreshToken = account.refresh_token; token.refreshToken = account.refresh_token;
token.accessTokenExpires = account.expires_at! * 1000;
token.first_name = profile.given_name; token.first_name = profile.given_name;
token.last_name = profile.family_name; token.last_name = profile.family_name;
token.username = profile.preferred_username; token.username = profile.preferred_username;
token.role = profile.realm_roles; token.role = profile.realm_roles;
return token;
}
// Retourner le token précédent si le token d'accès n'a pas expiré
if (Date.now() < (token.accessTokenExpires as number)) {
return token;
}
// Rafraîchir le token si expiré
try {
const response = await fetch(
`${process.env.KEYCLOAK_BASE_URL}/protocol/openid-connect/token`,
{
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "refresh_token",
client_id: process.env.KEYCLOAK_CLIENT_ID!,
client_secret: process.env.KEYCLOAK_CLIENT_SECRET!,
refresh_token: token.refreshToken as string,
}),
}
);
const refreshedTokens = await response.json();
if (!response.ok) {
throw refreshedTokens;
}
return {
...token,
accessToken: refreshedTokens.access_token,
refreshToken: refreshedTokens.refresh_token ?? token.refreshToken,
accessTokenExpires: Date.now() + refreshedTokens.expires_in * 1000,
};
} catch (error) {
console.error("Erreur lors du rafraîchissement du token:", error);
return {
...token,
error: "RefreshAccessTokenError",
};
} }
return token;
}, },
async session({ session, token }) { async session({ session, token }) {
if (token.error) {
// Rediriger vers la page de connexion si le rafraîchissement a échoué
throw new Error("RefreshAccessTokenError");
}
// On injecte l'access token et le rôle dans la session accessible côté client // On injecte l'access token et le rôle dans la session accessible côté client
session.accessToken = token.accessToken as string; session.accessToken = token.accessToken as string;
session.refreshToken = token.refreshToken as string;
session.error = token.error as string;
session.user.first_name = token.first_name as string; session.user.first_name = token.first_name as string;
session.user.last_name = token.last_name as string; session.user.last_name = token.last_name as string;
session.user.username = token.username as string; session.user.username = token.username as string;
@ -48,12 +94,11 @@ export const authOptions: NextAuthOptions = {
}, },
session: { session: {
strategy: "jwt", strategy: "jwt",
maxAge: 60 * 60, // 1 heure
}, },
events: { events: {
async signOut({ token }) { async signOut({ token }) {
try { try {
console.log("Déconnexion Keycloak");
console.log("Token", token);
const issuerUrl = process.env.KEYCLOAK_ISSUER!; const issuerUrl = process.env.KEYCLOAK_ISSUER!;
const logoutUrl = `${issuerUrl}/protocol/openid-connect/logout`; const logoutUrl = `${issuerUrl}/protocol/openid-connect/logout`;
await fetch(logoutUrl, { await fetch(logoutUrl, {

View File

@ -10,6 +10,8 @@ declare module "next-auth" {
role: string[]; role: string[];
} & DefaultSession["user"]; } & DefaultSession["user"];
accessToken?: string; accessToken?: string;
refreshToken?: string;
error?: string;
} }
interface JWT { interface JWT {
@ -18,6 +20,7 @@ declare module "next-auth" {
last_name?: string; last_name?: string;
username?: string; username?: string;
role?: string[] | string | null; role?: string[] | string | null;
error?: string;
} }
interface User extends DefaultUser { interface User extends DefaultUser {