Authentication
The Asterisms JS SDK provides a comprehensive authentication system that supports multiple authentication providers and flows.
Overview
Authentication in the Asterisms JS SDK is handled through the Auth Resource, which provides:
- Multiple authentication provider support (SRP6, OAuth, etc.)
- Secure token management with automatic refresh
- Session persistence across browser sessions
- Real-time authentication state monitoring
Basic Authentication Flow
1. Initialize Authentication
import { createAsterismsSDK } from '@asterisms/sdk';
import { SRP6AuthProvider } from '@asterisms/auth-provider-srp6';
const sdk = createAsterismsSDK({
bundleId: 'your-app-bundle-id',
rootDomain: 'your-domain.com',
navigationAdapter: yourNavigationAdapter
});
// Configure authentication provider
const authProvider = new SRP6AuthProvider({
serviceUrl: 'https://auth.yourapp.com'
});
sdk.auth.registerProvider('srp6', authProvider);
2. User Login
try {
const result = await sdk.auth.login({
provider: 'srp6',
credentials: {
username: 'user@example.com',
password: 'userPassword'
}
});
console.log('Login successful:', result.user);
} catch (error) {
if (error instanceof InvalidTokenError) {
console.error('Invalid credentials');
} else {
console.error('Login failed:', error.message);
}
}
3. Check Authentication State
// Check if user is currently authenticated
const isAuthenticated = sdk.auth.isAuthenticated();
// Get current user information
if (isAuthenticated) {
const user = sdk.auth.getCurrentUser();
console.log('Current user:', user);
}
4. User Logout
await sdk.auth.logout();
console.log('User logged out successfully');
Authentication Providers
SRP6 Authentication Provider
The SRP6 (Secure Remote Password) provider offers password-based authentication without sending passwords over the network:
import { SRP6AuthProvider } from '@asterisms/auth-provider-srp6';
const srpProvider = new SRP6AuthProvider({
serviceUrl: 'https://auth.yourapp.com/srp6',
timeout: 30000,
retryAttempts: 3
});
sdk.auth.registerProvider('srp6', srpProvider);
Custom Authentication Providers
You can create custom authentication providers by implementing the AuthProviderInterface:
import { AuthProviderInterface, AuthResult } from '@asterisms/sdk';
class CustomAuthProvider implements AuthProviderInterface {
async authenticate(credentials: any): Promise<AuthResult> {
// Implement your custom authentication logic
const response = await fetch('/api/custom-auth', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(credentials)
});
if (!response.ok) {
throw new Error('Authentication failed');
}
const data = await response.json();
return {
token: data.accessToken,
refreshToken: data.refreshToken,
user: data.user,
expiresIn: data.expiresIn
};
}
async refresh(refreshToken: string): Promise<AuthResult> {
// Implement token refresh logic
}
async logout(): Promise<void> {
// Implement logout logic
}
}
// Register the custom provider
sdk.auth.registerProvider('custom', new CustomAuthProvider());
Authentication Events
Monitor authentication state changes in real-time:
// Listen for authentication state changes
sdk.auth.onAuthStateChanged((state) => {
if (state.isAuthenticated) {
console.log('User authenticated:', state.user);
// Redirect to dashboard or update UI
} else {
console.log('User not authenticated');
// Redirect to login or show login form
}
});
// Listen for token refresh events
sdk.auth.onTokenRefresh((newToken) => {
console.log('Token refreshed successfully');
});
// Listen for authentication errors
sdk.auth.onAuthError((error) => {
console.error('Authentication error:', error);
// Handle authentication failures
});
Token Management
The SDK automatically handles token storage and refresh:
Token Storage
// Tokens are automatically stored securely
// You can configure storage options
const sdk = createAsterismsSDK({
bundleId: 'your-app',
rootDomain: 'yourapp.com',
navigationAdapter: yourAdapter,
auth: {
tokenStorage: 'localStorage', // or 'sessionStorage', 'memory'
autoRefresh: true,
refreshThreshold: 300 // Refresh 5 minutes before expiry
}
});
Manual Token Operations
// Get current token
const token = sdk.auth.getToken();
// Check if token is valid
const isValid = sdk.auth.isTokenValid();
// Manually refresh token
try {
await sdk.auth.refreshToken();
console.log('Token refreshed successfully');
} catch (error) {
console.error('Token refresh failed:', error);
// Redirect to login
}
Authentication Guards
Protect routes and components with authentication guards:
// Simple authentication check
function requireAuth() {
if (!sdk.auth.isAuthenticated()) {
throw new Error('Authentication required');
}
}
// Async authentication guard with automatic redirect
async function authGuard(redirectTo = '/login') {
if (!sdk.auth.isAuthenticated()) {
// Try to refresh token first
try {
await sdk.auth.refreshToken();
} catch {
// Redirect to login if refresh fails
window.location.href = redirectTo;
return false;
}
}
return true;
}
// Usage in route handler
async function handleProtectedRoute() {
if (!(await authGuard())) return;
// Route is protected, user is authenticated
// Continue with route logic
}
Framework Integration
SvelteKit Integration
// src/hooks.server.ts
import { authGuard } from '$lib/auth';
export async function handle({ event, resolve }) {
if (event.url.pathname.startsWith('/protected')) {
const isAuthenticated = await authGuard(event);
if (!isAuthenticated) {
return new Response('Unauthorized', { status: 401 });
}
}
return resolve(event);
}
React Integration
// AuthProvider.tsx
import React, { createContext, useContext, useEffect, useState } from 'react';
import { sdk } from './sdk';
const AuthContext = createContext(null);
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
const unsubscribe = sdk.auth.onAuthStateChanged((state) => {
setUser(state.user);
setLoading(false);
});
return unsubscribe;
}, []);
return (
<AuthContext.Provider value={{ user, loading }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => useContext(AuthContext);
Security Best Practices
- Use HTTPS: Always use HTTPS in production
- Secure Storage: Use secure token storage options
- Token Expiry: Set appropriate token expiration times
- Refresh Tokens: Implement secure refresh token rotation
- Error Handling: Don't expose sensitive information in error messages
// Example secure configuration
const sdk = createAsterismsSDK({
bundleId: 'your-app',
rootDomain: 'yourapp.com',
navigationAdapter: yourAdapter,
auth: {
tokenStorage: 'localStorage',
autoRefresh: true,
refreshThreshold: 300,
maxRetryAttempts: 3,
secureTransport: true // Enforce HTTPS
}
});
Troubleshooting
Common Issues
- Token Expired: Implement proper token refresh handling
- Network Errors: Add retry logic for network failures
- Storage Issues: Handle storage quota and permissions
- CORS Errors: Configure proper CORS headers on your backend
Debug Authentication
// Enable authentication debugging
const sdk = createAsterismsSDK({
bundleId: 'your-app',
rootDomain: 'yourapp.com',
navigationAdapter: yourAdapter,
logLevel: 'debug', // Enable debug logging
auth: {
debug: true // Enable authentication-specific debugging
}
});
// Monitor authentication events for debugging
sdk.auth.onAuthStateChanged((state) => {
console.log('Auth State:', state);
});
sdk.auth.onAuthError((error) => {
console.error('Auth Error:', error);
});
Next Steps