mirror of
https://github.com/shuaiplus/nodewarden.git
synced 2026-08-05 06:50:10 +00:00
fix(auth): prevent unexpected session logout
This commit is contained in:
@@ -42,6 +42,7 @@ interface RefreshFailure {
|
||||
ok: false;
|
||||
transient: boolean;
|
||||
error: string;
|
||||
retryAfterMs?: number;
|
||||
}
|
||||
|
||||
interface RefreshSuccess {
|
||||
@@ -333,8 +334,8 @@ export async function loginWithAccountPasskeyAssertion(assertion: AccountPasskey
|
||||
return json;
|
||||
}
|
||||
|
||||
function isTransientRefreshStatus(status: number): boolean {
|
||||
return status === 0 || status === 429 || status >= 500;
|
||||
function isPermanentRefreshFailure(status: number, errorCode: string | undefined): boolean {
|
||||
return status === 400 && (errorCode === 'invalid_grant' || errorCode === 'invalid_request');
|
||||
}
|
||||
|
||||
export async function refreshAccessToken(session: SessionState): Promise<RefreshResult> {
|
||||
@@ -346,6 +347,8 @@ export async function refreshAccessToken(session: SessionState): Promise<Refresh
|
||||
try {
|
||||
const resp = await fetch('/identity/connect/token', {
|
||||
method: 'POST',
|
||||
cache: 'no-store',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
...(session.authMode === 'web-cookie' ? { [WEB_SESSION_HEADER]: '1' } : {}),
|
||||
@@ -354,15 +357,19 @@ export async function refreshAccessToken(session: SessionState): Promise<Refresh
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const json = await parseJson<TokenError>(resp);
|
||||
const retryAfterSeconds = Number(resp.headers.get('Retry-After') || 0);
|
||||
return {
|
||||
ok: false,
|
||||
transient: isTransientRefreshStatus(resp.status),
|
||||
error: translateServerError(json?.error_description || json?.error, t('txt_session_refresh_failed')),
|
||||
transient: !isPermanentRefreshFailure(resp.status, json?.error),
|
||||
error: translateServerError(json?.error_description || json?.error, t('txt_session_refresh_temporarily_unavailable')),
|
||||
...(Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0
|
||||
? { retryAfterMs: retryAfterSeconds * 1000 }
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
const json = await parseJson<TokenSuccess>(resp);
|
||||
if (!json?.access_token) {
|
||||
return { ok: false, transient: false, error: t('txt_session_refresh_failed') };
|
||||
return { ok: false, transient: true, error: t('txt_session_refresh_temporarily_unavailable') };
|
||||
}
|
||||
return { ok: true, token: json };
|
||||
} catch (error) {
|
||||
@@ -400,6 +407,8 @@ export async function revokeCurrentSession(session: SessionState | null): Promis
|
||||
}
|
||||
await fetch('/identity/connect/revocation', {
|
||||
method: 'POST',
|
||||
cache: 'no-store',
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
...(session?.accessToken ? { Authorization: `Bearer ${session.accessToken}` } : {}),
|
||||
|
||||
Reference in New Issue
Block a user