Skip to main content

Getting Started

Complete guide to setting up authentication in your frontend application with @nauth-toolkit/client.

Framework-Specific Guides

For dedicated setup guides with full working examples, see Angular Standalone, Angular NgModule, React, or Capacitor Mobile. This page covers the generic SDK setup that works with any framework.

Prerequisites

  • nauth-toolkit backend running and configured
  • Node.js 22+
  • Your framework of choice (Angular, React, Vue, etc.)

Installation

npm install @nauth-toolkit/client

Step 1: Determine Token Delivery Mode

Your frontend must match your backend's token delivery mode:

Frontend ModeBackend EndpointUse Case
cookies/auth (cookies mode)Web apps (recommended)
json/auth (JSON mode)Mobile/native apps

Check your backend's nauth.config.ts:

// Backend configuration
NAuthModule.forRoot({
tokenDelivery: {
method: 'cookies', // Your mode
// ...
},
});

If your backend uses tokenDelivery.method = 'hybrid', the same /auth endpoints can serve both web (cookies) and native/mobile (JSON) clients. The backend selects delivery based on request origin (see Configuration).

See NAuthClientConfig for all configuration options including custom storage adapters, CSRF settings, endpoint overrides, and callbacks.

Step 2: Initialize the Client

Create and configure the NAuthClient instance. The client handles token storage, refresh, and API communication. Call initialize() on app startup to hydrate authentication state from storage.

Token Storage

For JSON token delivery mode, tokens are stored using a storage adapter. The SDK provides built-in adapters and supports custom implementations:

Storage OptionUse CaseDefault
BrowserStorage (localStorage)Web apps, persistent sessionsYes (browser)
BrowserStorage (sessionStorage)Web apps, session-only storageNo
InMemoryStorageSSR, testing, temporaryYes (SSR)
Custom adapterMobile apps (Capacitor, React Native), secure storageNo

Note: For cookies mode, tokens are managed by the browser and backend—no storage adapter needed.

Cookies mode (no storage needed):

// auth.ts
import { NAuthClient } from '@nauth-toolkit/client';

export const authClient = new NAuthClient({
baseUrl: 'https://api.yourapp.com/auth',
tokenDelivery: 'cookies', // Cookies mode - no storage needed
onSessionExpired: () => {
// Handle session expiration - use your router for navigation
if (typeof window !== 'undefined') {
window.location.replace('/login');
}
},
onAuthStateChange: (user) => {
// React to auth changes
// Use your application's logger/telemetry here
},
});

JSON mode with localStorage (default):

import { NAuthClient, BrowserStorage } from '@nauth-toolkit/client';

export const authClient = new NAuthClient({
baseUrl: 'https://api.yourapp.com/auth',
tokenDelivery: 'json', // JSON mode requires storage
storage: new BrowserStorage(), // Default for web apps (uses localStorage)
onSessionExpired: () => {
if (typeof window !== 'undefined') {
window.location.replace('/login');
}
},
});

JSON mode with custom storage (e.g., Capacitor):

import { NAuthClient, NAuthStorageAdapter } from '@nauth-toolkit/client';
import { Preferences } from '@capacitor/preferences';

class CapacitorStorage implements NAuthStorageAdapter {
async getItem(key: string): Promise<string | null> {
const { value } = await Preferences.get({ key });
return value;
}
async setItem(key: string, value: string): Promise<void> {
await Preferences.set({ key, value });
}
async removeItem(key: string): Promise<void> {
await Preferences.remove({ key });
}
async clear(): Promise<void> {
await Preferences.clear();
}
}

export const authClient = new NAuthClient({
baseUrl: 'https://api.yourapp.com/auth',
tokenDelivery: 'json',
storage: new CapacitorStorage(), // Custom mobile storage
onSessionExpired: () => {
// Handle session expiration
},
});

See NAuthStorageAdapter for interface details and more examples.

See NAuthClient API and Configuration for details.

// main.ts
import { initAuth, authClient } from './auth';

async function bootstrap(): Promise<void> {
// Initialize auth before rendering
await initAuth();

// Check if already logged in
if (authClient.isAuthenticatedSync()) {
// Use your application's logger/telemetry here
}

// Render your app
renderApp();
}

bootstrap();

Step 3: Implement Login

Handle user authentication with email/password. The login() method returns an AuthResponse that may contain a challenge (email verification, MFA, etc.) or successful authentication with tokens. Always check for challengeName to handle multi-step flows.

import { authClient } from './auth';

async function handleLogin(email: string, password: string): Promise<void> {
try {
const response = await authClient.login(email, password);

if (response.challengeName) {
// User needs to complete a challenge
handleChallenge(response);
} else {
// Login successful - use your router
if (typeof window !== 'undefined') {
window.location.href = '/dashboard';
}
}
} catch (error) {
console.error('Login failed:', error.message);
}
}

function handleChallenge(response: AuthResponse): void {
// Store session for challenge pages
if (typeof window !== 'undefined') {
sessionStorage.setItem('challengeSession', JSON.stringify(response));

// Use your router for navigation
const routes: Record<string, string> = {
VERIFY_EMAIL: '/verify-email',
VERIFY_PHONE: '/verify-phone',
MFA_REQUIRED: '/mfa',
MFA_SETUP_REQUIRED: '/mfa-setup',
FORCE_CHANGE_PASSWORD: '/change-password',
};

const route = routes[response.challengeName!];
if (route) {
window.location.href = route;
}
}
}

Step 4: Protect Routes

Protect routes that require authentication. You can use the built-in authGuard (Angular) or implement your own route protection logic.

// router.ts (example with vanilla router)
function checkAuth(): boolean {
return authClient.isAuthenticatedSync();
}

function protectedRoute(path: string, component: Component): void {
if (!checkAuth()) {
// Use your router for navigation
if (typeof window !== 'undefined') {
window.location.replace(`/login?returnUrl=${encodeURIComponent(path)}`);
}
return;
}
renderComponent(component);
}

Token Refresh

The SDK automatically handles token refresh for you. When using the Angular authInterceptor, expired access tokens are automatically refreshed in the background before retrying failed requests. The interceptor:

  • Attaches authentication headers (Bearer tokens for JSON mode, CSRF tokens for cookies mode)
  • Detects 401 responses and triggers token refresh
  • Queues concurrent requests during refresh to prevent race conditions
  • Synchronizes tokens across browser tabs using localStorage events (JSON mode)

For detailed information on token refresh strategies, cross-tab synchronization, and SSR considerations, see Token Management.

Step 5: Handle Logout

Clear authentication state and redirect to login. The logout() method invalidates the session on the backend and clears local tokens.

async function handleLogout(): Promise<void> {
await authClient.logout();
// Use your router for navigation
if (typeof window !== 'undefined') {
window.location.replace('/login');
}
}

Next Steps