fix(auth): return expires_in on token responses so the client refreshes early
The login / TOTP / refresh endpoints returned { access_token, user } with no
expires_in. The client (AuthContext.setAccessTokenFn) therefore fell back to
ttl=900s while the dev access token actually lives 60s (ACCESS_TOKEN_EXPIRY).
So the client believed every token was valid for 15 min, kept handing it out
(getAccessTokenFn only nulls 30s before the *believed* expiry) and scheduled
its proactive refresh 14 min out. The token silently died at 60s, the next
request (e.g. the offer lock heartbeat) hit a real 401, and apiFetch refreshed
reactively — producing the steady "…heartbeats → 401 → refresh → …" cycle.
Now every access-token response includes expires_in = accessTokenExpiry, so the
client tracks the true lifetime and refreshes BEFORE expiry (proactive up-front
refresh via the 30s-early null window). No more reactive 401s. In production
(900s) behaviour is unchanged; it just makes the client honour the real TTL.
Verified in Chrome: /api/admin/refresh now returns expires_in:60, and 11
consecutive heartbeats across >1 token cycle were all 200 with one proactive
refresh and zero 401s. tsc -b --noEmit, npm run build, vitest 152/152 clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -84,6 +84,7 @@ export default async function authRoutes(
|
||||
setRefreshCookie(reply, result.refreshToken, remember_me);
|
||||
return success(reply, {
|
||||
access_token: result.accessToken,
|
||||
expires_in: config.jwt.accessTokenExpiry,
|
||||
user: result.user,
|
||||
});
|
||||
},
|
||||
@@ -249,7 +250,11 @@ export default async function authRoutes(
|
||||
description: `TOTP přihlášení uživatele ${user.username}`,
|
||||
});
|
||||
|
||||
return success(reply, { access_token: accessToken, user: authData });
|
||||
return success(reply, {
|
||||
access_token: accessToken,
|
||||
expires_in: config.jwt.accessTokenExpiry,
|
||||
user: authData,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
@@ -287,6 +292,7 @@ export default async function authRoutes(
|
||||
setRefreshCookie(reply, result.refreshToken, result.rememberMe);
|
||||
return success(reply, {
|
||||
access_token: result.accessToken,
|
||||
expires_in: config.jwt.accessTokenExpiry,
|
||||
user: result.user,
|
||||
});
|
||||
},
|
||||
|
||||
@@ -414,7 +414,11 @@ export default async function totpRoutes(
|
||||
description: `Backup code login for user ${user.username}`,
|
||||
});
|
||||
|
||||
return success(reply, { access_token: accessToken, user: authData });
|
||||
return success(reply, {
|
||||
access_token: accessToken,
|
||||
expires_in: config.jwt.accessTokenExpiry,
|
||||
user: authData,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user