All checks were successful
continuous-integration/drone/push Build is passing
36 lines
1.0 KiB
TypeScript
36 lines
1.0 KiB
TypeScript
const MILLISECONDS_PER_SECOND = 1000;
|
|
|
|
export function decodeJwtPayload(token: string): Record<string, unknown> | null {
|
|
const parts = token.split('.');
|
|
if (parts.length !== 3) {
|
|
return null;
|
|
}
|
|
|
|
const base64Url = parts[1];
|
|
const base64 = base64Url.replaceAll('-', '+').replaceAll('_', '/');
|
|
const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');
|
|
|
|
try {
|
|
const payload = JSON.parse(atob(padded));
|
|
if (payload && typeof payload === 'object') {
|
|
return payload as Record<string, unknown>;
|
|
}
|
|
} catch {
|
|
return null;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function isJwtExpired(token: string, skewSeconds = 0) {
|
|
const payload = decodeJwtPayload(token);
|
|
const exp = payload?.exp;
|
|
if (typeof exp !== 'number' || !Number.isFinite(exp)) {
|
|
return false;
|
|
}
|
|
|
|
const expiresAt = exp * MILLISECONDS_PER_SECOND;
|
|
const now = Date.now();
|
|
return expiresAt <= now + skewSeconds * MILLISECONDS_PER_SECOND;
|
|
}
|