feat: persistent sessions with 30-day JWT and auto-refresh on page load
Sessions now last 30 days instead of 15 minutes. Both the rstack-identity component and legacy header auto-refresh the token when < 7 days remain, so users who visit at least once every ~23 days stay logged in indefinitely. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
783be14a11
commit
2b58068a1a
|
|
@ -898,6 +898,27 @@ export function mountHeader(options: HeaderOptions): void {
|
|||
// Mount to DOM
|
||||
document.body.prepend(header);
|
||||
renderHeader();
|
||||
|
||||
// Auto-refresh token if nearing expiry (< 7 days remaining)
|
||||
(async () => {
|
||||
const session = getSession();
|
||||
if (!session) return;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const remaining = session.claims.exp - now;
|
||||
if (remaining >= 7 * 24 * 60 * 60) return;
|
||||
try {
|
||||
const res = await fetch(`${ENCRYPTID_URL}/api/session/refresh`, {
|
||||
method: 'POST',
|
||||
headers: { Authorization: `Bearer ${session.accessToken}` },
|
||||
});
|
||||
if (!res.ok) return;
|
||||
const { token } = await res.json();
|
||||
if (token) {
|
||||
storeSession(token, session.claims.username || '', session.claims.did || '');
|
||||
renderHeader();
|
||||
}
|
||||
} catch { /* silently ignore */ }
|
||||
})();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ export class RStackIdentity extends HTMLElement {
|
|||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.#refreshIfNeeded();
|
||||
this.#render();
|
||||
this.#startNotifPolling();
|
||||
}
|
||||
|
|
@ -194,6 +195,26 @@ export class RStackIdentity extends HTMLElement {
|
|||
this.#stopNotifPolling();
|
||||
}
|
||||
|
||||
async #refreshIfNeeded() {
|
||||
const session = getSession();
|
||||
if (!session) return;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const remaining = session.claims.exp - now;
|
||||
if (remaining >= 7 * 24 * 60 * 60) return; // more than 7 days left, skip
|
||||
try {
|
||||
const res = await fetch(`${ENCRYPTID_URL}/api/session/refresh`, {
|
||||
method: "POST",
|
||||
headers: { Authorization: `Bearer ${session.accessToken}` },
|
||||
});
|
||||
if (!res.ok) return;
|
||||
const { token } = await res.json();
|
||||
if (token) {
|
||||
storeSession(token, session.claims.username || "", session.claims.did || "");
|
||||
this.#render();
|
||||
}
|
||||
} catch { /* silently ignore – user keeps current token */ }
|
||||
}
|
||||
|
||||
#startNotifPolling() {
|
||||
this.#stopNotifPolling();
|
||||
if (!getSession()) return;
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ const CONFIG = {
|
|||
if (!secret) throw new Error('JWT_SECRET environment variable is required');
|
||||
return secret;
|
||||
})(),
|
||||
sessionDuration: 15 * 60, // 15 minutes
|
||||
sessionDuration: 30 * 24 * 60 * 60, // 30 days
|
||||
refreshDuration: 7 * 24 * 60 * 60, // 7 days
|
||||
smtp: {
|
||||
host: process.env.SMTP_HOST || 'mail.rmail.online',
|
||||
|
|
|
|||
Loading…
Reference in New Issue