feat: Authentication token refresh logic
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
export default defineGraphQLContext(async (event) => {
|
||||
const wpAuthToken = await getAuthToken(event);
|
||||
return { wpAuthToken };
|
||||
const authToken = await getAuthToken(event);
|
||||
return { authToken };
|
||||
});
|
||||
|
||||
@@ -2,10 +2,10 @@ import { defu } from "defu";
|
||||
|
||||
export default defineRemoteExecutorHooks({
|
||||
onRequest(request, context) {
|
||||
// Attach the Authorization header if a wpAuthToken is present in the context
|
||||
if (context?.wpAuthToken) {
|
||||
// Attach the Authorization header if an authToken is present in the context
|
||||
if (context?.authToken) {
|
||||
request.extensions = defu(request.extensions, {
|
||||
headers: { Authorization: `Bearer ${context.wpAuthToken}` },
|
||||
headers: { Authorization: `Bearer ${context.authToken}` },
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@@ -21,3 +21,9 @@ mutation AuthLogin($username: String!, $password: String!) {
|
||||
...AuthPayload
|
||||
}
|
||||
}
|
||||
|
||||
mutation AuthRefreshToken($refreshToken: String!) {
|
||||
refreshToken(input: { refreshToken: $refreshToken }) {
|
||||
authToken
|
||||
}
|
||||
}
|
||||
@@ -67,8 +67,54 @@ export async function getAuthToken(event: H3Event) {
|
||||
const decoded = jwtDecode<{ exp: number }>(session.secure.authToken);
|
||||
const isExpired = decoded.exp * 1000 < Date.now();
|
||||
if (isExpired) {
|
||||
// TOOD: Refresh token logic
|
||||
try {
|
||||
const newAuthToken = await refreshAuthToken(session.secure.refreshToken);
|
||||
if (!newAuthToken) {
|
||||
throw new Error("Impossible de rafraîchir le jeton d'authentification.");
|
||||
}
|
||||
session.secure.authToken = newAuthToken;
|
||||
await setUserSession(event, session);
|
||||
} catch {
|
||||
await clearUserSession(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return session.secure.authToken;
|
||||
}
|
||||
|
||||
// Track in-flight refreshAuthToken calls to prevent duplicate requests
|
||||
const refreshTokenPromises = new Map<string, Promise<string | undefined>>();
|
||||
|
||||
// Refresh auth token by calling remote GraphQL endpoint directly
|
||||
export async function refreshAuthToken(refreshToken: string): Promise<string | undefined> {
|
||||
// Return existing in-flight promise if available
|
||||
const inFlight = refreshTokenPromises.get(refreshToken);
|
||||
if (inFlight) {
|
||||
return inFlight;
|
||||
}
|
||||
|
||||
const refreshPromise = (async () => {
|
||||
const { wpUrl } = useRuntimeConfig();
|
||||
const endpoint = `${wpUrl}/graphql`;
|
||||
|
||||
const { data } = await executeHttpOperation(
|
||||
{
|
||||
operationName: "AuthRefreshToken",
|
||||
variables: { refreshToken },
|
||||
},
|
||||
{ endpoint, headers: { Authorization: null } },
|
||||
);
|
||||
|
||||
return data?.refreshToken?.authToken || undefined;
|
||||
})();
|
||||
|
||||
refreshTokenPromises.set(refreshToken, refreshPromise);
|
||||
|
||||
return refreshPromise.finally(() => {
|
||||
const current = refreshTokenPromises.get(refreshToken);
|
||||
if (current === refreshPromise) {
|
||||
refreshTokenPromises.delete(refreshToken);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user