feat: Authentication token refresh logic
This commit is contained in:
29
wp-content/themes/headless/server/utils/auth.gql
Normal file
29
wp-content/themes/headless/server/utils/auth.gql
Normal file
@@ -0,0 +1,29 @@
|
||||
fragment AuthUser on User {
|
||||
id
|
||||
email @nonNull
|
||||
roles @nonNull {
|
||||
nodes {
|
||||
name @nonNull
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment AuthPayload on LoginPayload {
|
||||
authToken
|
||||
refreshToken
|
||||
user {
|
||||
...AuthUser
|
||||
}
|
||||
}
|
||||
|
||||
mutation AuthLogin($username: String!, $password: String!) {
|
||||
login(input: { provider: PASSWORD, credentials: { username: $username, password: $password } }) {
|
||||
...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