UNPKG

@simpleapps-com/augur-api

Version:

TypeScript client library for Augur microservices API endpoints

371 lines (291 loc) 10.9 kB
# Authentication Guide Complete guide to authentication patterns in the Augur API Client. ## Standard Authentication (Most Common) The standard authentication pattern works for 95% of use cases. ### Dual Authentication System Every API request requires two pieces of authentication: 1. **Site ID** (`x-site-id` header) - Identifies which site/tenant you're working with 2. **Bearer Token** (JWT) - Proves you're authorized to access that site ```typescript const api = new AugurAPI({ siteId: 'your-site-id', // Always required bearerToken: 'your-jwt-token', // Required except for health checks }); ``` ### How to Get Your Credentials **Site ID**: Usually provided by your system administrator or found in your project configuration. **Bearer Token**: Obtained through your application's login process. This is typically a JWT token that looks like: `eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...` ### Health Checks (No Authentication Required) Health checks are the only endpoints that don't require a bearer token: ```typescript // Health checks work without bearer token const api = new AugurAPI({ siteId: 'your-site-id', // No bearerToken needed }); const health = await api.joomla.getHealthCheck(); const pricingHealth = await api.pricing.getHealthCheck(); const vmiPing = await api.vmi.health.ping(); ``` ### Dynamic Authentication Updates Update credentials at runtime when needed: ```typescript // Update token after login/refresh api.setAuthToken('new-jwt-token'); // Switch to different site api.setSiteId('different-site-id'); // Example: Token refresh scenario async function refreshTokenIfNeeded() { try { await api.joomla.users.list({ limit: 1 }); } catch (error) { if (error instanceof AuthenticationError) { const newToken = await refreshJWTToken(); api.setAuthToken(newToken); } } } ``` ### Environment Variables Setup Store credentials securely in environment variables: ```bash # .env file AUGUR_SITE_ID=your-site-id AUGUR_JWT_TOKEN=your-jwt-token ``` ```typescript const api = new AugurAPI({ siteId: process.env.AUGUR_SITE_ID!, bearerToken: process.env.AUGUR_JWT_TOKEN!, }); ``` ### Security Best Practices 1. **Environment Variables**: Never hardcode credentials 2. **Token Rotation**: Implement regular token rotation in production 3. **HTTPS Only**: All API requests use HTTPS in production 4. **Secure Storage**: Never store tokens in localStorage for web apps 5. **Minimal Permissions**: Use tokens with minimal required permissions ```typescript // ✅ Good: Environment-based configuration const api = new AugurAPI({ siteId: process.env.AUGUR_SITE_ID!, bearerToken: getSecurelyStoredToken(), // From secure storage }); // ❌ Bad: Hardcoded credentials const api = new AugurAPI({ siteId: 'hardcoded-site-id', bearerToken: 'hardcoded-token', // Never do this! }); ``` --- ## Advanced: Cross-Site Authentication **⚠️ Advanced Feature**: Only needed for multi-tenant applications where you need to authenticate users across different sites. ### When You Need Cross-Site Auth Cross-site authentication is needed when: - You're building a multi-tenant application - You need to authenticate a user from one site against a different site - You're managing multiple client sites from a central application ### Prerequisites - Access to the special `augur_info` site - Admin-level JWT token with `augur_info` privileges - Target site ID where you want to authenticate the user ### Option 1: Streamlined Utility Function (Recommended) ```typescript import { authenticateUserForSite } from '@simpleapps-com/augur-api'; const result = await authenticateUserForSite({ targetSiteId: 'tenant_site_1', username: 'user@tenant.com', password: 'user-password', augurInfoToken: 'admin-jwt-token' // JWT with augur_info admin privileges }); if (result.success) { // Ready-to-use API client for the target site const userData = await result.targetSiteAPI!.joomla.users.get(result.userId!); console.log('User authenticated:', result.username); console.log('User data:', userData); } else { console.error('Authentication failed:', result.error); } ``` ### Option 2: Reusable Authenticator ```typescript import { createCrossSiteAuthenticator } from '@simpleapps-com/augur-api'; // Create reusable authenticator const crossSiteAuth = createCrossSiteAuthenticator('admin-jwt-token'); // Use for multiple sites const result1 = await crossSiteAuth('tenant_site_1', 'user1@tenant.com', 'pass1'); const result2 = await crossSiteAuth('tenant_site_2', 'user2@tenant.com', 'pass2'); if (result1.success) { const tenantData = await result1.targetSiteAPI!.joomla.content.list({ limit: 10 }); } ``` ### Option 3: Manual Approach ```typescript // Manual approach using the API client directly const crossSiteAPI = new AugurAPI({ siteId: 'augur_info', // Special site for cross-site operations bearerToken: 'admin-jwt-token', // JWT token with augur_info admin privileges }); // Authenticate user against a different site const authResult = await crossSiteAPI.joomla.users.verifyPassword({ username: 'user@tenant.com', password: 'user-password', siteId: 'tenant_site_1' // Target site for authentication }); if (authResult.data.isVerified) { // Create API instance for the target site const tenantAPI = new AugurAPI({ siteId: 'tenant_site_1', bearerToken: authResult.data.token, // Token scoped to tenant site }); const userData = await tenantAPI.joomla.users.get(authResult.data.id); } ``` ### Cross-Site Auth Flow Diagram ``` [Your App] → [augur_info API] → [Target Site] → [User Validated] → [Target Site API Client] ↓ ↓ ↓ ↓ ↓ Admin Token → Verify User → Check Password → Return User Token → Ready for API calls ``` ### Common Cross-Site Patterns #### Multi-Tenant Dashboard ```typescript // Authenticate users across multiple tenant sites const authenticator = createCrossSiteAuthenticator(adminToken); const tenants = ['site1', 'site2', 'site3']; const userCredentials = { username: 'user@example.com', password: 'pass' }; const results = await Promise.all( tenants.map(siteId => authenticator(siteId, userCredentials.username, userCredentials.password) ) ); // Process results for each tenant results.forEach((result, index) => { if (result.success) { console.log(`${tenants[index]}: User authenticated as ${result.username}`); } else { console.log(`${tenants[index]}: Authentication failed - ${result.error}`); } }); ``` #### Site Switching ```typescript // Allow users to switch between sites they have access to async function switchUserToSite(username: string, password: string, targetSiteId: string) { const result = await authenticateUserForSite({ targetSiteId, username, password, augurInfoToken: process.env.AUGUR_INFO_ADMIN_TOKEN! }); if (result.success) { // Store the new site's API client global.userAPI = result.targetSiteAPI; global.currentSiteId = targetSiteId; return { success: true, siteId: targetSiteId }; } return { success: false, error: result.error }; } ``` ### Cross-Site Error Handling ```typescript try { const result = await authenticateUserForSite({ targetSiteId: 'tenant-site', username: 'user@tenant.com', password: 'user-pass', augurInfoToken: adminToken }); if (!result.success) { switch (result.error) { case 'Invalid username or password': // Handle wrong username/password break; case 'Site not found': // Handle invalid target site (from API error) break; case 'Authentication failed': // Handle general auth failures or network issues break; default: // Handle other errors break; } } } catch (error) { console.error('Cross-site auth failed:', error.message); } ``` ### Security Considerations for Cross-Site Auth 1. **Admin Token Security**: The `augur_info` admin token is very powerful - store it extremely securely 2. **Audit Logging**: Log all cross-site authentication attempts for security monitoring 3. **Rate Limiting**: Implement rate limiting to prevent brute force attacks 4. **Token Scoping**: Returned tokens are scoped to the target site only 5. **Session Management**: Properly manage and clean up cross-site sessions ### When NOT to Use Cross-Site Auth Don't use cross-site authentication if: - You're working with a single site (use standard auth) - You don't have admin-level access to `augur_info` - You're building a simple application without multi-tenancy - Security requirements prohibit cross-site token exchange --- ## Troubleshooting Authentication ### Common Issues **"Authentication failed" (401 Error)** - Check your `bearerToken` is correct and not expired - Verify your `siteId` matches your environment - For cross-site auth, ensure your admin token has `augur_info` privileges **"Forbidden" (403 Error)** - Your token is valid but doesn't have permission for this operation - Check if you need admin-level permissions - Verify the site ID matches the token's scope **"Site not found" (Cross-site auth)** - Verify the target site ID exists and is accessible - Check that the target site is properly configured - Ensure your admin token has access to the target site **Token Expiration** - Implement token refresh logic - Monitor token expiration times - Have fallback authentication flow ### Authentication Testing ```typescript // Test standard authentication async function testAuth() { try { const api = new AugurAPI({ siteId: 'your-site-id', bearerToken: 'your-token' }); // Simple test call const health = await api.joomla.getHealthCheck(); console.log('✅ Authentication working:', health.data.status); // Test authenticated call const users = await api.joomla.users.list({ limit: 1 }); console.log('✅ Authenticated API calls working'); } catch (error) { console.error('❌ Authentication failed:', error.message); } } // Test cross-site authentication async function testCrossSiteAuth() { try { const result = await authenticateUserForSite({ targetSiteId: 'test-site', username: 'test-user', password: 'test-pass', augurInfoToken: 'admin-token' }); if (result.success) { console.log('✅ Cross-site auth working'); const testCall = await result.targetSiteAPI!.joomla.getHealthCheck(); console.log('✅ Target site API working:', testCall.data.status); } else { console.error('❌ Cross-site auth failed:', result.error); } } catch (error) { console.error('❌ Cross-site auth error:', error.message); } } ``` For most applications, stick with standard authentication. Only implement cross-site authentication if you specifically need multi-tenant capabilities.