/** * Minimal JWT helpers for inspecting access tokens without verifying them. * * We never trust these tokens for authorization decisions; the PDS does that. * We only read the `exp` claim to decide whether a stored access token is still * usable, so we can avoid forcing a token refresh (which rotates the single-use * refresh token) on every CLI invocation. */ /** * Decode the `exp` (expiry) claim from a JWT, in seconds since the epoch. * Returns null if the token is malformed or has no numeric `exp`. */ export function getJwtExpiry(jwt: string): number | null { const parts = jwt.split('.'); if (parts.length !== 3) { return null; } try { const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString('utf-8')); return typeof payload.exp === 'number' ? payload.exp : null; } catch { return null; } } /** * Report whether an access token is still valid with a safety margin. * * The margin guards against a token that is technically valid now but would * expire mid-request. A malformed or unparseable token is treated as invalid so * the caller falls back to a refresh. */ export function isAccessTokenValid(jwt: string, marginSeconds = 60): boolean { const exp = getJwtExpiry(jwt); if (exp === null) { return false; } return exp - marginSeconds > Date.now() / 1000; }