55 lines
1.9 KiB
TypeScript
55 lines
1.9 KiB
TypeScript
// Browser SPA auth helper.
|
|
//
|
|
// The server's jwtMiddleware handles transparent token refresh for cookie-based clients,
|
|
// so the browser rarely needs to act on a 401. When it does arrive it means both tokens
|
|
// are dead (refresh token expired or revoked) and the user must log in again.
|
|
//
|
|
// Usage:
|
|
// import { apiFetch, setAuthRedirectUrl } from 'rokojori-auth-connector/browser/apiFetch';
|
|
//
|
|
// // Optional — override the login URL if your app is on a different subdomain
|
|
// setAuthRedirectUrl('https://account.rokojori.com/login.html');
|
|
//
|
|
// const res = await apiFetch('/api/projects');
|
|
// const data = await res.json();
|
|
|
|
const AUTH_HOST = typeof window !== 'undefined'
|
|
? ( ( window as unknown as Record<string, unknown> ).AUTH_HOST as string | undefined )
|
|
: undefined;
|
|
|
|
let loginUrl = ( AUTH_HOST ?? 'https://account.rokojori.com' ) + '/login.html';
|
|
|
|
export function setAuthRedirectUrl( url: string ): void
|
|
{
|
|
loginUrl = url;
|
|
}
|
|
|
|
export async function apiFetch( input: RequestInfo | URL, init?: RequestInit ): Promise<Response>
|
|
{
|
|
const res = await fetch( input, init );
|
|
|
|
if ( res.status === 401 )
|
|
{
|
|
const redirect = encodeURIComponent( window.location.href );
|
|
window.location.href = `${ loginUrl }?redirect=${ redirect }`;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
// Decode the JWT access token payload without verifying the signature.
|
|
// Use this to read userId, roles, and products from the token the server set.
|
|
// The token is in the accessToken cookie — readable only if it is NOT HttpOnly,
|
|
// which it is by default. In that case call GET /api/auth/me instead.
|
|
export function decodeTokenPayload( token: string ): Record<string, unknown> | null
|
|
{
|
|
try
|
|
{
|
|
const parts = token.split( '.' );
|
|
if ( parts.length !== 3 ) return null;
|
|
const json = atob( parts[1].replace( /-/g, '+' ).replace( /_/g, '/' ) );
|
|
return JSON.parse( json ) as Record<string, unknown>;
|
|
}
|
|
catch { return null; }
|
|
}
|