176 lines
4.1 KiB
TypeScript
176 lines
4.1 KiB
TypeScript
|
|
/**
|
||
|
|
* Integration Example: Using @lilith/http-client with @lilith/http-auth-interceptor
|
||
|
|
*
|
||
|
|
* This example demonstrates how to compose the HTTP client with authentication interceptor.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { createApiClient } from '@lilith/http-client';
|
||
|
|
import { createAuthInterceptor } from '@lilith/http-auth-interceptor';
|
||
|
|
import type { JwtTokenSource } from '@lilith/http-auth-interceptor';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Example 1: Basic Setup with localStorage
|
||
|
|
*/
|
||
|
|
export function example1_basicSetup() {
|
||
|
|
// Step 1: Create HTTP client (transport only)
|
||
|
|
const client = createApiClient({
|
||
|
|
baseURL: 'https://api.example.com',
|
||
|
|
timeout: 10000,
|
||
|
|
});
|
||
|
|
|
||
|
|
// Step 2: Add authentication interceptor
|
||
|
|
createAuthInterceptor(client, {
|
||
|
|
getToken() {
|
||
|
|
return localStorage.getItem('auth_token');
|
||
|
|
},
|
||
|
|
|
||
|
|
async refreshToken() {
|
||
|
|
const refresh = localStorage.getItem('refresh_token');
|
||
|
|
if (!refresh) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
const response = await fetch('/auth/refresh', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ refreshToken: refresh }),
|
||
|
|
});
|
||
|
|
|
||
|
|
const data = await response.json();
|
||
|
|
localStorage.setItem('auth_token', data.accessToken);
|
||
|
|
return data.accessToken;
|
||
|
|
},
|
||
|
|
|
||
|
|
onRefreshFailed() {
|
||
|
|
localStorage.clear();
|
||
|
|
window.location.href = '/login';
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
// Step 3: Use client normally
|
||
|
|
return client;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Example 2: Using a Token Store Class
|
||
|
|
*/
|
||
|
|
class TokenStore implements JwtTokenSource {
|
||
|
|
private accessToken: string | null = null;
|
||
|
|
private refreshTokenValue: string | null = null;
|
||
|
|
|
||
|
|
getToken(): string | null {
|
||
|
|
return this.accessToken;
|
||
|
|
}
|
||
|
|
|
||
|
|
async refreshToken(): Promise<string | null> {
|
||
|
|
if (!this.refreshTokenValue) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
const response = await fetch('/auth/refresh', {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify({ refreshToken: this.refreshTokenValue }),
|
||
|
|
});
|
||
|
|
|
||
|
|
const data = await response.json();
|
||
|
|
this.accessToken = data.accessToken;
|
||
|
|
this.refreshTokenValue = data.refreshToken;
|
||
|
|
return data.accessToken;
|
||
|
|
}
|
||
|
|
|
||
|
|
onRefreshFailed(): void {
|
||
|
|
this.clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
setTokens(access: string, refresh: string): void {
|
||
|
|
this.accessToken = access;
|
||
|
|
this.refreshTokenValue = refresh;
|
||
|
|
}
|
||
|
|
|
||
|
|
clear(): void {
|
||
|
|
this.accessToken = null;
|
||
|
|
this.refreshTokenValue = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export function example2_tokenStore() {
|
||
|
|
const tokenStore = new TokenStore();
|
||
|
|
|
||
|
|
const client = createApiClient({
|
||
|
|
baseURL: 'https://api.example.com',
|
||
|
|
});
|
||
|
|
|
||
|
|
createAuthInterceptor(client, tokenStore);
|
||
|
|
|
||
|
|
// Can control tokens programmatically
|
||
|
|
tokenStore.setTokens('initial-access', 'initial-refresh');
|
||
|
|
|
||
|
|
return { client, tokenStore };
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Example 3: Public API (No Auth)
|
||
|
|
*/
|
||
|
|
export function example3_publicAPI() {
|
||
|
|
// Just use the HTTP client without auth interceptor
|
||
|
|
const client = createApiClient({
|
||
|
|
baseURL: 'https://api.public.com',
|
||
|
|
});
|
||
|
|
|
||
|
|
// No auth interceptor needed
|
||
|
|
return client;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Example 4: URL Exclusion
|
||
|
|
*/
|
||
|
|
export function example4_urlExclusion() {
|
||
|
|
const client = createApiClient({
|
||
|
|
baseURL: 'https://api.example.com',
|
||
|
|
});
|
||
|
|
|
||
|
|
createAuthInterceptor(
|
||
|
|
client,
|
||
|
|
{
|
||
|
|
getToken: () => localStorage.getItem('auth_token'),
|
||
|
|
refreshToken: async () => {
|
||
|
|
const response = await fetch('/auth/refresh', { method: 'POST' });
|
||
|
|
const data = await response.json();
|
||
|
|
return data.accessToken;
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
// Skip auth for public endpoints
|
||
|
|
excludeUrls: ['/public', /^\/auth\//],
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
return client;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Example 5: Custom Headers and Prefix
|
||
|
|
*/
|
||
|
|
export function example5_customHeaders() {
|
||
|
|
const client = createApiClient({
|
||
|
|
baseURL: 'https://api.example.com',
|
||
|
|
});
|
||
|
|
|
||
|
|
createAuthInterceptor(
|
||
|
|
client,
|
||
|
|
{
|
||
|
|
getToken: () => localStorage.getItem('auth_token'),
|
||
|
|
refreshToken: async () => {
|
||
|
|
const response = await fetch('/auth/refresh', { method: 'POST' });
|
||
|
|
const data = await response.json();
|
||
|
|
return data.accessToken;
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
authHeader: 'X-Auth-Token', // Custom header name
|
||
|
|
tokenPrefix: 'JWT', // Custom prefix (instead of "Bearer")
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
return client;
|
||
|
|
}
|