Client-side auth SDK for WRAL audience web apps (magic code flow)
npm install @wral/sdk-auth-audienceClient-side authentication SDK for WRAL audience-facing web applications using AWS Cognito passwordless magic code flow.
This library provides a clean, pure-functional interface for:
- Sending magic code emails
- Verifying codes
- Refreshing tokens
- Protecting pages and making authenticated API calls
- Logging out (local + optional global sign-out)
It is designed for use in browser-based apps (e.g., login and dashboard experiences) and follows a modular, dependency-injected pattern for easy testing and composability.
- Passwordless magic code authentication (Cognito CUSTOM_AUTH flow)
- Automatic token refresh (short-lived ID/access tokens + long-lived refresh token)
- Auth guards (requireAuth) for protected routes
- Authenticated fetch wrapper with 401 auto-refresh
- Simple, one-call refresh and auth check helpers
- Pure functions with explicit dependencies (config, storage, etc.)
``bash`
npm install @wral/sdk-auth-audience
Note: This package has a peer dependency on amazon-cognito-identity-js@^6.3.16. Install it alongside if not already present.
First, set up your configuration. For production, use a script like the provided setup-config.example.mjs to override defaults via window.authConfig.
`js
// Import the SDK
import {
createAuthConfig,
createStorage,
sendCode,
verifyCode,
requireAuth,
authFetch,
logout,
createUserPool,
signUpIfNeeded,
createCognitoUser,
extractTokens,
saveTokens,
decodeJwtPayload,
} from '@wral/sdk-auth-audience';
// Define config (or use window.authConfig)
const config = createAuthConfig({
userPoolId: 'us-east-1_XXXXXXXXXX',
clientId: 'XXXXXXXXXXXXXXXXXXXXXXXXXX',
logoutApiUrl: 'https://your-logout-endpoint.execute-api.us-east-1.amazonaws.com/prod/logout',
});
// Create storage wrapper (uses localStorage by default)
const storage = createStorage();
// Send magic code to user
try {
const { cognitoUser, challengeRequired } = await sendCode(
config,
'user@example.com',
storage,
createUserPool,
signUpIfNeeded,
createCognitoUser,
extractTokens,
saveTokens,
decodeJwtPayload
);
if (challengeRequired) {
console.log('Code sent to email');
// Prompt user for code, then verify
const code = '123456'; // From user input
await verifyCode(
cognitoUser,
code,
storage,
extractTokens,
saveTokens,
decodeJwtPayload
);
console.log('Authenticated!');
}
} catch (err) {
console.error('Auth failed:', err);
}
// Protect a page (redirects if not authenticated)
await requireAuth(config, storage, '/login/');
// Make an authenticated API call (auto-refreshes on 401)
const response = await authFetch(
'https://api.example.com/protected-data',
{ method: 'GET' },
config,
storage
);
// Logout (with global sign-out)
await logout(config, storage, true);
`
→ Creates config object with defaults (userPoolId, clientId, etc.). Override via window.authConfig for easy setup.
- createStorage() → Returns a localStorage wrapper with get/set/remove/clear methods.
- STORAGE_KEYS → Object with standard key names (e.g., wral_id_token).$3
- sendCode(config, email, storage, ...helpers) → Sends magic code, handles auto-signup if needed. Returns { success, authenticated?, challengeRequired?, cognitoUser }.
- verifyCode(cognitoUser, code, storage, ...helpers) → Verifies code and saves tokens. Returns { success }.
- signUpIfNeeded(email, userPool, generateTempPassword) → Signs up user if not exists (used internally by sendCode).$3
For quick, hassle-free token management without passing dependencies:`js
import { refreshTokenSimple, isAuthenticatedSimple } from '@wral/sdk-auth-audience';async function checkAndRefresh() {
if (await isAuthenticatedSimple()) {
console.log('User is authenticated (refreshed if needed)');
// Proceed with protected actions
} else {
const newToken = await refreshTokenSimple();
if (newToken) {
console.log('Token refreshed successfully:', newToken);
} else {
console.log('Refresh failed – redirect to login');
window.location.href = '/login/';
}
}
}
`-
refreshTokenSimple() → Refreshes the session using cached config/storage. Returns new access token or null on failure.
- isAuthenticatedSimple() → Checks if authenticated, auto-refreshes if expired/missing. Returns boolean.These use internal caching for config/storage – ideal for simple apps or components.
$3
- refreshSession(config, storage, ...helpers) → Low-level refresh. Returns new access token or null.
- isAuthenticated(config, storage, refreshFn) → Checks auth status, calls refresh if needed. Returns boolean.$3
- requireAuth(config, storage, [loginUrl='/login/']) → Redirects to login if not authenticated.
- getAuthHeaders(config, storage) → Returns { Authorization: 'Bearer (refreshes if needed).
- authFetch(url, options, config, storage) → Authenticated fetch with auto-refresh/retry on 401.$3
- logout(config, storage, [globalSignOut=true]) → Clears tokens + optional global sign-out via API.
- decodeJwtPayload(token) → Decodes JWT payload (pure function).
- generateTempPassword() → Generates Cognito-compliant temp password.
- createUserPool(config) / createCognitoUser(email, userPool) / extractTokens(result) → Cognito SDK wrappers.
- saveTokens(storage, tokens, decodeJwtPayload) → Saves tokens to storage.Development & Testing
`bash
npm run lint # Check code style (ESLint)
npm run test # Run Jest tests with coverage
npm run build # Build dist/ (ESM + CJS + types)
`Tests use jsdom and mocks for Cognito/fetch. Coverage reports in
coverage/.Publishing
- Use semver tags (e.g.,
v0.1.0`)See CONTRIBUTING.md for guidelines.
---
© WRAL – UNLICENSED