@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Token persistence interface and localStorage-backed default implementation.
|
||||
*
|
||||
* The TokenStore is injected via RudderClientOptions. When none is provided
|
||||
* the client uses {@link createDefaultTokenStore}: localStorage in browsers,
|
||||
* with a silent in-memory fallback where localStorage is unavailable
|
||||
* (SSR, private mode). Consumers can provide a custom implementation for
|
||||
* alternative storage backends (e.g., sessionStorage, secure cookies).
|
||||
*/
|
||||
export interface TokenStore {
|
||||
/** Returns the current access token, or null if not authenticated. */
|
||||
getAccessToken(): string | null;
|
||||
|
||||
/** Returns the current refresh token, or null if not available. */
|
||||
getRefreshToken(): string | null;
|
||||
|
||||
/** Persists access and refresh tokens after a successful login. */
|
||||
saveTokens(accessToken: string, refreshToken: string): void;
|
||||
|
||||
/** Removes all stored tokens (logout). */
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
const STORAGE_KEY_ACCESS = 'rudder_access_token';
|
||||
const STORAGE_KEY_REFRESH = 'rudder_refresh_token';
|
||||
|
||||
/**
|
||||
* Creates the default TokenStore: localStorage-backed when usable, otherwise
|
||||
* a silent in-memory fallback (tokens live for the page session only).
|
||||
*/
|
||||
export function createDefaultTokenStore(): TokenStore {
|
||||
try {
|
||||
const probe = 'rudder_storage_probe';
|
||||
localStorage.setItem(probe, '1');
|
||||
localStorage.removeItem(probe);
|
||||
return createLocalStorageTokenStore();
|
||||
} catch {
|
||||
return createMemoryTokenStore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TokenStore backed by the browser's localStorage.
|
||||
*
|
||||
* Uses keys `rudder_access_token` and `rudder_refresh_token`.
|
||||
*/
|
||||
export function createLocalStorageTokenStore(): TokenStore {
|
||||
return {
|
||||
getAccessToken(): string | null {
|
||||
try {
|
||||
return localStorage.getItem(STORAGE_KEY_ACCESS);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
getRefreshToken(): string | null {
|
||||
try {
|
||||
return localStorage.getItem(STORAGE_KEY_REFRESH);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
saveTokens(accessToken: string, refreshToken: string): void {
|
||||
try {
|
||||
localStorage.setItem(STORAGE_KEY_ACCESS, accessToken);
|
||||
localStorage.setItem(STORAGE_KEY_REFRESH, refreshToken);
|
||||
} catch {
|
||||
// Storage full or unavailable — silently ignore.
|
||||
}
|
||||
},
|
||||
|
||||
clear(): void {
|
||||
try {
|
||||
localStorage.removeItem(STORAGE_KEY_ACCESS);
|
||||
localStorage.removeItem(STORAGE_KEY_REFRESH);
|
||||
} catch {
|
||||
// Storage unavailable — silently ignore.
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function createMemoryTokenStore(): TokenStore {
|
||||
let accessToken: string | null = null;
|
||||
let refreshToken: string | null = null;
|
||||
|
||||
return {
|
||||
getAccessToken: () => accessToken,
|
||||
getRefreshToken: () => refreshToken,
|
||||
saveTokens(access, refresh) {
|
||||
accessToken = access;
|
||||
refreshToken = refresh;
|
||||
},
|
||||
clear() {
|
||||
accessToken = null;
|
||||
refreshToken = null;
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user