Public Access
feat(auth): use the cookie session and refresh on 401
The token is no longer stored; a tbp_session flag remembers the login. apiFetch renews the session once on a 401 and sends the request again. Parallel requests and other tabs share one refresh, because Auth revokes the session when a refresh token is used twice. Only a 401 from the refresh ends the session; a 502 or no network shows the normal error.
This commit is contained in:
1 parent
5ff8d48c53
commit
d9a39dda22
34 files changed
+297
-147
No files matched your search
+17
-27
@@ -1,35 +1,25 @@
|
||||
const TOKEN_KEY = 'tbp_jwt';
|
||||
// The tokens live in HttpOnly cookies that no script can read. This flag only remembers that a login happened; a
|
||||
// stale flag costs one 401 and a failed refresh, then the login page opens.
|
||||
const SESSION_KEY = 'tbp_session';
|
||||
// Where the token lived before the cookies. Removed on the next login or logout.
|
||||
const LEGACY_TOKEN_KEY = 'tbp_jwt';
|
||||
|
||||
export const getToken = () => localStorage.getItem(TOKEN_KEY);
|
||||
|
||||
export const setToken = (token) => localStorage.setItem(TOKEN_KEY, token);
|
||||
|
||||
export const clearToken = () => localStorage.removeItem(TOKEN_KEY);
|
||||
export const hasSession = () => localStorage.getItem(SESSION_KEY) !== null;
|
||||
|
||||
/**
|
||||
* Only checks `exp`. The signature is checked by the backends.
|
||||
* Changes on every login and on every settings save, so a hook that shows the user's Steam data can load again.
|
||||
*/
|
||||
export function isTokenValid(token, nowMs = Date.now()) {
|
||||
try {
|
||||
const payload = token.split('.')[1].replace(/-/g, '+').replace(/_/g, '/');
|
||||
const {exp} = JSON.parse(atob(payload));
|
||||
return typeof exp === 'number' && exp * 1000 > nowMs;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export const sessionStamp = () => localStorage.getItem(SESSION_KEY);
|
||||
|
||||
/**
|
||||
* Returns the stored token, or null. Removes an expired token.
|
||||
*/
|
||||
export function getValidToken() {
|
||||
const token = getToken();
|
||||
if (token && !isTokenValid(token)) {
|
||||
clearToken();
|
||||
return null;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
export const markSession = () => {
|
||||
localStorage.setItem(SESSION_KEY, String(Date.now()));
|
||||
localStorage.removeItem(LEGACY_TOKEN_KEY);
|
||||
};
|
||||
|
||||
export const clearSession = () => {
|
||||
localStorage.removeItem(SESSION_KEY);
|
||||
localStorage.removeItem(LEGACY_TOKEN_KEY);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the path when it is a path inside this app, else null. The login page uses it to go back after a
|
||||
|
||||
Reference in new issue
Block a user