feat: Authentication token refresh logic
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
export default defineGraphQLContext(async (event) => {
|
export default defineGraphQLContext(async (event) => {
|
||||||
const wpAuthToken = await getAuthToken(event);
|
const authToken = await getAuthToken(event);
|
||||||
return { wpAuthToken };
|
return { authToken };
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import { defu } from "defu";
|
|||||||
|
|
||||||
export default defineRemoteExecutorHooks({
|
export default defineRemoteExecutorHooks({
|
||||||
onRequest(request, context) {
|
onRequest(request, context) {
|
||||||
// Attach the Authorization header if a wpAuthToken is present in the context
|
// Attach the Authorization header if an authToken is present in the context
|
||||||
if (context?.wpAuthToken) {
|
if (context?.authToken) {
|
||||||
request.extensions = defu(request.extensions, {
|
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
|
...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 decoded = jwtDecode<{ exp: number }>(session.secure.authToken);
|
||||||
const isExpired = decoded.exp * 1000 < Date.now();
|
const isExpired = decoded.exp * 1000 < Date.now();
|
||||||
if (isExpired) {
|
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;
|
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