@wral/sdk-auth-audience
v0.3.0
Published
Client-side auth SDK for WRAL audience web apps (magic code flow)
Keywords
Readme
@wral/sdk-auth-audience
Client-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.
Features
- Passwordless magic code authentication (Cognito
CUSTOM_AUTHflow) - Automatic token refresh (short-lived ID/access tokens + long-lived refresh token)
- Auth guards (
requireAuth) for protected routes - Authenticated
fetchwrapper with 401 auto-refresh - Simple, one-call refresh and auth check helpers
- Pure functions with explicit dependencies (config, storage, etc.)
Installation
npm install @wral/sdk-auth-audienceNote: This package has a peer dependency on amazon-cognito-identity-js@^6.3.16. Install it alongside if not already present.
Quick Start
First, set up your configuration. For production, use a script like the provided setup-config.example.mjs to override defaults via window.authConfig.
// 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,
'[email protected]',
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);Core API
Configuration and Setup
createAuthConfig(overrides?)→ Creates config object with defaults (userPoolId, clientId, etc.). Override viawindow.authConfigfor 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).
Authentication Flow
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 bysendCode).
Simple Token Refresh and Checks
For quick, hassle-free token management without passing dependencies:
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 ornullon failure.isAuthenticatedSimple()→ Checks if authenticated, auto-refreshes if expired/missing. Returnsboolean.
These use internal caching for config/storage – ideal for simple apps or components.
Advanced Token Management
refreshSession(config, storage, ...helpers)→ Low-level refresh. Returns new access token ornull.isAuthenticated(config, storage, refreshFn)→ Checks auth status, calls refresh if needed. Returnsboolean.
Protection & API Calls
requireAuth(config, storage, [loginUrl='/login/'])→ Redirects to login if not authenticated.getAuthHeaders(config, storage)→ Returns{ Authorization: 'Bearer <token>' }(refreshes if needed).authFetch(url, options, config, storage)→ Authenticated fetch with auto-refresh/retry on 401.
Utils
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
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) - Push tags to trigger Bitbucket pipeline (lint, test, build, publish to npm)
- Pipeline publishes to public npm (scoped @wral)
Contributing
See CONTRIBUTING.md for guidelines.
© WRAL – UNLICENSED
