Authentication client for Koko applications with built-in token management, auto-refresh, and localStorage integration
npm install @kokolabs-io/clientAuthentication client for Koko applications with built-in token management, auto-refresh, and localStorage integration.
- Token Management: Automatic access and refresh token storage
- Auto-Refresh: Automatic token refresh before expiration
- localStorage Integration: Persistent token storage in the browser
- Fetch Wrapper: Built-in fetch with automatic auth headers
- Unauthorized Handler: Custom callback for handling 401 responses
- SSO/OAuth Support: Easy integration with OAuth flows
- Type-Safe: Full TypeScript support
``bash`
pnpm add @kokolabs-io/client
`typescript
import { createAuthClient } from '@kokolabs-io/client';
const auth = createAuthClient({
authUrl: 'https://your-app.com/auth/login',
refreshUrl: 'https://your-app.com/auth/refresh',
autoRefresh: true,
onUnauthorized: async ({ response, token }) => {
console.log('Unauthorized request detected');
// Handle 401 responses, e.g., redirect to login
window.location.href = '/login';
}
});
// Initialize the client (loads tokens from localStorage)
const { authenticated, token } = auth.init();
if (authenticated) {
console.log('User is authenticated:', token);
} else {
console.log('User is not authenticated');
}
`
`typescript
// Redirect to login page
auth.login('/dashboard'); // Optional returnTo parameter
// Or use with OAuth/SSO
auth.login(); // Redirects to authUrl
`
`typescript
// Logout and redirect
auth.logout({ redirect: true, returnTo: '/' });
// Logout without redirect (just clear tokens)
auth.logout({ redirect: false });
`
`typescript
// Get current access token
const token = auth.getToken();
// Set access token (e.g., after login)
auth.setToken('your-access-token');
// Clear access token
auth.clearToken();
// Get refresh token
const refreshToken = auth.getRefreshToken();
// Set refresh token
auth.setRefreshToken('your-refresh-token');
// Clear refresh token
auth.clearRefreshToken();
`
`typescript
// Get token expiration timestamp (in milliseconds)
const expiresAt = auth.getExpiresAtMs();
// Set token expiration
auth.setExpiresAtMs(Date.now() + 3600000); // 1 hour from now
// Check if token is expired
const isExpired = auth.isExpired();
// Check with time skew (default 60 seconds)
const isExpired = auth.isExpired(120000); // 2 minutes skew
`
`typescript`
// Manually refresh the access token
try {
const result = await auth.refresh();
console.log('New access token:', result.access_token);
console.log('New refresh token:', result.refresh_token);
console.log('Expires in (seconds):', result.expires_in);
} catch (error) {
console.error('Failed to refresh token:', error);
}
The fetch method automatically adds the Authorization header and handles token refresh:
`typescript
// Make an authenticated request
const response = await auth.fetch('https://api.example.com/user/profile');
const data = await response.json();
// With custom options
const response = await auth.fetch('https://api.example.com/user/profile', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ name: 'John Doe' })
});
`
`typescript
interface KokoAuthClientConfig {
// Required: URL to redirect to for login
authUrl: string;
// Optional: URL to refresh tokens (if not provided, refresh is disabled)
refreshUrl?: string;
// Optional: localStorage key for access token (default: 'koko_auth_token')
storageKey?: string;
// Optional: localStorage key for refresh token (default: 'koko_auth_refresh_token')
refreshStorageKey?: string;
// Optional: localStorage key for expiration timestamp (default: 'koko_auth_expires_at')
expiresAtKey?: string;
// Optional: Enable automatic token refresh (default: true)
autoRefresh?: boolean;
// Optional: Callback when 401 Unauthorized is received
onUnauthorized?: (ctx: UnauthorizedContext) => void | Promise
}
`
`typescript
import { createAuthClient } from '@kokolabs-io/client';
// Create auth client
const auth = createAuthClient({
authUrl: 'https://your-app.com/auth/login',
refreshUrl: 'https://your-app.com/auth/refresh',
storageKey: 'my_app_token',
autoRefresh: true,
onUnauthorized: async ({ response }) => {
// Clear tokens and redirect to login
auth.clearToken();
auth.clearRefreshToken();
window.location.href = '/login?returnTo=' + encodeURIComponent(window.location.pathname);
}
});
// Initialize on app load
const { authenticated } = auth.init();
// Login button handler
document.getElementById('login-btn')?.addEventListener('click', () => {
auth.login(window.location.pathname);
});
// Logout button handler
document.getElementById('logout-btn')?.addEventListener('click', () => {
auth.logout({ redirect: true, returnTo: '/' });
});
// Make authenticated API calls
async function fetchUserProfile() {
try {
const response = await auth.fetch('https://api.example.com/user/profile');
if (!response.ok) {
throw new Error(HTTP error! status: ${response.status});
}
const profile = await response.json();
return profile;
} catch (error) {
console.error('Failed to fetch profile:', error);
throw error;
}
}
// Check authentication before making requests
if (authenticated) {
fetchUserProfile().then(profile => {
console.log('User profile:', profile);
});
} else {
console.log('Please login first');
auth.login();
}
`
#### Methods
- init(): { authenticated: boolean; token: string | null } - Initialize and check authentication statuslogin(returnTo?: string): void
- - Redirect to login pagelogout(options?: { redirect?: boolean; returnTo?: string }): void
- - Logout usergetToken(): string
- - Get access tokensetToken(token: string): void
- - Set access tokenclearToken(): void
- - Clear access tokengetRefreshToken(): string
- - Get refresh tokensetRefreshToken(token: string): void
- - Set refresh tokenclearRefreshToken(): void
- - Clear refresh tokengetExpiresAtMs(): number
- - Get token expiration timestampsetExpiresAtMs(ms: number): void
- - Set token expiration timestampclearExpiresAtMs(): void
- - Clear token expiration timestampisExpired(skewMs?: number): boolean
- - Check if token is expiredrefresh(): Promise<{ access_token: string; refresh_token: string; expires_in: number }>
- - Refresh access tokenfetch(url: string, options?: RequestInit): Promise
- - Make authenticated request
Build from root:
`bash`
pnpm -C .. build
Build this package only:
`bash``
pnpm --filter @kokolabs-io/client build
MIT - Copyright (c) 2026 KokoLabs.io