@nauth-toolkit/client 0.1.18 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/angular/index.ts","../../src/angular/tokens.ts","../../src/angular/auth.service.ts","../../src/angular/http-adapter.ts","../../src/core/errors.ts","../../src/core/config.ts","../../src/core/refresh.ts","../../src/storage/browser.ts","../../src/storage/memory.ts","../../src/core/events.ts","../../src/adapters/fetch-adapter.ts","../../src/core/client.ts","../../src/angular/auth.interceptor.ts","../../src/angular/auth.guard.ts","../../src/angular/oauth-callback.guard.ts","../../src/angular/auth.module.ts"],"sourcesContent":["export * from './tokens';\nexport * from './auth.service';\nexport * from './auth.interceptor';\nexport * from './auth.guard';\nexport * from './oauth-callback.guard';\nexport * from './auth.module';\nexport * from './http-adapter';\n\n// Re-export commonly used types for convenience\nexport type { NAuthClientConfig, TokenDeliveryMode } from '../types/config.types';\nexport type { AuthResponse, ChallengeResponse, TokenResponse, AuthChallenge } from '../types/auth.types';\nexport type { AuthUser } from '../types/user.types';\nexport type { MFAStatus, MFAMethod, MFADeviceMethod } from '../types/mfa.types';\nexport type { AuthEvent, AuthEventType, AuthEventListener } from '../core/events';\nexport type { SocialProvider } from '../types/social.types';\nexport type { HttpAdapter } from '../core/http-adapter';\n","import { InjectionToken } from '@angular/core';\nimport { NAuthClientConfig } from '../types/config.types';\n\n/**\n * Injection token for providing NAuthClientConfig in Angular apps.\n */\nexport const NAUTH_CLIENT_CONFIG = new InjectionToken<NAuthClientConfig>('NAUTH_CLIENT_CONFIG');\n","import { Inject, Injectable, Optional, inject } from '@angular/core';\nimport { BehaviorSubject, from, Observable, Subject } from 'rxjs';\nimport { filter } from 'rxjs/operators';\nimport { NAUTH_CLIENT_CONFIG } from './tokens';\nimport { AngularHttpAdapter } from './http-adapter';\nimport { NAuthClient } from '../core/client';\nimport { NAuthClientConfig } from '../types/config.types';\nimport { ChallengeResponse, AuthResponse, TokenResponse } from '../types/auth.types';\nimport { AuthUser, ConfirmForgotPasswordResponse, ForgotPasswordResponse } from '../types/user.types';\nimport { GetChallengeDataResponse, GetSetupDataResponse } from '../types/mfa.types';\nimport { AuthEvent } from '../core/events';\nimport { SocialProvider } from '../types/social.types';\n\n/**\n * Angular wrapper around NAuthClient that exposes Observables for auth state.\n *\n * Design philosophy: Keep lean, use getClient() for full API access.\n * This service provides:\n * - Reactive state (currentUser$, isAuthenticated$, challenge$)\n * - Core auth methods as Observables (login, signup, logout, refresh)\n * - Challenge flow methods (respondToChallenge, resendCode)\n * - Escape hatch via getClient() for all other operations\n *\n * @example\n * ```typescript\n * constructor(private auth: AuthService) {}\n *\n * // Reactive state\n * this.auth.currentUser$.subscribe(user => ...);\n * this.auth.isAuthenticated$.subscribe(isAuth => ...);\n *\n * // Auth operations\n * this.auth.login(email, password).subscribe(response => ...);\n *\n * // Advanced operations via client\n * this.auth.getClient().getMfaStatus().then(status => ...);\n * ```\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class AuthService {\n private readonly client: NAuthClient;\n private readonly config: NAuthClientConfig;\n private readonly currentUserSubject = new BehaviorSubject<AuthUser | null>(null);\n private readonly isAuthenticatedSubject = new BehaviorSubject<boolean>(false);\n private readonly challengeSubject = new BehaviorSubject<AuthResponse | null>(null);\n private readonly authEventsSubject = new Subject<AuthEvent>();\n private initialized = false;\n\n /**\n * @param config - Injected client configuration\n *\n * Note: AngularHttpAdapter is automatically injected via Angular DI.\n * This ensures all requests go through Angular's HttpClient and interceptors.\n */\n constructor(@Optional() @Inject(NAUTH_CLIENT_CONFIG) config?: NAuthClientConfig) {\n if (!config) {\n throw new Error('NAUTH_CLIENT_CONFIG is required to initialize AuthService');\n }\n\n this.config = config;\n\n // Auto-inject AngularHttpAdapter (or use provided one)\n const httpAdapter = config.httpAdapter ?? inject(AngularHttpAdapter);\n\n this.client = new NAuthClient({\n ...config,\n httpAdapter, // Automatically use Angular's HttpClient\n onAuthStateChange: (user) => {\n this.currentUserSubject.next(user);\n this.isAuthenticatedSubject.next(Boolean(user));\n config.onAuthStateChange?.(user);\n },\n });\n\n // Forward all client events to Observable stream\n this.client.on('*', (event) => {\n this.authEventsSubject.next(event);\n });\n\n // Auto-initialize on construction (hydrate from storage)\n this.initialize();\n }\n\n // ============================================================================\n // Reactive State Observables\n // ============================================================================\n\n /**\n * Current user observable.\n */\n get currentUser$(): Observable<AuthUser | null> {\n return this.currentUserSubject.asObservable();\n }\n\n /**\n * Authenticated state observable.\n */\n get isAuthenticated$(): Observable<boolean> {\n return this.isAuthenticatedSubject.asObservable();\n }\n\n /**\n * Current challenge observable (for reactive challenge navigation).\n */\n get challenge$(): Observable<AuthResponse | null> {\n return this.challengeSubject.asObservable();\n }\n\n /**\n * Authentication events stream.\n * Emits all auth lifecycle events for custom logic, analytics, or UI updates.\n */\n get authEvents$(): Observable<AuthEvent> {\n return this.authEventsSubject.asObservable();\n }\n\n /**\n * Successful authentication events stream.\n * Emits when user successfully authenticates (login, signup, social auth).\n */\n get authSuccess$(): Observable<AuthEvent> {\n return this.authEventsSubject.pipe(filter((e) => e.type === 'auth:success'));\n }\n\n /**\n * Authentication error events stream.\n * Emits when authentication fails (login error, OAuth error, etc.).\n */\n get authError$(): Observable<AuthEvent> {\n return this.authEventsSubject.pipe(filter((e) => e.type === 'auth:error' || e.type === 'oauth:error'));\n }\n\n // ============================================================================\n // Sync State Accessors (for guards, templates)\n // ============================================================================\n\n /**\n * Check if authenticated (sync, uses cached state).\n */\n isAuthenticated(): boolean {\n return this.client.isAuthenticatedSync();\n }\n\n /**\n * Get current user (sync, uses cached state).\n */\n getCurrentUser(): AuthUser | null {\n return this.client.getCurrentUser();\n }\n\n /**\n * Get current challenge (sync).\n */\n getCurrentChallenge(): AuthResponse | null {\n return this.challengeSubject.value;\n }\n\n // ============================================================================\n // Core Auth Methods (Observable wrappers)\n // ============================================================================\n\n /**\n * Login with identifier and password.\n */\n login(identifier: string, password: string): Observable<AuthResponse> {\n return from(this.client.login(identifier, password).then((res) => this.updateChallengeState(res)));\n }\n\n /**\n * Signup with credentials.\n */\n signup(payload: Parameters<NAuthClient['signup']>[0]): Observable<AuthResponse> {\n return from(this.client.signup(payload).then((res) => this.updateChallengeState(res)));\n }\n\n /**\n * Logout current session.\n */\n logout(forgetDevice?: boolean): Observable<void> {\n return from(\n this.client.logout(forgetDevice).then(() => {\n this.challengeSubject.next(null);\n // Explicitly update auth state after logout\n this.currentUserSubject.next(null);\n this.isAuthenticatedSubject.next(false);\n\n // Clear CSRF token cookie if in cookies mode\n // Note: Backend should clear httpOnly cookies, but we clear non-httpOnly ones\n if (this.config.tokenDelivery === 'cookies' && typeof document !== 'undefined') {\n const csrfCookieName = this.config.csrf?.cookieName ?? 'nauth_csrf_token';\n // Extract domain from baseUrl if possible\n try {\n const url = new URL(this.config.baseUrl);\n document.cookie = `${csrfCookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${url.hostname}`;\n // Also try without domain (for localhost)\n document.cookie = `${csrfCookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n } catch {\n // Fallback if baseUrl parsing fails\n document.cookie = `${csrfCookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n }\n }\n }),\n );\n }\n\n /**\n * Logout all sessions.\n *\n * Revokes all active sessions for the current user across all devices.\n * Optionally revokes all trusted devices if forgetDevices is true.\n *\n * @param forgetDevices - If true, also revokes all trusted devices (default: false)\n * @returns Observable with number of sessions revoked\n */\n logoutAll(forgetDevices?: boolean): Observable<{ revokedCount: number }> {\n return from(\n this.client.logoutAll(forgetDevices).then((res) => {\n this.challengeSubject.next(null);\n // Explicitly update auth state after logout\n this.currentUserSubject.next(null);\n this.isAuthenticatedSubject.next(false);\n return res;\n }),\n );\n }\n\n /**\n * Refresh tokens.\n */\n refresh(): Observable<TokenResponse> {\n return from(this.client.refreshTokens());\n }\n\n // ============================================================================\n // Account Recovery (Forgot Password)\n // ============================================================================\n\n /**\n * Request a password reset code (forgot password).\n */\n forgotPassword(identifier: string): Observable<ForgotPasswordResponse> {\n return from(this.client.forgotPassword(identifier));\n }\n\n /**\n * Confirm a password reset code and set a new password.\n */\n confirmForgotPassword(\n identifier: string,\n code: string,\n newPassword: string,\n ): Observable<ConfirmForgotPasswordResponse> {\n return from(this.client.confirmForgotPassword(identifier, code, newPassword));\n }\n\n // ============================================================================\n // Challenge Flow Methods (Essential for any auth flow)\n // ============================================================================\n\n /**\n * Respond to a challenge (VERIFY_EMAIL, VERIFY_PHONE, MFA_REQUIRED, etc.).\n */\n respondToChallenge(response: ChallengeResponse): Observable<AuthResponse> {\n return from(this.client.respondToChallenge(response).then((res) => this.updateChallengeState(res)));\n }\n\n /**\n * Resend challenge code.\n */\n resendCode(session: string): Observable<{ destination: string }> {\n return from(this.client.resendCode(session));\n }\n\n /**\n * Get MFA setup data (for MFA_SETUP_REQUIRED challenge).\n *\n * Returns method-specific setup information:\n * - TOTP: { secret, qrCode, manualEntryKey }\n * - SMS: { maskedPhone }\n * - Email: { maskedEmail }\n * - Passkey: WebAuthn registration options\n *\n * @param session - Challenge session token\n * @param method - MFA method to set up\n * @returns Observable of setup data response\n */\n getSetupData(session: string, method: string): Observable<GetSetupDataResponse> {\n return from(this.client.getSetupData(session, method as Parameters<NAuthClient['getSetupData']>[1]));\n }\n\n /**\n * Get MFA challenge data (for MFA_REQUIRED challenge - e.g., passkey options).\n *\n * @param session - Challenge session token\n * @param method - Challenge method\n * @returns Observable of challenge data response\n */\n getChallengeData(session: string, method: string): Observable<GetChallengeDataResponse> {\n return from(this.client.getChallengeData(session, method as Parameters<NAuthClient['getChallengeData']>[1]));\n }\n\n /**\n * Clear stored challenge (when navigating away from challenge flow).\n */\n clearChallenge(): Observable<void> {\n return from(\n this.client.clearStoredChallenge().then(() => {\n this.challengeSubject.next(null);\n }),\n );\n }\n\n // ============================================================================\n // Social Authentication\n // ============================================================================\n\n /**\n * Initiate social OAuth login flow.\n * Redirects to OAuth provider with automatic state management.\n */\n loginWithSocial(provider: SocialProvider, options?: { redirectUri?: string }): Promise<void> {\n return this.client.loginWithSocial(provider, options);\n }\n\n /**\n * Get social auth URL to redirect user for OAuth (low-level API).\n */\n getSocialAuthUrl(provider: string, redirectUri?: string): Observable<{ url: string }> {\n return from(\n this.client.getSocialAuthUrl({ provider, redirectUri } as Parameters<NAuthClient['getSocialAuthUrl']>[0]),\n );\n }\n\n /**\n * Handle social auth callback (low-level API).\n */\n handleSocialCallback(provider: string, code: string, state: string): Observable<AuthResponse> {\n return from(\n this.client\n .handleSocialCallback({ provider, code, state } as Parameters<NAuthClient['handleSocialCallback']>[0])\n .then((res) => this.updateChallengeState(res)),\n );\n }\n\n // ============================================================================\n // Escape Hatch\n // ============================================================================\n\n /**\n * Expose underlying NAuthClient for advanced scenarios.\n *\n * Use this for operations not directly exposed by this service:\n * - Profile management (getProfile, updateProfile)\n * - MFA management (getMfaStatus, setupMfaDevice, etc.)\n * - Social account linking (linkSocialAccount, unlinkSocialAccount)\n * - Audit history (getAuditHistory)\n * - Device trust (trustDevice)\n *\n * @example\n * ```typescript\n * // Get MFA status\n * const status = await this.auth.getClient().getMfaStatus();\n *\n * // Update profile\n * const user = await this.auth.getClient().updateProfile({ firstName: 'John' });\n * ```\n */\n getClient(): NAuthClient {\n return this.client;\n }\n\n // ============================================================================\n // Internal Methods\n // ============================================================================\n\n /**\n * Initialize by hydrating state from storage.\n * Called automatically on construction.\n */\n private async initialize(): Promise<void> {\n if (this.initialized) return;\n this.initialized = true;\n\n await this.client.initialize();\n\n // Hydrate challenge state\n const storedChallenge = await this.client.getStoredChallenge();\n if (storedChallenge) {\n this.challengeSubject.next(storedChallenge);\n }\n\n // Update subjects from client state\n const user = this.client.getCurrentUser();\n if (user) {\n this.currentUserSubject.next(user);\n this.isAuthenticatedSubject.next(true);\n }\n }\n\n /**\n * Update challenge state after auth response.\n */\n private updateChallengeState(response: AuthResponse): AuthResponse {\n if (response.challengeName) {\n this.challengeSubject.next(response);\n } else {\n this.challengeSubject.next(null);\n }\n return response;\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { HttpClient, HttpErrorResponse } from '@angular/common/http';\nimport { firstValueFrom } from 'rxjs';\nimport { HttpAdapter, HttpRequest, HttpResponse } from '../core/http-adapter';\nimport { NAuthClientError } from '../core/errors';\nimport { NAuthErrorCode } from '../types/error.types';\n\n/**\n * HTTP adapter for Angular using HttpClient.\n *\n * This adapter:\n * - Uses Angular's HttpClient for all requests\n * - Works with Angular's HTTP interceptors (including authInterceptor)\n * - Auto-provided via Angular DI (providedIn: 'root')\n * - Converts HttpClient responses to HttpResponse format\n * - Converts HttpErrorResponse to NAuthClientError\n *\n * Users don't need to configure this manually - it's automatically\n * injected when using AuthService in Angular apps.\n *\n * @example\n * ```typescript\n * // Automatic usage (no manual setup needed)\n * // AuthService automatically injects AngularHttpAdapter\n * constructor(private auth: AuthService) {}\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class AngularHttpAdapter implements HttpAdapter {\n private readonly http = inject(HttpClient);\n\n /**\n * Execute HTTP request using Angular's HttpClient.\n *\n * @param config - Request configuration\n * @returns Response with parsed data\n * @throws NAuthClientError if request fails\n */\n async request<T>(config: HttpRequest): Promise<HttpResponse<T>> {\n try {\n // Use Angular's HttpClient - goes through ALL interceptors\n const data = await firstValueFrom(\n this.http.request<T>(config.method, config.url, {\n body: config.body,\n headers: config.headers,\n withCredentials: config.credentials === 'include',\n observe: 'body', // Only return body data\n }),\n );\n\n return {\n data,\n status: 200, // HttpClient only returns data on success\n headers: {}, // Can extract from observe: 'response' if needed\n };\n } catch (error) {\n if (error instanceof HttpErrorResponse) {\n // Convert Angular's HttpErrorResponse to NAuthClientError\n const errorData = error.error || {};\n const code =\n typeof errorData['code'] === 'string' ? (errorData.code as NAuthErrorCode) : NAuthErrorCode.INTERNAL_ERROR;\n const message =\n typeof errorData['message'] === 'string'\n ? (errorData.message as string)\n : error.message || `Request failed with status ${error.status}`;\n const timestamp = typeof errorData['timestamp'] === 'string' ? errorData.timestamp : undefined;\n const details = errorData['details'] as Record<string, unknown> | undefined;\n\n throw new NAuthClientError(code, message, {\n statusCode: error.status,\n timestamp,\n details,\n isNetworkError: error.status === 0, // Network error (no response from server)\n });\n }\n\n // Re-throw non-HTTP errors\n throw error;\n }\n }\n}\n\n\n\n","import { NAuthError, NAuthErrorCode } from '../types/error.types';\n\n/**\n * Client-side error wrapper for SDK operations.\n *\n * Mirrors the backend NAuthException structure for consistent error handling.\n *\n * @example\n * ```typescript\n * try {\n * await client.login({ identifier: 'user@example.com', password: 'wrong' });\n * } catch (error) {\n * if (error instanceof NAuthClientError) {\n * console.log(error.code); // 'AUTH_INVALID_CREDENTIALS'\n * console.log(error.message); // 'Invalid credentials'\n * console.log(error.timestamp); // '2025-12-06T...'\n *\n * // Check specific error code\n * if (error.isCode(NAuthErrorCode.RATE_LIMIT_LOGIN)) {\n * const retryAfter = error.details?.retryAfter as number;\n * console.log(`Rate limited. Retry in ${retryAfter}s`);\n * }\n * }\n * }\n * ```\n */\nexport class NAuthClientError extends Error implements NAuthError {\n public readonly code: NAuthErrorCode;\n public readonly details?: Record<string, unknown>;\n public readonly statusCode?: number;\n public readonly timestamp: string;\n public readonly isNetworkError: boolean;\n\n /**\n * Create a new client error.\n *\n * @param code - Error code from NAuthErrorCode enum\n * @param message - Human-readable error message\n * @param options - Optional metadata including details, statusCode, timestamp, and network error flag\n */\n constructor(\n code: NAuthErrorCode,\n message: string,\n options?: {\n details?: Record<string, unknown>;\n statusCode?: number;\n timestamp?: string;\n isNetworkError?: boolean;\n },\n ) {\n super(message);\n this.code = code;\n this.details = options?.details;\n this.statusCode = options?.statusCode;\n this.timestamp = options?.timestamp || new Date().toISOString();\n this.isNetworkError = options?.isNetworkError ?? false;\n this.name = 'NAuthClientError';\n Object.setPrototypeOf(this, NAuthClientError.prototype);\n }\n\n /**\n * Check if error matches a specific error code.\n *\n * @param code - Error code to check against\n * @returns True if the error code matches\n *\n * @example\n * ```typescript\n * if (error.isCode(NAuthErrorCode.RATE_LIMIT_SMS)) {\n * // Handle SMS rate limit\n * }\n * ```\n */\n isCode(code: NAuthErrorCode): boolean {\n return this.code === code;\n }\n\n /**\n * Get error details/metadata.\n *\n * @returns Error details object or undefined\n *\n * @example\n * ```typescript\n * const details = error.getDetails();\n * if (details?.retryAfter) {\n * console.log(`Retry after ${details.retryAfter} seconds`);\n * }\n * ```\n */\n getDetails(): Record<string, unknown> | undefined {\n return this.details;\n }\n\n /**\n * Get the error code.\n *\n * @returns The error code enum value\n */\n getCode(): NAuthErrorCode {\n return this.code;\n }\n\n /**\n * Serialize error to JSON object.\n *\n * @returns Plain object representation\n *\n * @example\n * ```typescript\n * const errorJson = error.toJSON();\n * // { code: 'AUTH_INVALID_CREDENTIALS', message: '...', timestamp: '...', details: {...} }\n * ```\n */\n toJSON(): {\n code: string;\n message: string;\n timestamp: string;\n details?: Record<string, unknown>;\n statusCode?: number;\n } {\n return {\n code: this.code,\n message: this.message,\n timestamp: this.timestamp,\n details: this.details,\n statusCode: this.statusCode,\n };\n }\n}\n","import {\n NAuthClientConfig,\n NAuthEndpoints,\n NAuthStorageAdapter,\n TokenDeliveryMode,\n HttpAdapter,\n} from '../types/config.types';\n\n/**\n * Fully resolved configuration with all defaults applied.\n */\nexport type ResolvedNAuthClientConfig = Omit<\n NAuthClientConfig,\n 'endpoints' | 'storage' | 'tokenDelivery' | 'httpAdapter'\n> & {\n tokenDelivery: TokenDeliveryMode;\n endpoints: NAuthEndpoints;\n storage: NAuthStorageAdapter;\n httpAdapter: HttpAdapter;\n csrf: { cookieName: string; headerName: string };\n deviceTrust: { headerName: string; storageKey: string };\n headers: Record<string, string>;\n timeout: number;\n};\n\n/**\n * Default endpoint paths matching backend controller.\n */\nexport const defaultEndpoints: NAuthEndpoints = {\n login: '/login',\n signup: '/signup',\n logout: '/logout',\n logoutAll: '/logout/all',\n refresh: '/refresh',\n respondChallenge: '/respond-challenge',\n resendCode: '/challenge/resend',\n getSetupData: '/challenge/setup-data',\n getChallengeData: '/challenge/challenge-data',\n profile: '/profile',\n changePassword: '/change-password',\n requestPasswordChange: '/request-password-change',\n forgotPassword: '/forgot-password',\n confirmForgotPassword: '/forgot-password/confirm',\n mfaStatus: '/mfa/status',\n mfaDevices: '/mfa/devices',\n mfaSetupData: '/mfa/setup-data',\n mfaVerifySetup: '/mfa/verify-setup',\n mfaRemove: '/mfa/method',\n mfaPreferred: '/mfa/preferred-method',\n mfaBackupCodes: '/mfa/backup-codes/generate',\n mfaExemption: '/mfa/exemption',\n socialAuthUrl: '/social/auth-url',\n socialCallback: '/social/callback',\n socialLinked: '/social/linked',\n socialLink: '/social/link',\n socialUnlink: '/social/unlink',\n socialVerify: '/social/:provider/verify',\n trustDevice: '/trust-device',\n isTrustedDevice: '/is-trusted-device',\n auditHistory: '/audit/history',\n updateProfile: '/profile',\n};\n\n/**\n * Normalize user config with defaults.\n *\n * @param config - User supplied config\n * @param defaultAdapter - Default HTTP adapter (FetchAdapter for vanilla, AngularHttpAdapter for Angular)\n * @returns Resolved config with defaults applied\n */\nexport const resolveConfig = (config: NAuthClientConfig, defaultAdapter: HttpAdapter): ResolvedNAuthClientConfig => {\n const resolvedEndpoints: NAuthEndpoints = {\n ...defaultEndpoints,\n ...(config.endpoints ?? {}),\n };\n\n return {\n ...config,\n csrf: {\n cookieName: config.csrf?.cookieName ?? 'nauth_csrf_token',\n headerName: config.csrf?.headerName ?? 'x-csrf-token',\n },\n deviceTrust: {\n headerName: config.deviceTrust?.headerName ?? 'X-Device-Token',\n storageKey: config.deviceTrust?.storageKey ?? 'nauth_device_token',\n },\n headers: config.headers ?? {},\n timeout: config.timeout ?? 30000,\n endpoints: resolvedEndpoints,\n storage: config.storage as NAuthStorageAdapter,\n httpAdapter: config.httpAdapter ?? defaultAdapter,\n };\n};\n","import { TokenResponse } from '../types/auth.types';\nimport { NAuthStorageAdapter } from '../types/config.types';\nimport { NAuthClientError } from './errors';\nimport { NAuthErrorCode } from '../types/error.types';\n\nconst ACCESS_TOKEN_KEY = 'nauth_access_token';\nconst REFRESH_TOKEN_KEY = 'nauth_refresh_token';\nconst ACCESS_EXPIRES_AT_KEY = 'nauth_access_token_expires_at';\nconst REFRESH_EXPIRES_AT_KEY = 'nauth_refresh_token_expires_at';\nconst USER_KEY = 'nauth_user';\nconst CHALLENGE_KEY = 'nauth_challenge_session';\n\n/**\n * Token state persisted in storage.\n */\nexport interface TokenState {\n accessToken: string | null;\n refreshToken: string | null;\n accessTokenExpiresAt?: number | null;\n refreshTokenExpiresAt?: number | null;\n}\n\n/**\n * Manage token persistence and refresh queuing.\n */\nexport class TokenManager {\n private readonly storage: NAuthStorageAdapter;\n private refreshPromise: Promise<TokenResponse> | null = null;\n private readonly isBrowser = typeof window !== 'undefined';\n\n /**\n * @param storage - storage adapter\n */\n constructor(storage: NAuthStorageAdapter) {\n this.storage = storage;\n }\n\n /**\n * Load tokens from storage.\n */\n async getTokens(): Promise<TokenState> {\n const [accessToken, refreshToken, accessExpRaw, refreshExpRaw] = await Promise.all([\n this.storage.getItem(ACCESS_TOKEN_KEY),\n this.storage.getItem(REFRESH_TOKEN_KEY),\n this.storage.getItem(ACCESS_EXPIRES_AT_KEY),\n this.storage.getItem(REFRESH_EXPIRES_AT_KEY),\n ]);\n return {\n accessToken,\n refreshToken,\n accessTokenExpiresAt: accessExpRaw ? Number(accessExpRaw) : null,\n refreshTokenExpiresAt: refreshExpRaw ? Number(refreshExpRaw) : null,\n };\n }\n\n /**\n * Persist tokens.\n *\n * @param tokens - new token pair\n */\n async setTokens(tokens: TokenResponse): Promise<void> {\n await Promise.all([\n this.storage.setItem(ACCESS_TOKEN_KEY, tokens.accessToken),\n this.storage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken),\n this.storage.setItem(ACCESS_EXPIRES_AT_KEY, tokens.accessTokenExpiresAt.toString()),\n this.storage.setItem(REFRESH_EXPIRES_AT_KEY, tokens.refreshTokenExpiresAt.toString()),\n ]);\n this.broadcastStorage();\n }\n\n /**\n * Clear tokens and related auth state.\n */\n async clearTokens(): Promise<void> {\n await Promise.all([\n this.storage.removeItem(ACCESS_TOKEN_KEY),\n this.storage.removeItem(REFRESH_TOKEN_KEY),\n this.storage.removeItem(ACCESS_EXPIRES_AT_KEY),\n this.storage.removeItem(REFRESH_EXPIRES_AT_KEY),\n this.storage.removeItem(USER_KEY),\n this.storage.removeItem(CHALLENGE_KEY),\n ]);\n this.broadcastStorage();\n }\n\n /**\n * Ensure only one refresh in flight.\n *\n * @param refreshFn - function performing refresh request\n */\n async refreshOnce(refreshFn: () => Promise<TokenResponse>): Promise<TokenResponse> {\n if (!this.refreshPromise) {\n this.refreshPromise = refreshFn()\n .then(async (tokens) => {\n await this.setTokens(tokens);\n return tokens;\n })\n .catch((error) => {\n throw error;\n })\n .finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n\n /**\n * Validate that a refresh token exists before attempting refresh.\n */\n async assertHasRefreshToken(): Promise<void> {\n const state = await this.getTokens();\n if (!state.refreshToken) {\n throw new NAuthClientError(NAuthErrorCode.AUTH_SESSION_NOT_FOUND, 'No refresh token available');\n }\n }\n\n /**\n * Broadcast a no-op write to trigger storage listeners in other tabs.\n */\n private broadcastStorage(): void {\n if (!this.isBrowser) return;\n try {\n window.localStorage.setItem('nauth_sync', Date.now().toString());\n } catch {\n // Best-effort; ignore if storage unavailable\n }\n }\n}\n","import { NAuthStorageAdapter } from './interface';\n\n/**\n * Browser storage adapter wrapping localStorage or sessionStorage.\n */\nexport class BrowserStorage implements NAuthStorageAdapter {\n private readonly storage: Storage;\n\n /**\n * Create a browser storage adapter.\n *\n * @param storage - Storage implementation (localStorage by default)\n */\n constructor(storage: Storage = window.localStorage) {\n this.storage = storage;\n }\n\n async getItem(key: string): Promise<string | null> {\n return this.storage.getItem(key);\n }\n\n async setItem(key: string, value: string): Promise<void> {\n this.storage.setItem(key, value);\n }\n\n async removeItem(key: string): Promise<void> {\n this.storage.removeItem(key);\n }\n}\n","import { NAuthStorageAdapter } from './interface';\n\n/**\n * In-memory storage adapter for SSR, tests, or environments without Web Storage.\n */\nexport class InMemoryStorage implements NAuthStorageAdapter {\n private readonly store = new Map<string, string>();\n\n async getItem(key: string): Promise<string | null> {\n return this.store.has(key) ? (this.store.get(key) as string) : null;\n }\n\n async setItem(key: string, value: string): Promise<void> {\n this.store.set(key, value);\n }\n\n async removeItem(key: string): Promise<void> {\n this.store.delete(key);\n }\n}\n","import type { AuthResponse } from '../types/auth.types';\nimport type { NAuthClientError } from './errors';\n\n/**\n * Authentication event types emitted by NAuthClient\n *\n * Events are emitted throughout the authentication lifecycle,\n * allowing applications to react to auth state changes.\n */\nexport type AuthEventType =\n | 'auth:login'\n | 'auth:signup'\n | 'auth:success'\n | 'auth:challenge'\n | 'auth:error'\n | 'auth:logout'\n | 'auth:refresh'\n | 'oauth:started'\n | 'oauth:callback'\n | 'oauth:completed'\n | 'oauth:error';\n\n/**\n * Discriminated union of all authentication events with type-safe payloads\n *\n * Each event has a specific payload type for better type safety.\n */\nexport type AuthEvent =\n | AuthLoginEvent\n | AuthSignupEvent\n | AuthSuccessEvent\n | AuthChallengeEvent\n | AuthErrorEvent\n | AuthLogoutEvent\n | AuthRefreshEvent\n | OAuthStartedEvent\n | OAuthCallbackEvent\n | OAuthCompletedEvent\n | OAuthErrorEvent;\n\n/**\n * Login initiated event\n */\nexport interface AuthLoginEvent {\n type: 'auth:login';\n data: {\n identifier: string;\n };\n timestamp: number;\n}\n\n/**\n * Signup initiated event\n */\nexport interface AuthSignupEvent {\n type: 'auth:signup';\n data: {\n email: string;\n };\n timestamp: number;\n}\n\n/**\n * Successful authentication event\n */\nexport interface AuthSuccessEvent {\n type: 'auth:success';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * Challenge required event\n */\nexport interface AuthChallengeEvent {\n type: 'auth:challenge';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * Authentication error event\n */\nexport interface AuthErrorEvent {\n type: 'auth:error';\n data: NAuthClientError;\n timestamp: number;\n}\n\n/**\n * User logged out event\n */\nexport interface AuthLogoutEvent {\n type: 'auth:logout';\n data: {\n forgetDevice?: boolean;\n global?: boolean;\n };\n timestamp: number;\n}\n\n/**\n * Token refreshed event\n */\nexport interface AuthRefreshEvent {\n type: 'auth:refresh';\n data: {\n success: boolean;\n };\n timestamp: number;\n}\n\n/**\n * OAuth flow started event\n */\nexport interface OAuthStartedEvent {\n type: 'oauth:started';\n data: {\n provider: string;\n };\n timestamp: number;\n}\n\n/**\n * OAuth callback received event\n */\nexport interface OAuthCallbackEvent {\n type: 'oauth:callback';\n data: {\n provider: string;\n };\n timestamp: number;\n}\n\n/**\n * OAuth flow completed event\n */\nexport interface OAuthCompletedEvent {\n type: 'oauth:completed';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * OAuth error event\n */\nexport interface OAuthErrorEvent {\n type: 'oauth:error';\n data: NAuthClientError;\n timestamp: number;\n}\n\n/**\n * Event listener callback function\n */\nexport type AuthEventListener = (event: AuthEvent) => void;\n\n/**\n * Internal event emitter for authentication events\n *\n * Provides pub/sub functionality for auth lifecycle events.\n *\n * @internal\n */\nexport class EventEmitter {\n private listeners = new Map<AuthEventType | '*', Set<AuthEventListener>>();\n\n /**\n * Subscribe to an authentication event\n *\n * @param event - Event type or '*' for all events\n * @param listener - Callback function\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = emitter.on('auth:success', (event) => {\n * console.log('User logged in:', event.data);\n * });\n *\n * // Later\n * unsubscribe();\n * ```\n */\n on(event: AuthEventType | '*', listener: AuthEventListener): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n\n // Return unsubscribe function\n return () => this.off(event, listener);\n }\n\n /**\n * Unsubscribe from an authentication event\n *\n * @param event - Event type or '*'\n * @param listener - Callback function to remove\n */\n off(event: AuthEventType | '*', listener: AuthEventListener): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n /**\n * Emit an authentication event\n *\n * Notifies all listeners for the specific event type and wildcard listeners.\n *\n * @param event - Event to emit\n * @internal\n */\n emit(event: AuthEvent): void {\n const specificListeners = this.listeners.get(event.type);\n const wildcardListeners = this.listeners.get('*');\n\n // Emit to specific event listeners\n specificListeners?.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n console.error(`Error in ${event.type} event listener:`, error);\n }\n });\n\n // Emit to wildcard listeners\n wildcardListeners?.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n console.error(`Error in wildcard event listener:`, error);\n }\n });\n }\n\n /**\n * Remove all listeners\n *\n * @internal\n */\n clear(): void {\n this.listeners.clear();\n }\n}\n","import { HttpAdapter, HttpRequest, HttpResponse } from '../core/http-adapter';\nimport { NAuthClientError } from '../core/errors';\nimport { NAuthErrorCode } from '../types/error.types';\n\n/**\n * HTTP adapter using native fetch API.\n *\n * Suitable for:\n * - Vanilla JavaScript/TypeScript\n * - Node.js (with fetch polyfill or Node 18+)\n * - Environments without framework-specific HTTP clients\n *\n * @example\n * ```typescript\n * import { NAuthClient } from '@nauth-toolkit/client';\n * import { FetchAdapter } from '@nauth-toolkit/client/adapters/fetch';\n *\n * const client = new NAuthClient({\n * baseUrl: 'https://api.example.com/auth',\n * httpAdapter: new FetchAdapter(),\n * });\n * ```\n */\nexport class FetchAdapter implements HttpAdapter {\n /**\n * Execute HTTP request using native fetch.\n *\n * @param config - Request configuration\n * @returns Response with parsed data\n * @throws NAuthClientError if request fails\n */\n async request<T>(config: HttpRequest): Promise<HttpResponse<T>> {\n const fetchOptions: RequestInit = {\n method: config.method,\n headers: config.headers,\n signal: config.signal,\n credentials: config.credentials,\n };\n\n if (config.body !== undefined) {\n fetchOptions.body = JSON.stringify(config.body);\n }\n\n let response: Response;\n try {\n response = await fetch(config.url, fetchOptions);\n } catch (error) {\n throw new NAuthClientError(NAuthErrorCode.INTERNAL_ERROR, 'Network request failed', {\n isNetworkError: true,\n details: { url: config.url, message: (error as Error).message },\n });\n }\n\n const status = response.status;\n let data: unknown = null;\n const text = await response.text();\n if (text) {\n try {\n data = JSON.parse(text);\n } catch {\n data = text;\n }\n }\n\n // Extract headers\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n if (!response.ok) {\n const errorData = typeof data === 'object' && data !== null ? (data as Record<string, unknown>) : {};\n const code =\n typeof errorData['code'] === 'string' ? (errorData.code as NAuthErrorCode) : NAuthErrorCode.INTERNAL_ERROR;\n const message =\n typeof errorData['message'] === 'string'\n ? (errorData.message as string)\n : `Request failed with status ${status}`;\n const timestamp = typeof errorData['timestamp'] === 'string' ? errorData.timestamp : undefined;\n const details = errorData['details'] as Record<string, unknown> | undefined;\n\n throw new NAuthClientError(code, message, {\n statusCode: status,\n timestamp,\n details,\n });\n }\n\n return { data: data as T, status, headers };\n }\n}\n\n\n\n","import { resolveConfig, ResolvedNAuthClientConfig } from './config';\nimport { TokenManager } from './refresh';\nimport { BrowserStorage } from '../storage/browser';\nimport { InMemoryStorage } from '../storage/memory';\nimport { EventEmitter, AuthEventType, AuthEventListener } from './events';\nimport { NAuthClientError } from './errors';\nimport { NAuthErrorCode } from '../types/error.types';\nimport { FetchAdapter } from '../adapters/fetch-adapter';\nimport {\n AuthChallenge,\n ChallengeResponse,\n GetChallengeDataRequest,\n GetSetupDataRequest,\n LoginRequest,\n LogoutAllRequest,\n AuthResponse,\n ResendCodeRequest,\n SignupRequest,\n TokenResponse,\n} from '../types/auth.types';\nimport { NAuthClientConfig } from '../types/config.types';\nimport { GetChallengeDataResponse, GetSetupDataResponse, MFAStatus } from '../types/mfa.types';\nimport {\n LinkedAccountsResponse,\n SocialAuthUrlRequest,\n SocialCallbackRequest,\n SocialVerifyRequest,\n SocialProvider,\n} from '../types/social.types';\nimport {\n AuthUser,\n ChangePasswordRequest,\n ConfirmForgotPasswordRequest,\n ConfirmForgotPasswordResponse,\n ForgotPasswordRequest,\n ForgotPasswordResponse,\n UpdateProfileRequest,\n} from '../types/user.types';\nimport { AuditHistoryResponse } from '../types/audit.types';\n\nconst USER_KEY = 'nauth_user';\nconst CHALLENGE_KEY = 'nauth_challenge_session';\nconst hasWindow = (): boolean =>\n typeof globalThis !== 'undefined' && typeof (globalThis as { window?: unknown }).window !== 'undefined';\n\n/**\n * Choose default storage implementation.\n */\nconst defaultStorage = () => {\n if (hasWindow() && typeof window.localStorage !== 'undefined') {\n return new BrowserStorage();\n }\n return new InMemoryStorage();\n};\n\n/**\n * Primary client for interacting with nauth-toolkit backend.\n */\nexport class NAuthClient {\n private readonly config: ResolvedNAuthClientConfig;\n private readonly tokenManager: TokenManager;\n private readonly eventEmitter: EventEmitter;\n private currentUser: AuthUser | null = null;\n\n /**\n * Create a new client instance.\n *\n * @param userConfig - Client configuration\n */\n constructor(userConfig: NAuthClientConfig) {\n const storage = userConfig.storage ?? defaultStorage();\n const defaultAdapter = userConfig.httpAdapter ?? new FetchAdapter();\n this.config = resolveConfig({ ...userConfig, storage }, defaultAdapter);\n this.tokenManager = new TokenManager(storage);\n this.eventEmitter = new EventEmitter();\n if (hasWindow()) {\n window.addEventListener('storage', this.handleStorageEvent);\n }\n }\n\n /**\n * Clean up resources.\n */\n dispose(): void {\n if (hasWindow()) {\n window.removeEventListener('storage', this.handleStorageEvent);\n }\n }\n\n /**\n * Login with identifier and password.\n */\n async login(identifier: string, password: string): Promise<AuthResponse> {\n const loginEvent = { type: 'auth:login' as const, data: { identifier }, timestamp: Date.now() };\n this.eventEmitter.emit(loginEvent);\n\n try {\n const body: LoginRequest = { identifier, password };\n const response = await this.post<AuthResponse>(this.config.endpoints.login, body);\n await this.handleAuthResponse(response);\n\n // Emit success or challenge event\n if (response.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: response, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: response, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return response;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(NAuthErrorCode.AUTH_INVALID_CREDENTIALS, (error as Error).message || 'Login failed');\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Signup with credentials.\n */\n async signup(payload: SignupRequest): Promise<AuthResponse> {\n this.eventEmitter.emit({ type: 'auth:signup', data: { email: payload.email }, timestamp: Date.now() });\n\n try {\n const response = await this.post<AuthResponse>(this.config.endpoints.signup, payload);\n await this.handleAuthResponse(response);\n\n // Emit success or challenge event\n if (response.challengeName) {\n this.eventEmitter.emit({ type: 'auth:challenge', data: response, timestamp: Date.now() });\n } else {\n this.eventEmitter.emit({ type: 'auth:success', data: response, timestamp: Date.now() });\n }\n\n return response;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(NAuthErrorCode.AUTH_INVALID_CREDENTIALS, (error as Error).message || 'Signup failed');\n this.eventEmitter.emit({ type: 'auth:error', data: authError, timestamp: Date.now() });\n throw authError;\n }\n }\n\n /**\n * Refresh tokens manually.\n */\n async refreshTokens(): Promise<TokenResponse> {\n const tokenDelivery = this.getTokenDeliveryMode();\n\n // Only check for refresh token in localStorage for JSON mode\n // In cookies mode, refresh token is in httpOnly cookie (backend manages it)\n if (tokenDelivery === 'json') {\n await this.tokenManager.assertHasRefreshToken();\n }\n\n const body =\n tokenDelivery === 'json'\n ? { refreshToken: (await this.tokenManager.getTokens()).refreshToken }\n : { refreshToken: '' };\n const refreshFn = async () => {\n // In cookies mode, refresh token is sent via httpOnly cookie (no access token needed, auth=false)\n // In JSON mode, refresh token is in body (no access token needed, auth=false)\n // Refresh endpoint is PUBLIC - it doesn't need an access token\n return this.post<TokenResponse>(this.config.endpoints.refresh, body, false);\n };\n const tokens = await this.tokenManager.refreshOnce(refreshFn);\n this.config.onTokenRefresh?.();\n this.eventEmitter.emit({ type: 'auth:refresh', data: { success: true }, timestamp: Date.now() });\n return tokens;\n }\n\n /**\n * Logout current session.\n *\n * Uses GET request to avoid CSRF token issues.\n *\n * @param forgetDevice - If true, also untrust the device (require MFA on next login)\n */\n async logout(forgetDevice?: boolean): Promise<void> {\n const queryParams = forgetDevice ? '?forgetMe=true' : '';\n try {\n await this.get(this.config.endpoints.logout + queryParams, true);\n } catch (error) {\n // Ignore logout errors (session might already be invalid)\n console.warn('[nauth] Logout request failed (session may already be invalid):', error);\n } finally {\n // Always clear local state even if request fails\n // Pass forgetDevice flag to clear device token in JSON mode\n await this.clearAuthState(forgetDevice);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevice, global: false },\n timestamp: Date.now(),\n });\n }\n }\n\n /**\n * Logout all sessions.\n *\n * Revokes all active sessions for the current user across all devices.\n * Optionally revokes all trusted devices if forgetDevices is true.\n *\n * @param forgetDevices - If true, also revokes all trusted devices (default: false)\n * @returns Number of sessions revoked\n */\n async logoutAll(forgetDevices?: boolean): Promise<{ revokedCount: number }> {\n try {\n const payload: LogoutAllRequest = {\n forgetDevices: forgetDevices ?? false,\n };\n const result = await this.post<{ message: string; revokedCount: number }>(\n this.config.endpoints.logoutAll,\n payload,\n true,\n );\n // Clear device token in JSON mode if forgetDevices is true\n await this.clearAuthState(forgetDevices);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevices, global: true },\n timestamp: Date.now(),\n });\n return { revokedCount: result.revokedCount };\n } catch (error) {\n // If request fails, still clear local state\n await this.clearAuthState(forgetDevices);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevices, global: true },\n timestamp: Date.now(),\n });\n throw error;\n }\n }\n\n /**\n * Respond to a challenge.\n *\n * Validates challenge response data before sending to backend.\n * Provides helpful error messages for common validation issues.\n *\n * @param response - Challenge response data\n * @returns Auth response from backend\n * @throws {NAuthClientError} If validation fails\n */\n async respondToChallenge(response: ChallengeResponse): Promise<AuthResponse> {\n // Validate TOTP setup requires both secret and code\n if (response.type === AuthChallenge.MFA_SETUP_REQUIRED && response.method === 'totp') {\n const setupData = response.setupData;\n if (!setupData || typeof setupData !== 'object') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires setupData with both secret and code',\n { details: { field: 'setupData' } },\n );\n }\n\n const secret = setupData['secret'];\n const code = setupData['code'];\n\n if (!secret || typeof secret !== 'string') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires secret in setupData. Make sure to include the secret from getSetupData() response.',\n { details: { field: 'secret' } },\n );\n }\n\n if (!code || typeof code !== 'string') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires code in setupData. Please enter the verification code from your authenticator app.',\n { details: { field: 'code' } },\n );\n }\n }\n\n try {\n const result = await this.post<AuthResponse>(this.config.endpoints.respondChallenge, response);\n await this.handleAuthResponse(result);\n\n // Emit success or challenge event\n if (result.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return result;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(\n NAuthErrorCode.CHALLENGE_INVALID,\n (error as Error).message || 'Challenge response failed',\n );\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Resend a challenge code.\n */\n async resendCode(session: string): Promise<{ destination: string }> {\n const payload: ResendCodeRequest = { session };\n return this.post<{ destination: string }>(this.config.endpoints.resendCode, payload);\n }\n\n /**\n * Get setup data for MFA.\n *\n * Returns method-specific setup information:\n * - TOTP: { secret, qrCode, manualEntryKey }\n * - SMS: { maskedPhone }\n * - Email: { maskedEmail }\n * - Passkey: WebAuthn registration options\n *\n * @param session - Challenge session token\n * @param method - MFA method to set up\n * @returns Setup data wrapped in GetSetupDataResponse\n */\n async getSetupData(session: string, method: GetSetupDataRequest['method']): Promise<GetSetupDataResponse> {\n const payload: GetSetupDataRequest = { session, method };\n return this.post<GetSetupDataResponse>(this.config.endpoints.getSetupData, payload);\n }\n\n /**\n * Get challenge data (e.g., WebAuthn options).\n *\n * Returns challenge-specific data for verification flows.\n *\n * @param session - Challenge session token\n * @param method - Challenge method to get data for\n * @returns Challenge data wrapped in GetChallengeDataResponse\n */\n async getChallengeData(\n session: string,\n method: GetChallengeDataRequest['method'],\n ): Promise<GetChallengeDataResponse> {\n const payload: GetChallengeDataRequest = { session, method };\n return this.post<GetChallengeDataResponse>(this.config.endpoints.getChallengeData, payload);\n }\n\n /**\n * Get current user profile.\n */\n async getProfile(): Promise<AuthUser> {\n const profile = await this.get<AuthUser>(this.config.endpoints.profile, true);\n await this.setUser(profile);\n return profile;\n }\n\n /**\n * Update user profile.\n */\n async updateProfile(updates: UpdateProfileRequest): Promise<AuthUser> {\n const updated = await this.put<AuthUser>(this.config.endpoints.updateProfile, updates, true);\n await this.setUser(updated);\n return updated;\n }\n\n /**\n * Change user password.\n */\n async changePassword(oldPassword: string, newPassword: string): Promise<void> {\n const payload: ChangePasswordRequest = { currentPassword: oldPassword, newPassword };\n await this.post(this.config.endpoints.changePassword, payload, true);\n }\n\n /**\n * Request a password reset code (forgot password).\n */\n async forgotPassword(identifier: string): Promise<ForgotPasswordResponse> {\n const payload: ForgotPasswordRequest = { identifier };\n return this.post<ForgotPasswordResponse>(this.config.endpoints.forgotPassword, payload);\n }\n\n /**\n * Confirm a password reset code and set a new password.\n */\n async confirmForgotPassword(\n identifier: string,\n code: string,\n newPassword: string,\n ): Promise<ConfirmForgotPasswordResponse> {\n const payload: ConfirmForgotPasswordRequest = { identifier, code, newPassword };\n return this.post<ConfirmForgotPasswordResponse>(this.config.endpoints.confirmForgotPassword, payload);\n }\n\n /**\n * Request password change (must change on next login).\n */\n async requestPasswordChange(): Promise<void> {\n await this.post(this.config.endpoints.requestPasswordChange, {}, true);\n }\n\n /**\n * Get MFA status.\n */\n async getMfaStatus(): Promise<MFAStatus> {\n return this.get<MFAStatus>(this.config.endpoints.mfaStatus, true);\n }\n\n /**\n * Get MFA devices.\n */\n async getMfaDevices(): Promise<unknown[]> {\n return this.get<unknown[]>(this.config.endpoints.mfaDevices, true);\n }\n\n /**\n * Setup MFA device (authenticated user).\n */\n async setupMfaDevice(method: string): Promise<unknown> {\n return this.post<unknown>(this.config.endpoints.mfaSetupData, { method }, true);\n }\n\n /**\n * Verify MFA setup (authenticated user).\n */\n async verifyMfaSetup(\n method: string,\n setupData: Record<string, unknown>,\n deviceName?: string,\n ): Promise<{ deviceId: number }> {\n return this.post<{ deviceId: number }>(\n this.config.endpoints.mfaVerifySetup,\n { method, setupData, deviceName },\n true,\n );\n }\n\n /**\n * Remove MFA method.\n */\n async removeMfaDevice(method: string): Promise<{ message: string }> {\n const path = `${this.config.endpoints.mfaRemove}/${method}`;\n return this.delete<{ message: string }>(path, true);\n }\n\n /**\n * Set preferred MFA method.\n *\n * @param method - Device method to set as preferred ('totp', 'sms', 'email', or 'passkey'). Cannot be 'backup'.\n * @returns Success message\n */\n async setPreferredMfaMethod(method: 'totp' | 'sms' | 'email' | 'passkey'): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.mfaPreferred, { method }, true);\n }\n\n /**\n * Generate backup codes.\n */\n async generateBackupCodes(): Promise<string[]> {\n const result = await this.post<{ codes: string[] }>(this.config.endpoints.mfaBackupCodes, {}, true);\n return result.codes;\n }\n\n /**\n * Set MFA exemption (admin/test scenarios).\n */\n async setMfaExemption(exempt: boolean, reason?: string): Promise<void> {\n await this.post(this.config.endpoints.mfaExemption, { exempt, reason }, true);\n }\n\n // ============================================================================\n // Event System\n // ============================================================================\n\n /**\n * Subscribe to authentication events.\n *\n * Emits events throughout the auth lifecycle for custom logic, analytics, or UI updates.\n *\n * @param event - Event type to listen for, or '*' for all events\n * @param listener - Callback function to handle the event\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * // Listen to successful authentication\n * const unsubscribe = client.on('auth:success', (event) => {\n * console.log('User logged in:', event.data.user);\n * analytics.track('login_success');\n * });\n *\n * // Listen to all events\n * client.on('*', (event) => {\n * console.log('Auth event:', event.type, event.data);\n * });\n *\n * // Unsubscribe when done\n * unsubscribe();\n * ```\n */\n on(event: AuthEventType | '*', listener: AuthEventListener): () => void {\n return this.eventEmitter.on(event, listener);\n }\n\n /**\n * Unsubscribe from authentication events.\n *\n * @param event - Event type\n * @param listener - Callback function to remove\n */\n off(event: AuthEventType | '*', listener: AuthEventListener): void {\n this.eventEmitter.off(event, listener);\n }\n\n // ============================================================================\n // Social Authentication\n // ============================================================================\n\n /**\n * Start social OAuth flow with automatic state management.\n *\n * Generates a secure state token, stores OAuth context, and redirects to the OAuth provider.\n * After OAuth callback, use `handleOAuthCallback()` to complete authentication.\n *\n * @param provider - OAuth provider ('google', 'apple', 'facebook')\n * @param options - Optional configuration\n *\n * @example\n * ```typescript\n * // Simple usage\n * await client.loginWithSocial('google');\n *\n * // With custom redirect URI\n * await client.loginWithSocial('apple', {\n * redirectUri: 'https://example.com/auth/callback'\n * });\n * ```\n */\n async loginWithSocial(provider: SocialProvider, _options?: { redirectUri?: string }): Promise<void> {\n // Emit event\n this.eventEmitter.emit({ type: 'oauth:started', data: { provider }, timestamp: Date.now() });\n\n // Get OAuth URL from backend (backend will generate and store state)\n // Don't send state - backend handles it\n const { url } = await this.getSocialAuthUrl({ provider });\n\n // Redirect to OAuth provider (via backend)\n if (hasWindow()) {\n window.location.href = url;\n }\n }\n\n /**\n * Auto-detect and handle OAuth callback.\n *\n * Call this on app initialization or in callback route.\n * Returns null if not an OAuth callback (no provider/code params).\n *\n * The SDK validates the state token, completes authentication via backend,\n * and emits appropriate events.\n *\n * @param urlOrParams - Optional URL string or URLSearchParams (auto-detects from window.location if not provided)\n * @returns AuthResponse if OAuth callback detected, null otherwise\n *\n * @example\n * ```typescript\n * // Auto-detect on app init\n * const response = await client.handleOAuthCallback();\n * if (response) {\n * if (response.challengeName) {\n * router.navigate(['/challenge', response.challengeName]);\n * } else {\n * router.navigate(['/']); // Navigate to your app's home route\n * }\n * }\n *\n * // In callback route\n * const response = await client.handleOAuthCallback(window.location.search);\n * ```\n */\n async handleOAuthCallback(urlOrParams?: string | URLSearchParams): Promise<AuthResponse | null> {\n // Parse URL params\n let params: URLSearchParams;\n if (urlOrParams instanceof URLSearchParams) {\n params = urlOrParams;\n } else if (typeof urlOrParams === 'string') {\n params = new URLSearchParams(urlOrParams);\n } else if (hasWindow()) {\n params = new URLSearchParams(window.location.search);\n } else {\n return null;\n }\n\n // Check if this is an OAuth callback\n const provider = params.get('provider') as SocialProvider | null;\n const code = params.get('code');\n const state = params.get('state');\n const error = params.get('error');\n\n if (!provider || (!code && !error)) {\n return null; // Not an OAuth callback\n }\n\n this.eventEmitter.emit({ type: 'oauth:callback', data: { provider }, timestamp: Date.now() });\n\n try {\n // Handle OAuth error\n if (error) {\n const authError = new NAuthClientError(\n NAuthErrorCode.SOCIAL_TOKEN_INVALID,\n params.get('error_description') || error,\n { details: { error, provider } },\n );\n this.eventEmitter.emit({ type: 'oauth:error', data: authError, timestamp: Date.now() });\n throw authError;\n }\n\n if (!state) {\n throw new NAuthClientError(NAuthErrorCode.CHALLENGE_INVALID, 'Missing OAuth state parameter');\n }\n\n // Complete OAuth flow via backend\n // Backend validates state - don't validate on frontend\n const response = await this.handleSocialCallback({\n provider,\n code: code!,\n state,\n });\n\n // Emit appropriate event\n if (response.challengeName) {\n this.eventEmitter.emit({ type: 'auth:challenge', data: response, timestamp: Date.now() });\n } else {\n this.eventEmitter.emit({ type: 'auth:success', data: response, timestamp: Date.now() });\n }\n\n this.eventEmitter.emit({ type: 'oauth:completed', data: response, timestamp: Date.now() });\n\n return response;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(\n NAuthErrorCode.SOCIAL_TOKEN_INVALID,\n (error as Error).message || 'OAuth callback failed',\n );\n\n this.eventEmitter.emit({ type: 'oauth:error', data: authError, timestamp: Date.now() });\n throw authError;\n }\n }\n\n /**\n * Get social auth URL (low-level API).\n *\n * For most cases, use `loginWithSocial()` which handles state management automatically.\n */\n async getSocialAuthUrl(request: SocialAuthUrlRequest): Promise<{ url: string }> {\n return this.post(this.config.endpoints.socialAuthUrl, request);\n }\n\n /**\n * Handle social callback.\n */\n async handleSocialCallback(request: SocialCallbackRequest): Promise<AuthResponse> {\n const result = await this.post<AuthResponse>(this.config.endpoints.socialCallback, request);\n await this.handleAuthResponse(result);\n return result;\n }\n\n /**\n * Verify native social token (mobile).\n */\n async verifyNativeSocial(request: SocialVerifyRequest): Promise<AuthResponse> {\n try {\n const path = this.config.endpoints.socialVerify.replace(':provider', request.provider);\n const result = await this.post<AuthResponse>(path, request);\n await this.handleAuthResponse(result);\n\n // Emit success or challenge event\n if (result.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return result;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(\n NAuthErrorCode.SOCIAL_TOKEN_INVALID,\n (error as Error).message || 'Social verification failed',\n );\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Get linked accounts.\n */\n async getLinkedAccounts(): Promise<LinkedAccountsResponse> {\n return this.get<LinkedAccountsResponse>(this.config.endpoints.socialLinked, true);\n }\n\n /**\n * Link social account.\n */\n async linkSocialAccount(provider: string, code: string, state: string): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.socialLink, { provider, code, state }, true);\n }\n\n /**\n * Unlink social account.\n */\n async unlinkSocialAccount(provider: string): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.socialUnlink, { provider }, true);\n }\n\n /**\n * Trust current device.\n */\n async trustDevice(): Promise<{ deviceToken: string }> {\n const result = await this.post<{ deviceToken: string }>(this.config.endpoints.trustDevice, {}, true);\n await this.setDeviceToken(result.deviceToken);\n return result;\n }\n\n /**\n * Check if the current device is trusted.\n *\n * Returns whether the current device is trusted based on the device token\n * (from cookie in cookies mode, or header in JSON mode).\n *\n * This performs a server-side validation of the device token and checks:\n * - Device token exists and is valid\n * - Device token matches a trusted device record in the database\n * - Trust has not expired\n *\n * @returns Object with trusted status\n *\n * @example\n * ```typescript\n * const result = await client.isTrustedDevice();\n * if (result.trusted) {\n * console.log('This device is trusted');\n * }\n * ```\n */\n async isTrustedDevice(): Promise<{ trusted: boolean }> {\n return this.get<{ trusted: boolean }>(this.config.endpoints.isTrustedDevice, true);\n }\n\n /**\n * Get paginated audit history for the current user.\n *\n * Returns authentication and security events with full audit details including:\n * - Event type (login, logout, MFA, etc.)\n * - Event status (success, failure, suspicious)\n * - Device information, location, risk factors\n *\n * @param params - Query parameters for filtering and pagination\n * @returns Paginated audit history response\n *\n * @example\n * ```typescript\n * const history = await client.getAuditHistory({\n * page: 1,\n * limit: 20,\n * eventType: 'LOGIN_SUCCESS'\n * });\n * ```\n */\n async getAuditHistory(params?: Record<string, string | number | boolean>): Promise<AuditHistoryResponse> {\n const entries: [string, string][] = Object.entries(params ?? {}).map(([k, v]) => [k, String(v)]);\n const query = entries.length > 0 ? `?${new URLSearchParams(entries).toString()}` : '';\n const path = `${this.config.endpoints.auditHistory}${query}`;\n return this.get<AuditHistoryResponse>(path, true);\n }\n\n /**\n * Initialize client by hydrating state from storage.\n * Call this on app startup to restore auth state.\n */\n async initialize(): Promise<void> {\n const userJson = await this.config.storage.getItem(USER_KEY);\n if (userJson) {\n try {\n this.currentUser = JSON.parse(userJson) as AuthUser;\n this.config.onAuthStateChange?.(this.currentUser);\n } catch {\n // Invalid stored user - clear it\n await this.config.storage.removeItem(USER_KEY);\n }\n }\n }\n\n /**\n * Determine if user is authenticated (async - checks tokens).\n */\n async isAuthenticated(): Promise<boolean> {\n const tokens = await this.tokenManager.getTokens();\n return Boolean(tokens.accessToken);\n }\n\n /**\n * Determine if user is authenticated (sync - checks cached user).\n * Use this for guards and sync checks. Use `isAuthenticated()` for definitive check.\n */\n isAuthenticatedSync(): boolean {\n return this.currentUser !== null;\n }\n\n /**\n * Get current access token (may be null).\n */\n async getAccessToken(): Promise<string | null> {\n const tokens = await this.tokenManager.getTokens();\n return tokens.accessToken ?? null;\n }\n\n /**\n * Get current user (cached, sync).\n */\n getCurrentUser(): AuthUser | null {\n return this.currentUser;\n }\n\n /**\n * Get stored challenge session (for resuming challenge flows).\n */\n async getStoredChallenge(): Promise<AuthResponse | null> {\n const raw = await this.config.storage.getItem(CHALLENGE_KEY);\n if (!raw) return null;\n try {\n return JSON.parse(raw) as AuthResponse;\n } catch {\n return null;\n }\n }\n\n /**\n * Clear stored challenge session.\n */\n async clearStoredChallenge(): Promise<void> {\n await this.config.storage.removeItem(CHALLENGE_KEY);\n }\n\n /**\n * Internal: handle auth response (tokens or challenge).\n *\n * In cookies mode: Tokens are set as httpOnly cookies by backend, not stored in client storage.\n * In JSON mode: Tokens are stored in tokenManager for Authorization header.\n */\n private async handleAuthResponse(response: AuthResponse): Promise<void> {\n if (response.challengeName) {\n await this.persistChallenge(response);\n return;\n }\n\n // Only store tokens in JSON mode (cookies mode uses httpOnly cookies set by backend)\n if (this.config.tokenDelivery === 'json' && response.accessToken && response.refreshToken) {\n await this.tokenManager.setTokens({\n accessToken: response.accessToken,\n refreshToken: response.refreshToken,\n accessTokenExpiresAt: response.accessTokenExpiresAt ?? 0,\n refreshTokenExpiresAt: response.refreshTokenExpiresAt ?? 0,\n });\n }\n\n // Device token handling (only for JSON mode - cookies mode uses httpOnly cookie)\n if (this.config.tokenDelivery === 'json' && response.deviceToken) {\n await this.setDeviceToken(response.deviceToken);\n }\n\n // Always store user info (needed for both modes)\n if (response.user) {\n await this.setUser(response.user as AuthUser);\n }\n\n await this.clearChallenge();\n }\n\n /**\n * Persist challenge state.\n */\n private async persistChallenge(challenge: AuthResponse): Promise<void> {\n await this.config.storage.setItem(CHALLENGE_KEY, JSON.stringify(challenge));\n }\n\n /**\n * Clear challenge state.\n */\n private async clearChallenge(): Promise<void> {\n await this.config.storage.removeItem(CHALLENGE_KEY);\n }\n\n /**\n * Persist user.\n */\n private async setUser(user: AuthUser): Promise<void> {\n this.currentUser = user;\n await this.config.storage.setItem(USER_KEY, JSON.stringify(user));\n this.config.onAuthStateChange?.(user);\n }\n\n /**\n * Clear all auth state.\n *\n * @param forgetDevice - If true, also clear device token (for JSON mode)\n */\n private async clearAuthState(forgetDevice?: boolean): Promise<void> {\n this.currentUser = null;\n await this.tokenManager.clearTokens();\n await this.config.storage.removeItem(USER_KEY);\n\n // Clear device token in JSON mode (cookies mode uses httpOnly cookie cleared by backend)\n if (forgetDevice && this.config.tokenDelivery === 'json') {\n await this.config.storage.removeItem(this.config.deviceTrust.storageKey);\n }\n\n this.config.onAuthStateChange?.(null);\n }\n\n /**\n * Persist device token (json mode mobile).\n */\n private async setDeviceToken(token: string): Promise<void> {\n await this.config.storage.setItem(this.config.deviceTrust.storageKey, token);\n }\n\n /**\n * Determine token delivery mode for this environment.\n */\n private getTokenDeliveryMode(): 'json' | 'cookies' {\n return this.config.tokenDelivery;\n }\n\n /**\n * Build request URL by combining baseUrl with path.\n * @private\n */\n private buildUrl(path: string): string {\n return `${this.config.baseUrl}${path}`;\n }\n\n /**\n * Build request headers for authentication.\n * @private\n */\n private async buildHeaders(auth: boolean): Promise<Record<string, string>> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n };\n\n // Add access token in JSON mode\n if (auth && this.config.tokenDelivery === 'json') {\n const accessToken = (await this.tokenManager.getTokens()).accessToken;\n if (accessToken) {\n headers['Authorization'] = `Bearer ${accessToken}`;\n }\n }\n\n // Add CSRF token for mutating requests in cookies mode\n if (this.config.tokenDelivery === 'cookies' && hasWindow()) {\n const csrfToken = this.getCsrfToken();\n if (csrfToken) {\n headers[this.config.csrf.headerName] = csrfToken;\n }\n }\n\n return headers;\n }\n\n /**\n * Get CSRF token from cookie (browser only).\n * @private\n */\n private getCsrfToken(): string | null {\n if (!hasWindow() || typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(^| )${this.config.csrf.cookieName}=([^;]+)`));\n return match ? decodeURIComponent(match[2]) : null;\n }\n\n /**\n * Execute GET request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async get<T>(path: string, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'GET',\n url,\n headers,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute POST request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async post<T>(path: string, body: unknown, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'POST',\n url,\n headers,\n body,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute PUT request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async put<T>(path: string, body: unknown, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'PUT',\n url,\n headers,\n body,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute DELETE request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async delete<T>(path: string, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'DELETE',\n url,\n headers,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Handle cross-tab storage updates.\n */\n private readonly handleStorageEvent = (event: StorageEvent): void => {\n if (event.key === 'nauth_sync') {\n // Best-effort reload of user state\n this.config.storage\n .getItem(USER_KEY)\n .then((value: string | null) => (value ? (JSON.parse(value) as AuthUser) : null))\n .then((user: AuthUser | null) => {\n this.currentUser = user;\n this.config.onAuthStateChange?.(user);\n })\n .catch(() => {\n // ignore\n });\n }\n };\n}\n","import { inject, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { HttpHandlerFn, HttpInterceptorFn, HttpRequest, HttpClient, HttpErrorResponse } from '@angular/common/http';\nimport { Router } from '@angular/router';\nimport { catchError, switchMap, throwError, filter, take, BehaviorSubject, from } from 'rxjs';\nimport { NAUTH_CLIENT_CONFIG } from './tokens';\nimport { AuthService } from './auth.service';\n\n/**\n * Refresh state management.\n * BehaviorSubject pattern is the industry-standard for token refresh.\n */\nlet isRefreshing = false;\nconst refreshTokenSubject = new BehaviorSubject<string | null>(null);\n\n/**\n * Track retried requests to prevent infinite loops.\n */\nconst retriedRequests = new WeakSet<HttpRequest<unknown>>();\n\n/**\n * Get CSRF token from cookie.\n */\nfunction getCsrfToken(cookieName: string): string | null {\n if (typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(^| )${cookieName}=([^;]+)`));\n return match ? decodeURIComponent(match[2]) : null;\n}\n\n/**\n * Angular HTTP interceptor for nauth-toolkit.\n *\n * Handles:\n * - Cookies mode: withCredentials + CSRF tokens + refresh via POST\n * - JSON mode: refresh via SDK, retry with new token\n */\nexport const authInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => {\n const config = inject(NAUTH_CLIENT_CONFIG);\n const http = inject(HttpClient);\n const authService = inject(AuthService);\n const platformId = inject(PLATFORM_ID);\n const router = inject(Router);\n const isBrowser = isPlatformBrowser(platformId);\n\n if (!isBrowser) {\n return next(req);\n }\n\n const tokenDelivery = config.tokenDelivery;\n const baseUrl = config.baseUrl;\n const endpoints = config.endpoints ?? {};\n const refreshPath = endpoints.refresh ?? '/refresh';\n const loginPath = endpoints.login ?? '/login';\n const signupPath = endpoints.signup ?? '/signup';\n const socialAuthUrlPath = endpoints.socialAuthUrl ?? '/social/auth-url';\n const socialCallbackPath = endpoints.socialCallback ?? '/social/callback';\n const refreshUrl = `${baseUrl}${refreshPath}`;\n\n const isAuthApiRequest = req.url.includes(baseUrl);\n const isRefreshEndpoint = req.url.includes(refreshPath);\n const isPublicEndpoint =\n req.url.includes(loginPath) ||\n req.url.includes(signupPath) ||\n req.url.includes(socialAuthUrlPath) ||\n req.url.includes(socialCallbackPath);\n\n // Build request with credentials (cookies mode only)\n let authReq = req;\n if (tokenDelivery === 'cookies') {\n authReq = authReq.clone({ withCredentials: true });\n\n if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {\n const csrfCookieName = config.csrf?.cookieName ?? 'nauth_csrf_token';\n const csrfHeaderName = config.csrf?.headerName ?? 'x-csrf-token';\n const csrfToken = getCsrfToken(csrfCookieName);\n if (csrfToken) {\n authReq = authReq.clone({ setHeaders: { [csrfHeaderName]: csrfToken } });\n }\n }\n }\n\n return next(authReq).pipe(\n catchError((error: unknown) => {\n const shouldHandle =\n error instanceof HttpErrorResponse &&\n error.status === 401 &&\n isAuthApiRequest &&\n !isRefreshEndpoint &&\n !isPublicEndpoint &&\n !retriedRequests.has(req);\n\n if (!shouldHandle) {\n return throwError(() => error);\n }\n\n if (config.debug) {\n console.warn('[nauth-interceptor] 401 detected:', req.url);\n }\n\n if (!isRefreshing) {\n isRefreshing = true;\n refreshTokenSubject.next(null);\n\n if (config.debug) {\n console.warn('[nauth-interceptor] Starting refresh...');\n }\n\n // Refresh based on mode\n const refresh$ =\n tokenDelivery === 'cookies'\n ? http.post<{ accessToken?: string }>(refreshUrl, {}, { withCredentials: true })\n : from(authService.getClient().refreshTokens());\n\n return refresh$.pipe(\n switchMap((response) => {\n if (config.debug) {\n console.warn('[nauth-interceptor] Refresh successful');\n }\n isRefreshing = false;\n\n // Get new token (JSON mode) or signal success (cookies mode)\n const newToken = 'accessToken' in response ? response.accessToken : 'success';\n refreshTokenSubject.next(newToken ?? 'success');\n\n // Build retry request\n const retryReq = buildRetryRequest(authReq, tokenDelivery, newToken);\n retriedRequests.add(retryReq);\n\n if (config.debug) {\n console.warn('[nauth-interceptor] Retrying:', req.url);\n }\n return next(retryReq);\n }),\n catchError((err) => {\n if (config.debug) {\n console.error('[nauth-interceptor] Refresh failed:', err);\n }\n isRefreshing = false;\n refreshTokenSubject.next(null);\n\n // Handle session expiration - redirect to configured URL\n if (config.redirects?.sessionExpired) {\n router.navigateByUrl(config.redirects.sessionExpired).catch((navError) => {\n if (config.debug) {\n console.error('[nauth-interceptor] Navigation failed:', navError);\n }\n });\n }\n\n return throwError(() => err);\n }),\n );\n } else {\n // Wait for ongoing refresh\n if (config.debug) {\n console.warn('[nauth-interceptor] Waiting for refresh...');\n }\n return refreshTokenSubject.pipe(\n filter((token): token is string => token !== null),\n take(1),\n switchMap((token) => {\n if (config.debug) {\n console.warn('[nauth-interceptor] Refresh done, retrying:', req.url);\n }\n const retryReq = buildRetryRequest(authReq, tokenDelivery, token);\n retriedRequests.add(retryReq);\n return next(retryReq);\n }),\n );\n }\n }),\n );\n};\n\n/**\n * Build retry request with appropriate auth.\n */\nfunction buildRetryRequest(\n originalReq: HttpRequest<unknown>,\n tokenDelivery: string,\n newToken?: string,\n): HttpRequest<unknown> {\n if (tokenDelivery === 'json' && newToken && newToken !== 'success') {\n return originalReq.clone({\n setHeaders: { Authorization: `Bearer ${newToken}` },\n });\n }\n return originalReq.clone();\n}\n\n/**\n * Class-based interceptor for NgModule compatibility.\n */\nexport class AuthInterceptor {\n intercept(req: HttpRequest<unknown>, next: HttpHandlerFn) {\n return authInterceptor(req, next);\n }\n}\n","import { inject } from '@angular/core';\nimport { CanActivateFn, Router, UrlTree } from '@angular/router';\nimport { AuthService } from './auth.service';\n\n/**\n * Functional route guard for authentication (Angular 17+).\n *\n * Protects routes by checking if user is authenticated.\n * Redirects to login page if not authenticated.\n *\n * @param redirectTo - Path to redirect to if not authenticated (default: '/login')\n * @returns CanActivateFn guard function\n *\n * @example\n * ```typescript\n * // In route configuration\n * const routes: Routes = [\n * {\n * path: 'home',\n * component: HomeComponent,\n * canActivate: [authGuard()]\n * },\n * {\n * path: 'admin',\n * component: AdminComponent,\n * canActivate: [authGuard('/admin/login')]\n * }\n * ];\n * ```\n */\nexport function authGuard(redirectTo = '/login'): CanActivateFn {\n return (): boolean | UrlTree => {\n const auth = inject(AuthService);\n const router = inject(Router);\n\n if (auth.isAuthenticated()) {\n return true;\n }\n\n return router.createUrlTree([redirectTo]);\n };\n}\n\n/**\n * Class-based authentication guard for NgModule compatibility.\n *\n * @example\n * ```typescript\n * // In route configuration (NgModule)\n * const routes: Routes = [\n * {\n * path: 'home',\n * component: HomeComponent,\n * canActivate: [AuthGuard]\n * }\n * ];\n *\n * // In module providers\n * @NgModule({\n * providers: [AuthGuard]\n * })\n * ```\n */\nexport class AuthGuard {\n /**\n * @param auth - Authentication service\n * @param router - Angular router\n */\n constructor(\n private auth: AuthService,\n private router: Router,\n ) {}\n\n /**\n * Check if route can be activated.\n *\n * @returns True if authenticated, otherwise redirects to login\n */\n canActivate(): boolean | UrlTree {\n if (this.auth.isAuthenticated()) {\n return true;\n }\n\n return this.router.createUrlTree(['/login']);\n }\n}\n","import { inject, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { type CanActivateFn } from '@angular/router';\nimport { AuthService } from './auth.service';\nimport { NAUTH_CLIENT_CONFIG } from './tokens';\n\n/**\n * OAuth callback route guard.\n *\n * Drop-in guard that automatically processes OAuth callbacks and redirects appropriately.\n * Place this guard on your `/auth/callback` route to handle social authentication.\n *\n * The guard:\n * - Auto-detects OAuth callback parameters (provider, code, state)\n * - Completes authentication via backend\n * - Redirects using window.location (works in browser, Capacitor, SSR-safe)\n *\n * Configure redirect URLs in `NAUTH_CLIENT_CONFIG.redirects`.\n *\n * @example\n * ```typescript\n * // app.routes.ts\n * import { oauthCallbackGuard } from '@nauth-toolkit/client/angular';\n *\n * export const routes: Routes = [\n * {\n * path: 'auth/callback',\n * canActivate: [oauthCallbackGuard],\n * redirectTo: '/', // Fallback - guard handles redirect\n * },\n * ];\n * ```\n *\n * @example\n * ```typescript\n * // app.config.ts - Configure redirect URLs\n * import { NAUTH_CLIENT_CONFIG } from '@nauth-toolkit/client/angular';\n *\n * providers: [\n * {\n * provide: NAUTH_CLIENT_CONFIG,\n * useValue: {\n * baseUrl: 'https://api.example.com/auth',\n * tokenDelivery: 'cookies',\n * redirects: {\n * success: '/home', // Common redirect for all successful auth\n * oauthError: '/login',\n * challengeBase: '/auth/challenge',\n * },\n * },\n * }\n * ]\n * ```\n */\nexport const oauthCallbackGuard: CanActivateFn = async (): Promise<boolean> => {\n const auth = inject(AuthService);\n const config = inject(NAUTH_CLIENT_CONFIG);\n const platformId = inject(PLATFORM_ID);\n const isBrowser = isPlatformBrowser(platformId);\n\n // SSR: Don't process in server environment\n if (!isBrowser) {\n return false;\n }\n\n try {\n // Auto-detect and handle OAuth callback\n const response = await auth.getClient().handleOAuthCallback();\n\n if (!response) {\n // Not an OAuth callback - redirect to home\n const homeUrl = config.redirects?.success || '/';\n window.location.replace(homeUrl);\n return false;\n }\n\n // Handle successful response\n if (response.challengeName) {\n // Challenge required\n const challengeBase = config.redirects?.challengeBase || '/auth/challenge';\n const challengeRoute = response.challengeName.toLowerCase().replace(/_/g, '-');\n const challengePath = `${challengeBase}/${challengeRoute}`;\n if (config.debug) {\n console.warn('[oauth-callback-guard] Redirecting to challenge:', challengePath);\n }\n window.location.replace(challengePath);\n } else {\n // Authentication complete\n const successUrl = config.redirects?.success || '/';\n if (config.debug) {\n console.warn('[oauth-callback-guard] Redirecting to success URL:', successUrl);\n }\n window.location.replace(successUrl);\n }\n } catch (error) {\n // OAuth callback failed\n console.error('[oauth-callback-guard] OAuth callback failed:', error);\n const errorUrl = config.redirects?.oauthError || '/login';\n if (config.debug) {\n console.warn('[oauth-callback-guard] Redirecting to error URL:', errorUrl);\n }\n window.location.replace(errorUrl);\n }\n\n // Return false to prevent route activation (we're navigating manually)\n return false;\n};\n","import { ModuleWithProviders, NgModule } from '@angular/core';\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\nimport { NAUTH_CLIENT_CONFIG } from './tokens';\nimport { AuthInterceptor } from './auth.interceptor';\nimport { NAuthClientConfig } from '../types/config.types';\n\n/**\n * NgModule wrapper to provide configuration and interceptor.\n */\n@NgModule({})\nexport class NAuthModule {\n /**\n * Configure the module with client settings.\n *\n * @param config - Client configuration\n */\n static forRoot(config: NAuthClientConfig): ModuleWithProviders<NAuthModule> {\n return {\n ngModule: NAuthModule,\n providers: [\n { provide: NAUTH_CLIENT_CONFIG, useValue: config },\n { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },\n ],\n };\n }\n}\n"],"mappings":"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","names":["import_core","import_rxjs","import_core","USER_KEY","CHALLENGE_KEY","error","import_core","import_http","import_rxjs","import_core","import_router","import_core","import_common","import_core","import_http"]}
1
+ {"version":3,"sources":["../../src/angular/index.ts","../../src/angular/tokens.ts","../../src/angular/auth.service.ts","../../src/angular/http-adapter.ts","../../src/core/errors.ts","../../src/core/config.ts","../../src/core/refresh.ts","../../src/storage/browser.ts","../../src/storage/memory.ts","../../src/core/events.ts","../../src/adapters/fetch-adapter.ts","../../src/core/client.ts","../../src/angular/auth.interceptor.ts","../../src/angular/auth.guard.ts","../../src/angular/social-redirect-callback.guard.ts","../../src/angular/auth.module.ts"],"sourcesContent":["export * from './tokens';\nexport * from './auth.service';\nexport * from './auth.interceptor';\nexport * from './auth.guard';\nexport * from './social-redirect-callback.guard';\nexport * from './auth.module';\nexport * from './http-adapter';\n\n// Re-export commonly used types for convenience\nexport type { NAuthClientConfig, TokenDeliveryMode } from '../types/config.types';\nexport type { AuthResponse, ChallengeResponse, TokenResponse, AuthChallenge } from '../types/auth.types';\nexport type { AuthUser } from '../types/user.types';\nexport type { MFAStatus, MFAMethod, MFADeviceMethod } from '../types/mfa.types';\nexport type { AuthEvent, AuthEventType, AuthEventListener } from '../core/events';\nexport type { SocialProvider } from '../types/social.types';\nexport type { HttpAdapter } from '../core/http-adapter';\n","import { InjectionToken } from '@angular/core';\nimport { NAuthClientConfig } from '../types/config.types';\n\n/**\n * Injection token for providing NAuthClientConfig in Angular apps.\n */\nexport const NAUTH_CLIENT_CONFIG = new InjectionToken<NAuthClientConfig>('NAUTH_CLIENT_CONFIG');\n","import { Inject, Injectable, Optional, inject } from '@angular/core';\nimport { BehaviorSubject, from, Observable, Subject } from 'rxjs';\nimport { filter } from 'rxjs/operators';\nimport { NAUTH_CLIENT_CONFIG } from './tokens';\nimport { AngularHttpAdapter } from './http-adapter';\nimport { NAuthClient } from '../core/client';\nimport { NAuthClientConfig } from '../types/config.types';\nimport { ChallengeResponse, AuthResponse, TokenResponse } from '../types/auth.types';\nimport {\n AuthUser,\n ConfirmForgotPasswordResponse,\n ForgotPasswordResponse,\n UpdateProfileRequest,\n} from '../types/user.types';\nimport { GetChallengeDataResponse, GetSetupDataResponse, MFAStatus, MFADevice } from '../types/mfa.types';\nimport { AuthEvent } from '../core/events';\nimport { SocialProvider, SocialLoginOptions, LinkedAccountsResponse, SocialVerifyRequest } from '../types/social.types';\nimport { AuditHistoryResponse } from '../types/audit.types';\n\n/**\n * Angular wrapper around NAuthClient that exposes Observables for auth state.\n *\n * This service provides:\n * - Reactive state (currentUser$, isAuthenticated$, challenge$)\n * - All core auth methods as Observables (login, signup, logout, refresh)\n * - Profile management (getProfile, updateProfile, changePassword)\n * - Challenge flow methods (respondToChallenge, resendCode)\n * - MFA management (getMfaStatus, setupMfaDevice, etc.)\n * - Social authentication and account linking\n * - Device trust management\n * - Audit history\n *\n * @example\n * ```typescript\n * constructor(private auth: AuthService) {}\n *\n * // Reactive state\n * this.auth.currentUser$.subscribe(user => ...);\n * this.auth.isAuthenticated$.subscribe(isAuth => ...);\n *\n * // Auth operations\n * this.auth.login(email, password).subscribe(response => ...);\n *\n * // Profile management\n * this.auth.changePassword(oldPassword, newPassword).subscribe(() => ...);\n * this.auth.updateProfile({ firstName: 'John' }).subscribe(user => ...);\n *\n * // MFA operations\n * this.auth.getMfaStatus().subscribe(status => ...);\n * ```\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class AuthService {\n private readonly client: NAuthClient;\n private readonly config: NAuthClientConfig;\n private readonly currentUserSubject = new BehaviorSubject<AuthUser | null>(null);\n private readonly isAuthenticatedSubject = new BehaviorSubject<boolean>(false);\n private readonly challengeSubject = new BehaviorSubject<AuthResponse | null>(null);\n private readonly authEventsSubject = new Subject<AuthEvent>();\n private initialized = false;\n\n /**\n * @param config - Injected client configuration\n *\n * Note: AngularHttpAdapter is automatically injected via Angular DI.\n * This ensures all requests go through Angular's HttpClient and interceptors.\n */\n constructor(@Optional() @Inject(NAUTH_CLIENT_CONFIG) config?: NAuthClientConfig) {\n if (!config) {\n throw new Error('NAUTH_CLIENT_CONFIG is required to initialize AuthService');\n }\n\n this.config = config;\n\n // Auto-inject AngularHttpAdapter (or use provided one)\n const httpAdapter = config.httpAdapter ?? inject(AngularHttpAdapter);\n\n this.client = new NAuthClient({\n ...config,\n httpAdapter, // Automatically use Angular's HttpClient\n onAuthStateChange: (user) => {\n this.currentUserSubject.next(user);\n this.isAuthenticatedSubject.next(Boolean(user));\n config.onAuthStateChange?.(user);\n },\n });\n\n // Forward all client events to Observable stream\n this.client.on('*', (event) => {\n this.authEventsSubject.next(event);\n });\n\n // Auto-initialize on construction (hydrate from storage)\n this.initialize();\n }\n\n // ============================================================================\n // Reactive State Observables\n // ============================================================================\n\n /**\n * Current user observable.\n */\n get currentUser$(): Observable<AuthUser | null> {\n return this.currentUserSubject.asObservable();\n }\n\n /**\n * Authenticated state observable.\n */\n get isAuthenticated$(): Observable<boolean> {\n return this.isAuthenticatedSubject.asObservable();\n }\n\n /**\n * Current challenge observable (for reactive challenge navigation).\n */\n get challenge$(): Observable<AuthResponse | null> {\n return this.challengeSubject.asObservable();\n }\n\n /**\n * Authentication events stream.\n * Emits all auth lifecycle events for custom logic, analytics, or UI updates.\n */\n get authEvents$(): Observable<AuthEvent> {\n return this.authEventsSubject.asObservable();\n }\n\n /**\n * Successful authentication events stream.\n * Emits when user successfully authenticates (login, signup, social auth).\n */\n get authSuccess$(): Observable<AuthEvent> {\n return this.authEventsSubject.pipe(filter((e) => e.type === 'auth:success'));\n }\n\n /**\n * Authentication error events stream.\n * Emits when authentication fails (login error, OAuth error, etc.).\n */\n get authError$(): Observable<AuthEvent> {\n return this.authEventsSubject.pipe(filter((e) => e.type === 'auth:error' || e.type === 'oauth:error'));\n }\n\n // ============================================================================\n // Sync State Accessors (for guards, templates)\n // ============================================================================\n\n /**\n * Check if authenticated (sync, uses cached state).\n */\n isAuthenticated(): boolean {\n return this.client.isAuthenticatedSync();\n }\n\n /**\n * Get current user (sync, uses cached state).\n */\n getCurrentUser(): AuthUser | null {\n return this.client.getCurrentUser();\n }\n\n /**\n * Get current challenge (sync).\n */\n getCurrentChallenge(): AuthResponse | null {\n return this.challengeSubject.value;\n }\n\n // ============================================================================\n // Core Auth Methods (Observable wrappers)\n // ============================================================================\n\n /**\n * Login with identifier and password.\n */\n login(identifier: string, password: string): Observable<AuthResponse> {\n return from(this.client.login(identifier, password).then((res) => this.updateChallengeState(res)));\n }\n\n /**\n * Signup with credentials.\n */\n signup(payload: Parameters<NAuthClient['signup']>[0]): Observable<AuthResponse> {\n return from(this.client.signup(payload).then((res) => this.updateChallengeState(res)));\n }\n\n /**\n * Logout current session.\n */\n logout(forgetDevice?: boolean): Observable<void> {\n return from(\n this.client.logout(forgetDevice).then(() => {\n this.challengeSubject.next(null);\n // Explicitly update auth state after logout\n this.currentUserSubject.next(null);\n this.isAuthenticatedSubject.next(false);\n\n // Clear CSRF token cookie if in cookies mode\n // Note: Backend should clear httpOnly cookies, but we clear non-httpOnly ones\n if (this.config.tokenDelivery === 'cookies' && typeof document !== 'undefined') {\n const csrfCookieName = this.config.csrf?.cookieName ?? 'nauth_csrf_token';\n // Extract domain from baseUrl if possible\n try {\n const url = new URL(this.config.baseUrl);\n document.cookie = `${csrfCookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${url.hostname}`;\n // Also try without domain (for localhost)\n document.cookie = `${csrfCookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n } catch {\n // Fallback if baseUrl parsing fails\n document.cookie = `${csrfCookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/`;\n }\n }\n }),\n );\n }\n\n /**\n * Logout all sessions.\n *\n * Revokes all active sessions for the current user across all devices.\n * Optionally revokes all trusted devices if forgetDevices is true.\n *\n * @param forgetDevices - If true, also revokes all trusted devices (default: false)\n * @returns Observable with number of sessions revoked\n */\n logoutAll(forgetDevices?: boolean): Observable<{ revokedCount: number }> {\n return from(\n this.client.logoutAll(forgetDevices).then((res) => {\n this.challengeSubject.next(null);\n // Explicitly update auth state after logout\n this.currentUserSubject.next(null);\n this.isAuthenticatedSubject.next(false);\n return res;\n }),\n );\n }\n\n /**\n * Refresh tokens.\n */\n refresh(): Observable<TokenResponse> {\n return from(this.client.refreshTokens());\n }\n\n /**\n * Refresh tokens (promise-based).\n *\n * Returns a promise instead of an Observable, matching the core NAuthClient API.\n * Useful for async/await patterns in guards and interceptors.\n *\n * @returns Promise of TokenResponse\n *\n * @example\n * ```typescript\n * const tokens = await auth.refreshTokensPromise();\n * ```\n */\n refreshTokensPromise(): Promise<TokenResponse> {\n return this.client.refreshTokens();\n }\n\n // ============================================================================\n // Account Recovery (Forgot Password)\n // ============================================================================\n\n /**\n * Request a password reset code (forgot password).\n */\n forgotPassword(identifier: string): Observable<ForgotPasswordResponse> {\n return from(this.client.forgotPassword(identifier));\n }\n\n /**\n * Confirm a password reset code and set a new password.\n */\n confirmForgotPassword(\n identifier: string,\n code: string,\n newPassword: string,\n ): Observable<ConfirmForgotPasswordResponse> {\n return from(this.client.confirmForgotPassword(identifier, code, newPassword));\n }\n\n /**\n * Change user password (requires current password).\n *\n * @param oldPassword - Current password\n * @param newPassword - New password (must meet requirements)\n * @returns Observable that completes when password is changed\n *\n * @example\n * ```typescript\n * this.auth.changePassword('oldPassword123', 'newSecurePassword456!').subscribe({\n * next: () => console.log('Password changed successfully'),\n * error: (err) => console.error('Failed to change password:', err)\n * });\n * ```\n */\n changePassword(oldPassword: string, newPassword: string): Observable<void> {\n return from(this.client.changePassword(oldPassword, newPassword));\n }\n\n /**\n * Request password change (must change on next login).\n *\n * @returns Observable that completes when request is sent\n */\n requestPasswordChange(): Observable<void> {\n return from(this.client.requestPasswordChange());\n }\n\n // ============================================================================\n // Profile Management\n // ============================================================================\n\n /**\n * Get current user profile.\n *\n * @returns Observable of current user profile\n *\n * @example\n * ```typescript\n * this.auth.getProfile().subscribe(user => {\n * console.log('User profile:', user);\n * });\n * ```\n */\n getProfile(): Observable<AuthUser> {\n return from(\n this.client.getProfile().then((user) => {\n // Update local state when profile is fetched\n this.currentUserSubject.next(user);\n return user;\n }),\n );\n }\n\n /**\n * Get current user profile (promise-based).\n *\n * Returns a promise instead of an Observable, matching the core NAuthClient API.\n * Useful for async/await patterns in guards and interceptors.\n *\n * @returns Promise of current user profile\n *\n * @example\n * ```typescript\n * const user = await auth.getProfilePromise();\n * ```\n */\n getProfilePromise(): Promise<AuthUser> {\n return this.client.getProfile().then((user) => {\n // Update local state when profile is fetched\n this.currentUserSubject.next(user);\n return user;\n });\n }\n\n /**\n * Update user profile.\n *\n * @param updates - Profile fields to update\n * @returns Observable of updated user profile\n *\n * @example\n * ```typescript\n * this.auth.updateProfile({ firstName: 'John', lastName: 'Doe' }).subscribe(user => {\n * console.log('Profile updated:', user);\n * });\n * ```\n */\n updateProfile(updates: UpdateProfileRequest): Observable<AuthUser> {\n return from(\n this.client.updateProfile(updates).then((user) => {\n // Update local state when profile is updated\n this.currentUserSubject.next(user);\n return user;\n }),\n );\n }\n\n // ============================================================================\n // Challenge Flow Methods (Essential for any auth flow)\n // ============================================================================\n\n /**\n * Respond to a challenge (VERIFY_EMAIL, VERIFY_PHONE, MFA_REQUIRED, etc.).\n */\n respondToChallenge(response: ChallengeResponse): Observable<AuthResponse> {\n return from(this.client.respondToChallenge(response).then((res) => this.updateChallengeState(res)));\n }\n\n /**\n * Resend challenge code.\n */\n resendCode(session: string): Observable<{ destination: string }> {\n return from(this.client.resendCode(session));\n }\n\n /**\n * Get MFA setup data (for MFA_SETUP_REQUIRED challenge).\n *\n * Returns method-specific setup information:\n * - TOTP: { secret, qrCode, manualEntryKey }\n * - SMS: { maskedPhone }\n * - Email: { maskedEmail }\n * - Passkey: WebAuthn registration options\n *\n * @param session - Challenge session token\n * @param method - MFA method to set up\n * @returns Observable of setup data response\n */\n getSetupData(session: string, method: string): Observable<GetSetupDataResponse> {\n return from(this.client.getSetupData(session, method as Parameters<NAuthClient['getSetupData']>[1]));\n }\n\n /**\n * Get MFA challenge data (for MFA_REQUIRED challenge - e.g., passkey options).\n *\n * @param session - Challenge session token\n * @param method - Challenge method\n * @returns Observable of challenge data response\n */\n getChallengeData(session: string, method: string): Observable<GetChallengeDataResponse> {\n return from(this.client.getChallengeData(session, method as Parameters<NAuthClient['getChallengeData']>[1]));\n }\n\n /**\n * Clear stored challenge (when navigating away from challenge flow).\n */\n clearChallenge(): Observable<void> {\n return from(\n this.client.clearStoredChallenge().then(() => {\n this.challengeSubject.next(null);\n }),\n );\n }\n\n // ============================================================================\n // Social Authentication\n // ============================================================================\n\n /**\n * Initiate social OAuth login flow.\n * Redirects the browser to backend `/auth/social/:provider/redirect`.\n */\n loginWithSocial(provider: SocialProvider, options?: SocialLoginOptions): Promise<void> {\n return this.client.loginWithSocial(provider, options);\n }\n\n /**\n * Exchange an exchangeToken (from redirect callback URL) into an AuthResponse.\n *\n * Used for `tokenDelivery: 'json'` or hybrid flows where the backend redirects back\n * with `exchangeToken` instead of setting cookies.\n *\n * @param exchangeToken - One-time exchange token from the callback URL\n * @returns Observable of AuthResponse\n */\n exchangeSocialRedirect(exchangeToken: string): Observable<AuthResponse> {\n return from(this.client.exchangeSocialRedirect(exchangeToken).then((res) => this.updateChallengeState(res)));\n }\n\n /**\n * Exchange an exchangeToken (from redirect callback URL) into an AuthResponse (promise-based).\n *\n * Returns a promise instead of an Observable, matching the core NAuthClient API.\n * Useful for async/await patterns in guards and interceptors.\n *\n * @param exchangeToken - One-time exchange token from the callback URL\n * @returns Promise of AuthResponse\n *\n * @example\n * ```typescript\n * const response = await auth.exchangeSocialRedirectPromise(exchangeToken);\n * ```\n */\n exchangeSocialRedirectPromise(exchangeToken: string): Promise<AuthResponse> {\n return this.client.exchangeSocialRedirect(exchangeToken).then((res) => this.updateChallengeState(res));\n }\n\n /**\n * Verify native social token (mobile).\n *\n * @param request - Social verification request with provider and token\n * @returns Observable of AuthResponse\n */\n verifyNativeSocial(request: SocialVerifyRequest): Observable<AuthResponse> {\n return from(this.client.verifyNativeSocial(request).then((res) => this.updateChallengeState(res)));\n }\n\n /**\n * Get linked social accounts.\n *\n * @returns Observable of linked accounts response\n */\n getLinkedAccounts(): Observable<LinkedAccountsResponse> {\n return from(this.client.getLinkedAccounts());\n }\n\n /**\n * Link social account.\n *\n * @param provider - Social provider to link\n * @param code - OAuth authorization code\n * @param state - OAuth state parameter\n * @returns Observable with success message\n */\n linkSocialAccount(provider: string, code: string, state: string): Observable<{ message: string }> {\n return from(this.client.linkSocialAccount(provider, code, state));\n }\n\n /**\n * Unlink social account.\n *\n * @param provider - Social provider to unlink\n * @returns Observable with success message\n */\n unlinkSocialAccount(provider: string): Observable<{ message: string }> {\n return from(this.client.unlinkSocialAccount(provider));\n }\n\n // ============================================================================\n // MFA Management\n // ============================================================================\n\n /**\n * Get MFA status for the current user.\n *\n * @returns Observable of MFA status\n */\n getMfaStatus(): Observable<MFAStatus> {\n return from(this.client.getMfaStatus());\n }\n\n /**\n * Get MFA devices for the current user.\n *\n * @returns Observable of MFA devices array\n */\n getMfaDevices(): Observable<MFADevice[]> {\n return from(this.client.getMfaDevices() as Promise<MFADevice[]>);\n }\n\n /**\n * Setup MFA device (authenticated user).\n *\n * @param method - MFA method to set up\n * @returns Observable of setup data\n */\n setupMfaDevice(method: string): Observable<unknown> {\n return from(this.client.setupMfaDevice(method));\n }\n\n /**\n * Verify MFA setup (authenticated user).\n *\n * @param method - MFA method\n * @param setupData - Setup data from setupMfaDevice\n * @param deviceName - Optional device name\n * @returns Observable with device ID\n */\n verifyMfaSetup(\n method: string,\n setupData: Record<string, unknown>,\n deviceName?: string,\n ): Observable<{ deviceId: number }> {\n return from(this.client.verifyMfaSetup(method, setupData, deviceName));\n }\n\n /**\n * Remove MFA device.\n *\n * @param method - MFA method to remove\n * @returns Observable with success message\n */\n removeMfaDevice(method: string): Observable<{ message: string }> {\n return from(this.client.removeMfaDevice(method));\n }\n\n /**\n * Set preferred MFA method.\n *\n * @param method - Device method to set as preferred ('totp', 'sms', 'email', or 'passkey')\n * @returns Observable with success message\n */\n setPreferredMfaMethod(method: 'totp' | 'sms' | 'email' | 'passkey'): Observable<{ message: string }> {\n return from(this.client.setPreferredMfaMethod(method));\n }\n\n /**\n * Generate backup codes.\n *\n * @returns Observable of backup codes array\n */\n generateBackupCodes(): Observable<string[]> {\n return from(this.client.generateBackupCodes());\n }\n\n /**\n * Set MFA exemption (admin/test scenarios).\n *\n * @param exempt - Whether to exempt user from MFA\n * @param reason - Optional reason for exemption\n * @returns Observable that completes when exemption is set\n */\n setMfaExemption(exempt: boolean, reason?: string): Observable<void> {\n return from(this.client.setMfaExemption(exempt, reason));\n }\n\n // ============================================================================\n // Device Trust\n // ============================================================================\n\n /**\n * Trust current device.\n *\n * @returns Observable with device token\n */\n trustDevice(): Observable<{ deviceToken: string }> {\n return from(this.client.trustDevice());\n }\n\n /**\n * Check if the current device is trusted.\n *\n * @returns Observable with trusted status\n */\n isTrustedDevice(): Observable<{ trusted: boolean }> {\n return from(this.client.isTrustedDevice());\n }\n\n // ============================================================================\n // Audit History\n // ============================================================================\n\n /**\n * Get paginated audit history for the current user.\n *\n * @param params - Query parameters for filtering and pagination\n * @returns Observable of audit history response\n *\n * @example\n * ```typescript\n * this.auth.getAuditHistory({ page: 1, limit: 20, eventType: 'LOGIN_SUCCESS' }).subscribe(history => {\n * console.log('Audit history:', history);\n * });\n * ```\n */\n getAuditHistory(params?: Record<string, string | number | boolean>): Observable<AuditHistoryResponse> {\n return from(this.client.getAuditHistory(params));\n }\n\n // ============================================================================\n // Escape Hatch\n // ============================================================================\n\n /**\n * Expose underlying NAuthClient for advanced scenarios.\n *\n * @deprecated All core functionality is now exposed directly on AuthService as Observables.\n * Use the direct methods on AuthService instead (e.g., `auth.changePassword()` instead of `auth.getClient().changePassword()`).\n * This method is kept for backward compatibility only and may be removed in a future version.\n *\n * @returns The underlying NAuthClient instance\n *\n * @example\n * ```typescript\n * // Deprecated - use direct methods instead\n * const status = await this.auth.getClient().getMfaStatus();\n *\n * // Preferred - use Observable-based methods\n * this.auth.getMfaStatus().subscribe(status => ...);\n * ```\n */\n getClient(): NAuthClient {\n return this.client;\n }\n\n // ============================================================================\n // Internal Methods\n // ============================================================================\n\n /**\n * Initialize by hydrating state from storage.\n * Called automatically on construction.\n */\n private async initialize(): Promise<void> {\n if (this.initialized) return;\n this.initialized = true;\n\n await this.client.initialize();\n\n // Hydrate challenge state\n const storedChallenge = await this.client.getStoredChallenge();\n if (storedChallenge) {\n this.challengeSubject.next(storedChallenge);\n }\n\n // Update subjects from client state\n const user = this.client.getCurrentUser();\n if (user) {\n this.currentUserSubject.next(user);\n this.isAuthenticatedSubject.next(true);\n }\n }\n\n /**\n * Update challenge state after auth response.\n */\n private updateChallengeState(response: AuthResponse): AuthResponse {\n if (response.challengeName) {\n this.challengeSubject.next(response);\n } else {\n this.challengeSubject.next(null);\n }\n return response;\n }\n}\n","import { Injectable, inject } from '@angular/core';\nimport { HttpClient, HttpErrorResponse } from '@angular/common/http';\nimport { firstValueFrom } from 'rxjs';\nimport { HttpAdapter, HttpRequest, HttpResponse } from '../core/http-adapter';\nimport { NAuthClientError } from '../core/errors';\nimport { NAuthErrorCode } from '../types/error.types';\n\n/**\n * HTTP adapter for Angular using HttpClient.\n *\n * This adapter:\n * - Uses Angular's HttpClient for all requests\n * - Works with Angular's HTTP interceptors (including authInterceptor)\n * - Auto-provided via Angular DI (providedIn: 'root')\n * - Converts HttpClient responses to HttpResponse format\n * - Converts HttpErrorResponse to NAuthClientError\n *\n * Users don't need to configure this manually - it's automatically\n * injected when using AuthService in Angular apps.\n *\n * @example\n * ```typescript\n * // Automatic usage (no manual setup needed)\n * // AuthService automatically injects AngularHttpAdapter\n * constructor(private auth: AuthService) {}\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class AngularHttpAdapter implements HttpAdapter {\n private readonly http = inject(HttpClient);\n\n /**\n * Execute HTTP request using Angular's HttpClient.\n *\n * @param config - Request configuration\n * @returns Response with parsed data\n * @throws NAuthClientError if request fails\n */\n async request<T>(config: HttpRequest): Promise<HttpResponse<T>> {\n try {\n // Use Angular's HttpClient - goes through ALL interceptors\n const data = await firstValueFrom(\n this.http.request<T>(config.method, config.url, {\n body: config.body,\n headers: config.headers,\n withCredentials: config.credentials === 'include',\n observe: 'body', // Only return body data\n }),\n );\n\n return {\n data,\n status: 200, // HttpClient only returns data on success\n headers: {}, // Can extract from observe: 'response' if needed\n };\n } catch (error) {\n if (error instanceof HttpErrorResponse) {\n // Convert Angular's HttpErrorResponse to NAuthClientError\n const errorData = error.error || {};\n const code =\n typeof errorData['code'] === 'string' ? (errorData.code as NAuthErrorCode) : NAuthErrorCode.INTERNAL_ERROR;\n const message =\n typeof errorData['message'] === 'string'\n ? (errorData.message as string)\n : error.message || `Request failed with status ${error.status}`;\n const timestamp = typeof errorData['timestamp'] === 'string' ? errorData.timestamp : undefined;\n const details = errorData['details'] as Record<string, unknown> | undefined;\n\n throw new NAuthClientError(code, message, {\n statusCode: error.status,\n timestamp,\n details,\n isNetworkError: error.status === 0, // Network error (no response from server)\n });\n }\n\n // Re-throw non-HTTP errors\n throw error;\n }\n }\n}\n\n\n\n","import { NAuthError, NAuthErrorCode } from '../types/error.types';\n\n/**\n * Client-side error wrapper for SDK operations.\n *\n * Mirrors the backend NAuthException structure for consistent error handling.\n *\n * @example\n * ```typescript\n * try {\n * await client.login({ identifier: 'user@example.com', password: 'wrong' });\n * } catch (error) {\n * if (error instanceof NAuthClientError) {\n * console.log(error.code); // 'AUTH_INVALID_CREDENTIALS'\n * console.log(error.message); // 'Invalid credentials'\n * console.log(error.timestamp); // '2025-12-06T...'\n *\n * // Check specific error code\n * if (error.isCode(NAuthErrorCode.RATE_LIMIT_LOGIN)) {\n * const retryAfter = error.details?.retryAfter as number;\n * console.log(`Rate limited. Retry in ${retryAfter}s`);\n * }\n * }\n * }\n * ```\n */\nexport class NAuthClientError extends Error implements NAuthError {\n public readonly code: NAuthErrorCode;\n public readonly details?: Record<string, unknown>;\n public readonly statusCode?: number;\n public readonly timestamp: string;\n public readonly isNetworkError: boolean;\n\n /**\n * Create a new client error.\n *\n * @param code - Error code from NAuthErrorCode enum\n * @param message - Human-readable error message\n * @param options - Optional metadata including details, statusCode, timestamp, and network error flag\n */\n constructor(\n code: NAuthErrorCode,\n message: string,\n options?: {\n details?: Record<string, unknown>;\n statusCode?: number;\n timestamp?: string;\n isNetworkError?: boolean;\n },\n ) {\n super(message);\n this.code = code;\n this.details = options?.details;\n this.statusCode = options?.statusCode;\n this.timestamp = options?.timestamp || new Date().toISOString();\n this.isNetworkError = options?.isNetworkError ?? false;\n this.name = 'NAuthClientError';\n Object.setPrototypeOf(this, NAuthClientError.prototype);\n }\n\n /**\n * Check if error matches a specific error code.\n *\n * @param code - Error code to check against\n * @returns True if the error code matches\n *\n * @example\n * ```typescript\n * if (error.isCode(NAuthErrorCode.RATE_LIMIT_SMS)) {\n * // Handle SMS rate limit\n * }\n * ```\n */\n isCode(code: NAuthErrorCode): boolean {\n return this.code === code;\n }\n\n /**\n * Get error details/metadata.\n *\n * @returns Error details object or undefined\n *\n * @example\n * ```typescript\n * const details = error.getDetails();\n * if (details?.retryAfter) {\n * console.log(`Retry after ${details.retryAfter} seconds`);\n * }\n * ```\n */\n getDetails(): Record<string, unknown> | undefined {\n return this.details;\n }\n\n /**\n * Get the error code.\n *\n * @returns The error code enum value\n */\n getCode(): NAuthErrorCode {\n return this.code;\n }\n\n /**\n * Serialize error to JSON object.\n *\n * @returns Plain object representation\n *\n * @example\n * ```typescript\n * const errorJson = error.toJSON();\n * // { code: 'AUTH_INVALID_CREDENTIALS', message: '...', timestamp: '...', details: {...} }\n * ```\n */\n toJSON(): {\n code: string;\n message: string;\n timestamp: string;\n details?: Record<string, unknown>;\n statusCode?: number;\n } {\n return {\n code: this.code,\n message: this.message,\n timestamp: this.timestamp,\n details: this.details,\n statusCode: this.statusCode,\n };\n }\n}\n","import {\n NAuthClientConfig,\n NAuthEndpoints,\n NAuthStorageAdapter,\n TokenDeliveryMode,\n HttpAdapter,\n} from '../types/config.types';\n\n/**\n * Fully resolved configuration with all defaults applied.\n */\nexport type ResolvedNAuthClientConfig = Omit<\n NAuthClientConfig,\n 'endpoints' | 'storage' | 'tokenDelivery' | 'httpAdapter'\n> & {\n tokenDelivery: TokenDeliveryMode;\n endpoints: NAuthEndpoints;\n storage: NAuthStorageAdapter;\n httpAdapter: HttpAdapter;\n csrf: { cookieName: string; headerName: string };\n deviceTrust: { headerName: string; storageKey: string };\n headers: Record<string, string>;\n timeout: number;\n};\n\n/**\n * Default endpoint paths matching backend controller.\n */\nexport const defaultEndpoints: NAuthEndpoints = {\n login: '/login',\n signup: '/signup',\n logout: '/logout',\n logoutAll: '/logout/all',\n refresh: '/refresh',\n respondChallenge: '/respond-challenge',\n resendCode: '/challenge/resend',\n getSetupData: '/challenge/setup-data',\n getChallengeData: '/challenge/challenge-data',\n profile: '/profile',\n changePassword: '/change-password',\n requestPasswordChange: '/request-password-change',\n forgotPassword: '/forgot-password',\n confirmForgotPassword: '/forgot-password/confirm',\n mfaStatus: '/mfa/status',\n mfaDevices: '/mfa/devices',\n mfaSetupData: '/mfa/setup-data',\n mfaVerifySetup: '/mfa/verify-setup',\n mfaRemove: '/mfa/method',\n mfaPreferred: '/mfa/preferred-method',\n mfaBackupCodes: '/mfa/backup-codes/generate',\n mfaExemption: '/mfa/exemption',\n socialLinked: '/social/linked',\n socialLink: '/social/link',\n socialUnlink: '/social/unlink',\n socialVerify: '/social/:provider/verify',\n socialRedirectStart: '/social/:provider/redirect',\n socialExchange: '/social/exchange',\n trustDevice: '/trust-device',\n isTrustedDevice: '/is-trusted-device',\n auditHistory: '/audit/history',\n updateProfile: '/profile',\n};\n\n/**\n * Normalize user config with defaults.\n *\n * @param config - User supplied config\n * @param defaultAdapter - Default HTTP adapter (FetchAdapter for vanilla, AngularHttpAdapter for Angular)\n * @returns Resolved config with defaults applied\n */\nexport const resolveConfig = (config: NAuthClientConfig, defaultAdapter: HttpAdapter): ResolvedNAuthClientConfig => {\n const resolvedEndpoints: NAuthEndpoints = {\n ...defaultEndpoints,\n ...(config.endpoints ?? {}),\n };\n\n return {\n ...config,\n csrf: {\n cookieName: config.csrf?.cookieName ?? 'nauth_csrf_token',\n headerName: config.csrf?.headerName ?? 'x-csrf-token',\n },\n deviceTrust: {\n headerName: config.deviceTrust?.headerName ?? 'X-Device-Token',\n storageKey: config.deviceTrust?.storageKey ?? 'nauth_device_token',\n },\n headers: config.headers ?? {},\n timeout: config.timeout ?? 30000,\n endpoints: resolvedEndpoints,\n storage: config.storage as NAuthStorageAdapter,\n httpAdapter: config.httpAdapter ?? defaultAdapter,\n };\n};\n","import { TokenResponse } from '../types/auth.types';\nimport { NAuthStorageAdapter } from '../types/config.types';\nimport { NAuthClientError } from './errors';\nimport { NAuthErrorCode } from '../types/error.types';\n\nconst ACCESS_TOKEN_KEY = 'nauth_access_token';\nconst REFRESH_TOKEN_KEY = 'nauth_refresh_token';\nconst ACCESS_EXPIRES_AT_KEY = 'nauth_access_token_expires_at';\nconst REFRESH_EXPIRES_AT_KEY = 'nauth_refresh_token_expires_at';\nconst USER_KEY = 'nauth_user';\nconst CHALLENGE_KEY = 'nauth_challenge_session';\n\n/**\n * Token state persisted in storage.\n */\nexport interface TokenState {\n accessToken: string | null;\n refreshToken: string | null;\n accessTokenExpiresAt?: number | null;\n refreshTokenExpiresAt?: number | null;\n}\n\n/**\n * Manage token persistence and refresh queuing.\n */\nexport class TokenManager {\n private readonly storage: NAuthStorageAdapter;\n private refreshPromise: Promise<TokenResponse> | null = null;\n private readonly isBrowser = typeof window !== 'undefined';\n\n /**\n * @param storage - storage adapter\n */\n constructor(storage: NAuthStorageAdapter) {\n this.storage = storage;\n }\n\n /**\n * Load tokens from storage.\n */\n async getTokens(): Promise<TokenState> {\n const [accessToken, refreshToken, accessExpRaw, refreshExpRaw] = await Promise.all([\n this.storage.getItem(ACCESS_TOKEN_KEY),\n this.storage.getItem(REFRESH_TOKEN_KEY),\n this.storage.getItem(ACCESS_EXPIRES_AT_KEY),\n this.storage.getItem(REFRESH_EXPIRES_AT_KEY),\n ]);\n return {\n accessToken,\n refreshToken,\n accessTokenExpiresAt: accessExpRaw ? Number(accessExpRaw) : null,\n refreshTokenExpiresAt: refreshExpRaw ? Number(refreshExpRaw) : null,\n };\n }\n\n /**\n * Persist tokens.\n *\n * @param tokens - new token pair\n */\n async setTokens(tokens: TokenResponse): Promise<void> {\n await Promise.all([\n this.storage.setItem(ACCESS_TOKEN_KEY, tokens.accessToken),\n this.storage.setItem(REFRESH_TOKEN_KEY, tokens.refreshToken),\n this.storage.setItem(ACCESS_EXPIRES_AT_KEY, tokens.accessTokenExpiresAt.toString()),\n this.storage.setItem(REFRESH_EXPIRES_AT_KEY, tokens.refreshTokenExpiresAt.toString()),\n ]);\n this.broadcastStorage();\n }\n\n /**\n * Clear tokens and related auth state.\n */\n async clearTokens(): Promise<void> {\n await Promise.all([\n this.storage.removeItem(ACCESS_TOKEN_KEY),\n this.storage.removeItem(REFRESH_TOKEN_KEY),\n this.storage.removeItem(ACCESS_EXPIRES_AT_KEY),\n this.storage.removeItem(REFRESH_EXPIRES_AT_KEY),\n this.storage.removeItem(USER_KEY),\n this.storage.removeItem(CHALLENGE_KEY),\n ]);\n this.broadcastStorage();\n }\n\n /**\n * Ensure only one refresh in flight.\n *\n * @param refreshFn - function performing refresh request\n */\n async refreshOnce(refreshFn: () => Promise<TokenResponse>): Promise<TokenResponse> {\n if (!this.refreshPromise) {\n this.refreshPromise = refreshFn()\n .then(async (tokens) => {\n await this.setTokens(tokens);\n return tokens;\n })\n .catch((error) => {\n throw error;\n })\n .finally(() => {\n this.refreshPromise = null;\n });\n }\n return this.refreshPromise;\n }\n\n /**\n * Validate that a refresh token exists before attempting refresh.\n */\n async assertHasRefreshToken(): Promise<void> {\n const state = await this.getTokens();\n if (!state.refreshToken) {\n throw new NAuthClientError(NAuthErrorCode.AUTH_SESSION_NOT_FOUND, 'No refresh token available');\n }\n }\n\n /**\n * Broadcast a no-op write to trigger storage listeners in other tabs.\n */\n private broadcastStorage(): void {\n if (!this.isBrowser) return;\n try {\n window.localStorage.setItem('nauth_sync', Date.now().toString());\n } catch {\n // Best-effort; ignore if storage unavailable\n }\n }\n}\n","import { NAuthStorageAdapter } from './interface';\n\n/**\n * Browser storage adapter wrapping localStorage or sessionStorage.\n */\nexport class BrowserStorage implements NAuthStorageAdapter {\n private readonly storage: Storage;\n\n /**\n * Create a browser storage adapter.\n *\n * @param storage - Storage implementation (localStorage by default)\n */\n constructor(storage: Storage = window.localStorage) {\n this.storage = storage;\n }\n\n async getItem(key: string): Promise<string | null> {\n return this.storage.getItem(key);\n }\n\n async setItem(key: string, value: string): Promise<void> {\n this.storage.setItem(key, value);\n }\n\n async removeItem(key: string): Promise<void> {\n this.storage.removeItem(key);\n }\n\n async clear(): Promise<void> {\n this.storage.clear();\n }\n}\n","import { NAuthStorageAdapter } from './interface';\n\n/**\n * In-memory storage adapter for SSR, tests, or environments without Web Storage.\n */\nexport class InMemoryStorage implements NAuthStorageAdapter {\n private readonly store = new Map<string, string>();\n\n async getItem(key: string): Promise<string | null> {\n return this.store.has(key) ? (this.store.get(key) as string) : null;\n }\n\n async setItem(key: string, value: string): Promise<void> {\n this.store.set(key, value);\n }\n\n async removeItem(key: string): Promise<void> {\n this.store.delete(key);\n }\n\n async clear(): Promise<void> {\n this.store.clear();\n }\n}\n","import type { AuthResponse } from '../types/auth.types';\nimport type { NAuthClientError } from './errors';\n\n/**\n * Authentication event types emitted by NAuthClient\n *\n * Events are emitted throughout the authentication lifecycle,\n * allowing applications to react to auth state changes.\n */\nexport type AuthEventType =\n | 'auth:login'\n | 'auth:signup'\n | 'auth:success'\n | 'auth:challenge'\n | 'auth:error'\n | 'auth:logout'\n | 'auth:refresh'\n | 'oauth:started'\n | 'oauth:callback'\n | 'oauth:completed'\n | 'oauth:error';\n\n/**\n * Discriminated union of all authentication events with type-safe payloads\n *\n * Each event has a specific payload type for better type safety.\n */\nexport type AuthEvent =\n | AuthLoginEvent\n | AuthSignupEvent\n | AuthSuccessEvent\n | AuthChallengeEvent\n | AuthErrorEvent\n | AuthLogoutEvent\n | AuthRefreshEvent\n | OAuthStartedEvent\n | OAuthCallbackEvent\n | OAuthCompletedEvent\n | OAuthErrorEvent;\n\n/**\n * Login initiated event\n */\nexport interface AuthLoginEvent {\n type: 'auth:login';\n data: {\n identifier: string;\n };\n timestamp: number;\n}\n\n/**\n * Signup initiated event\n */\nexport interface AuthSignupEvent {\n type: 'auth:signup';\n data: {\n email: string;\n };\n timestamp: number;\n}\n\n/**\n * Successful authentication event\n */\nexport interface AuthSuccessEvent {\n type: 'auth:success';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * Challenge required event\n */\nexport interface AuthChallengeEvent {\n type: 'auth:challenge';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * Authentication error event\n */\nexport interface AuthErrorEvent {\n type: 'auth:error';\n data: NAuthClientError;\n timestamp: number;\n}\n\n/**\n * User logged out event\n */\nexport interface AuthLogoutEvent {\n type: 'auth:logout';\n data: {\n forgetDevice?: boolean;\n global?: boolean;\n };\n timestamp: number;\n}\n\n/**\n * Token refreshed event\n */\nexport interface AuthRefreshEvent {\n type: 'auth:refresh';\n data: {\n success: boolean;\n };\n timestamp: number;\n}\n\n/**\n * OAuth flow started event\n */\nexport interface OAuthStartedEvent {\n type: 'oauth:started';\n data: {\n provider: string;\n };\n timestamp: number;\n}\n\n/**\n * OAuth callback received event\n */\nexport interface OAuthCallbackEvent {\n type: 'oauth:callback';\n data: {\n provider: string;\n };\n timestamp: number;\n}\n\n/**\n * OAuth flow completed event\n */\nexport interface OAuthCompletedEvent {\n type: 'oauth:completed';\n data: AuthResponse;\n timestamp: number;\n}\n\n/**\n * OAuth error event\n */\nexport interface OAuthErrorEvent {\n type: 'oauth:error';\n data: NAuthClientError;\n timestamp: number;\n}\n\n/**\n * Event listener callback function\n */\nexport type AuthEventListener = (event: AuthEvent) => void;\n\n/**\n * Internal event emitter for authentication events\n *\n * Provides pub/sub functionality for auth lifecycle events.\n *\n * @internal\n */\nexport class EventEmitter {\n private listeners = new Map<AuthEventType | '*', Set<AuthEventListener>>();\n\n /**\n * Subscribe to an authentication event\n *\n * @param event - Event type or '*' for all events\n * @param listener - Callback function\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * const unsubscribe = emitter.on('auth:success', (event) => {\n * console.log('User logged in:', event.data);\n * });\n *\n * // Later\n * unsubscribe();\n * ```\n */\n on(event: AuthEventType | '*', listener: AuthEventListener): () => void {\n if (!this.listeners.has(event)) {\n this.listeners.set(event, new Set());\n }\n this.listeners.get(event)!.add(listener);\n\n // Return unsubscribe function\n return () => this.off(event, listener);\n }\n\n /**\n * Unsubscribe from an authentication event\n *\n * @param event - Event type or '*'\n * @param listener - Callback function to remove\n */\n off(event: AuthEventType | '*', listener: AuthEventListener): void {\n this.listeners.get(event)?.delete(listener);\n }\n\n /**\n * Emit an authentication event\n *\n * Notifies all listeners for the specific event type and wildcard listeners.\n *\n * @param event - Event to emit\n * @internal\n */\n emit(event: AuthEvent): void {\n const specificListeners = this.listeners.get(event.type);\n const wildcardListeners = this.listeners.get('*');\n\n // Emit to specific event listeners\n specificListeners?.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n console.error(`Error in ${event.type} event listener:`, error);\n }\n });\n\n // Emit to wildcard listeners\n wildcardListeners?.forEach((listener) => {\n try {\n listener(event);\n } catch (error) {\n console.error(`Error in wildcard event listener:`, error);\n }\n });\n }\n\n /**\n * Remove all listeners\n *\n * @internal\n */\n clear(): void {\n this.listeners.clear();\n }\n}\n","import { HttpAdapter, HttpRequest, HttpResponse } from '../core/http-adapter';\nimport { NAuthClientError } from '../core/errors';\nimport { NAuthErrorCode } from '../types/error.types';\n\n/**\n * HTTP adapter using native fetch API.\n *\n * Suitable for:\n * - Vanilla JavaScript/TypeScript\n * - Node.js (with fetch polyfill or Node 18+)\n * - Environments without framework-specific HTTP clients\n *\n * @example\n * ```typescript\n * import { NAuthClient } from '@nauth-toolkit/client';\n * import { FetchAdapter } from '@nauth-toolkit/client/adapters/fetch';\n *\n * const client = new NAuthClient({\n * baseUrl: 'https://api.example.com/auth',\n * httpAdapter: new FetchAdapter(),\n * });\n * ```\n */\nexport class FetchAdapter implements HttpAdapter {\n /**\n * Execute HTTP request using native fetch.\n *\n * @param config - Request configuration\n * @returns Response with parsed data\n * @throws NAuthClientError if request fails\n */\n async request<T>(config: HttpRequest): Promise<HttpResponse<T>> {\n const fetchOptions: RequestInit = {\n method: config.method,\n headers: config.headers,\n signal: config.signal,\n credentials: config.credentials,\n };\n\n if (config.body !== undefined) {\n fetchOptions.body = JSON.stringify(config.body);\n }\n\n let response: Response;\n try {\n response = await fetch(config.url, fetchOptions);\n } catch (error) {\n throw new NAuthClientError(NAuthErrorCode.INTERNAL_ERROR, 'Network request failed', {\n isNetworkError: true,\n details: { url: config.url, message: (error as Error).message },\n });\n }\n\n const status = response.status;\n let data: unknown = null;\n const text = await response.text();\n if (text) {\n try {\n data = JSON.parse(text);\n } catch {\n data = text;\n }\n }\n\n // Extract headers\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n\n if (!response.ok) {\n const errorData = typeof data === 'object' && data !== null ? (data as Record<string, unknown>) : {};\n const code =\n typeof errorData['code'] === 'string'\n ? (errorData['code'] as NAuthErrorCode)\n : NAuthErrorCode.INTERNAL_ERROR;\n const message =\n typeof errorData['message'] === 'string'\n ? (errorData['message'] as string)\n : `Request failed with status ${status}`;\n const timestamp = typeof errorData['timestamp'] === 'string' ? (errorData['timestamp'] as string) : undefined;\n const details = errorData['details'] as Record<string, unknown> | undefined;\n\n throw new NAuthClientError(code, message, {\n statusCode: status,\n timestamp,\n details,\n });\n }\n\n return { data: data as T, status, headers };\n }\n}\n\n\n\n","import { resolveConfig, ResolvedNAuthClientConfig } from './config';\nimport { TokenManager } from './refresh';\nimport { BrowserStorage } from '../storage/browser';\nimport { InMemoryStorage } from '../storage/memory';\nimport { EventEmitter, AuthEventType, AuthEventListener } from './events';\nimport { NAuthClientError } from './errors';\nimport { NAuthErrorCode } from '../types/error.types';\nimport { FetchAdapter } from '../adapters/fetch-adapter';\nimport {\n AuthChallenge,\n ChallengeResponse,\n GetChallengeDataRequest,\n GetSetupDataRequest,\n LoginRequest,\n LogoutAllRequest,\n AuthResponse,\n ResendCodeRequest,\n SignupRequest,\n TokenResponse,\n} from '../types/auth.types';\nimport { NAuthClientConfig } from '../types/config.types';\nimport { GetChallengeDataResponse, GetSetupDataResponse, MFAStatus } from '../types/mfa.types';\nimport { LinkedAccountsResponse, SocialLoginOptions, SocialVerifyRequest, SocialProvider } from '../types/social.types';\nimport {\n AuthUser,\n ChangePasswordRequest,\n ConfirmForgotPasswordRequest,\n ConfirmForgotPasswordResponse,\n ForgotPasswordRequest,\n ForgotPasswordResponse,\n UpdateProfileRequest,\n} from '../types/user.types';\nimport { AuditHistoryResponse } from '../types/audit.types';\n\nconst USER_KEY = 'nauth_user';\nconst CHALLENGE_KEY = 'nauth_challenge_session';\nconst hasWindow = (): boolean =>\n typeof globalThis !== 'undefined' && typeof (globalThis as { window?: unknown }).window !== 'undefined';\n\n/**\n * Choose default storage implementation.\n */\nconst defaultStorage = () => {\n if (hasWindow() && typeof window.localStorage !== 'undefined') {\n return new BrowserStorage();\n }\n return new InMemoryStorage();\n};\n\n/**\n * Primary client for interacting with nauth-toolkit backend.\n */\nexport class NAuthClient {\n private readonly config: ResolvedNAuthClientConfig;\n private readonly tokenManager: TokenManager;\n private readonly eventEmitter: EventEmitter;\n private currentUser: AuthUser | null = null;\n\n /**\n * Create a new client instance.\n *\n * @param userConfig - Client configuration\n */\n constructor(userConfig: NAuthClientConfig) {\n const storage = userConfig.storage ?? defaultStorage();\n const defaultAdapter = userConfig.httpAdapter ?? new FetchAdapter();\n this.config = resolveConfig({ ...userConfig, storage }, defaultAdapter);\n this.tokenManager = new TokenManager(storage);\n this.eventEmitter = new EventEmitter();\n if (hasWindow()) {\n window.addEventListener('storage', this.handleStorageEvent);\n }\n }\n\n /**\n * Clean up resources.\n */\n dispose(): void {\n if (hasWindow()) {\n window.removeEventListener('storage', this.handleStorageEvent);\n }\n }\n\n /**\n * Login with identifier and password.\n */\n async login(identifier: string, password: string): Promise<AuthResponse> {\n const loginEvent = { type: 'auth:login' as const, data: { identifier }, timestamp: Date.now() };\n this.eventEmitter.emit(loginEvent);\n\n try {\n const body: LoginRequest = { identifier, password };\n const response = await this.post<AuthResponse>(this.config.endpoints.login, body);\n await this.handleAuthResponse(response);\n\n // Emit success or challenge event\n if (response.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: response, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: response, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return response;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(NAuthErrorCode.AUTH_INVALID_CREDENTIALS, (error as Error).message || 'Login failed');\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Signup with credentials.\n */\n async signup(payload: SignupRequest): Promise<AuthResponse> {\n this.eventEmitter.emit({ type: 'auth:signup', data: { email: payload.email }, timestamp: Date.now() });\n\n try {\n const response = await this.post<AuthResponse>(this.config.endpoints.signup, payload);\n await this.handleAuthResponse(response);\n\n // Emit success or challenge event\n if (response.challengeName) {\n this.eventEmitter.emit({ type: 'auth:challenge', data: response, timestamp: Date.now() });\n } else {\n this.eventEmitter.emit({ type: 'auth:success', data: response, timestamp: Date.now() });\n }\n\n return response;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(NAuthErrorCode.AUTH_INVALID_CREDENTIALS, (error as Error).message || 'Signup failed');\n this.eventEmitter.emit({ type: 'auth:error', data: authError, timestamp: Date.now() });\n throw authError;\n }\n }\n\n /**\n * Refresh tokens manually.\n */\n async refreshTokens(): Promise<TokenResponse> {\n const tokenDelivery = this.getTokenDeliveryMode();\n\n // Only check for refresh token in localStorage for JSON mode\n // In cookies mode, refresh token is in httpOnly cookie (backend manages it)\n if (tokenDelivery === 'json') {\n await this.tokenManager.assertHasRefreshToken();\n }\n\n const body =\n tokenDelivery === 'json'\n ? { refreshToken: (await this.tokenManager.getTokens()).refreshToken }\n : { refreshToken: '' };\n const refreshFn = async () => {\n // In cookies mode, refresh token is sent via httpOnly cookie (no access token needed, auth=false)\n // In JSON mode, refresh token is in body (no access token needed, auth=false)\n // Refresh endpoint is PUBLIC - it doesn't need an access token\n return this.post<TokenResponse>(this.config.endpoints.refresh, body, false);\n };\n const tokens = await this.tokenManager.refreshOnce(refreshFn);\n this.config.onTokenRefresh?.();\n this.eventEmitter.emit({ type: 'auth:refresh', data: { success: true }, timestamp: Date.now() });\n return tokens;\n }\n\n /**\n * Logout current session.\n *\n * Uses GET request to avoid CSRF token issues.\n *\n * @param forgetDevice - If true, also untrust the device (require MFA on next login)\n */\n async logout(forgetDevice?: boolean): Promise<void> {\n const queryParams = forgetDevice ? '?forgetMe=true' : '';\n try {\n await this.get(this.config.endpoints.logout + queryParams, true);\n } catch (error) {\n // Ignore logout errors (session might already be invalid)\n console.warn('[nauth] Logout request failed (session may already be invalid):', error);\n } finally {\n // Always clear local state even if request fails\n // Pass forgetDevice flag to clear device token in JSON mode\n await this.clearAuthState(forgetDevice);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevice, global: false },\n timestamp: Date.now(),\n });\n }\n }\n\n /**\n * Logout all sessions.\n *\n * Revokes all active sessions for the current user across all devices.\n * Optionally revokes all trusted devices if forgetDevices is true.\n *\n * @param forgetDevices - If true, also revokes all trusted devices (default: false)\n * @returns Number of sessions revoked\n */\n async logoutAll(forgetDevices?: boolean): Promise<{ revokedCount: number }> {\n try {\n const payload: LogoutAllRequest = {\n forgetDevices: forgetDevices ?? false,\n };\n const result = await this.post<{ message: string; revokedCount: number }>(\n this.config.endpoints.logoutAll,\n payload,\n true,\n );\n // Clear device token in JSON mode if forgetDevices is true\n await this.clearAuthState(forgetDevices);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevices, global: true },\n timestamp: Date.now(),\n });\n return { revokedCount: result.revokedCount };\n } catch (error) {\n // If request fails, still clear local state\n await this.clearAuthState(forgetDevices);\n this.eventEmitter.emit({\n type: 'auth:logout',\n data: { forgetDevice: !!forgetDevices, global: true },\n timestamp: Date.now(),\n });\n throw error;\n }\n }\n\n /**\n * Respond to a challenge.\n *\n * Validates challenge response data before sending to backend.\n * Provides helpful error messages for common validation issues.\n *\n * @param response - Challenge response data\n * @returns Auth response from backend\n * @throws {NAuthClientError} If validation fails\n */\n async respondToChallenge(response: ChallengeResponse): Promise<AuthResponse> {\n // Validate TOTP setup requires both secret and code\n if (response.type === AuthChallenge.MFA_SETUP_REQUIRED && response.method === 'totp') {\n const setupData = response.setupData;\n if (!setupData || typeof setupData !== 'object') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires setupData with both secret and code',\n { details: { field: 'setupData' } },\n );\n }\n\n const secret = setupData['secret'];\n const code = setupData['code'];\n\n if (!secret || typeof secret !== 'string') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires secret in setupData. Make sure to include the secret from getSetupData() response.',\n { details: { field: 'secret' } },\n );\n }\n\n if (!code || typeof code !== 'string') {\n throw new NAuthClientError(\n NAuthErrorCode.VALIDATION_FAILED,\n 'TOTP setup requires code in setupData. Please enter the verification code from your authenticator app.',\n { details: { field: 'code' } },\n );\n }\n }\n\n try {\n const result = await this.post<AuthResponse>(this.config.endpoints.respondChallenge, response);\n await this.handleAuthResponse(result);\n\n // Emit success or challenge event\n if (result.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return result;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(\n NAuthErrorCode.CHALLENGE_INVALID,\n (error as Error).message || 'Challenge response failed',\n );\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Resend a challenge code.\n */\n async resendCode(session: string): Promise<{ destination: string }> {\n const payload: ResendCodeRequest = { session };\n return this.post<{ destination: string }>(this.config.endpoints.resendCode, payload);\n }\n\n /**\n * Get setup data for MFA.\n *\n * Returns method-specific setup information:\n * - TOTP: { secret, qrCode, manualEntryKey }\n * - SMS: { maskedPhone }\n * - Email: { maskedEmail }\n * - Passkey: WebAuthn registration options\n *\n * @param session - Challenge session token\n * @param method - MFA method to set up\n * @returns Setup data wrapped in GetSetupDataResponse\n */\n async getSetupData(session: string, method: GetSetupDataRequest['method']): Promise<GetSetupDataResponse> {\n const payload: GetSetupDataRequest = { session, method };\n return this.post<GetSetupDataResponse>(this.config.endpoints.getSetupData, payload);\n }\n\n /**\n * Get challenge data (e.g., WebAuthn options).\n *\n * Returns challenge-specific data for verification flows.\n *\n * @param session - Challenge session token\n * @param method - Challenge method to get data for\n * @returns Challenge data wrapped in GetChallengeDataResponse\n */\n async getChallengeData(\n session: string,\n method: GetChallengeDataRequest['method'],\n ): Promise<GetChallengeDataResponse> {\n const payload: GetChallengeDataRequest = { session, method };\n return this.post<GetChallengeDataResponse>(this.config.endpoints.getChallengeData, payload);\n }\n\n /**\n * Get current user profile.\n */\n async getProfile(): Promise<AuthUser> {\n const profile = await this.get<AuthUser>(this.config.endpoints.profile, true);\n await this.setUser(profile);\n return profile;\n }\n\n /**\n * Update user profile.\n */\n async updateProfile(updates: UpdateProfileRequest): Promise<AuthUser> {\n const updated = await this.put<AuthUser>(this.config.endpoints.updateProfile, updates, true);\n await this.setUser(updated);\n return updated;\n }\n\n /**\n * Change user password.\n */\n async changePassword(oldPassword: string, newPassword: string): Promise<void> {\n const payload: ChangePasswordRequest = { currentPassword: oldPassword, newPassword };\n await this.post(this.config.endpoints.changePassword, payload, true);\n }\n\n /**\n * Request a password reset code (forgot password).\n */\n async forgotPassword(identifier: string): Promise<ForgotPasswordResponse> {\n const payload: ForgotPasswordRequest = { identifier };\n return this.post<ForgotPasswordResponse>(this.config.endpoints.forgotPassword, payload);\n }\n\n /**\n * Confirm a password reset code and set a new password.\n */\n async confirmForgotPassword(\n identifier: string,\n code: string,\n newPassword: string,\n ): Promise<ConfirmForgotPasswordResponse> {\n const payload: ConfirmForgotPasswordRequest = { identifier, code, newPassword };\n const result = await this.post<ConfirmForgotPasswordResponse>(this.config.endpoints.confirmForgotPassword, payload);\n // ============================================================================\n // IMPORTANT: Password reset revokes all sessions\n // ============================================================================\n // WHY: The backend invalidates all sessions as a security measure. Clearing local auth state avoids\n // stale UI (e.g., still showing social-only/no-password state from cached user) and prevents the\n // client from attempting further authenticated calls with invalid tokens/cookies.\n await this.clearAuthState(false);\n return result;\n }\n\n /**\n * Request password change (must change on next login).\n */\n async requestPasswordChange(): Promise<void> {\n await this.post(this.config.endpoints.requestPasswordChange, {}, true);\n }\n\n /**\n * Get MFA status.\n */\n async getMfaStatus(): Promise<MFAStatus> {\n return this.get<MFAStatus>(this.config.endpoints.mfaStatus, true);\n }\n\n /**\n * Get MFA devices.\n */\n async getMfaDevices(): Promise<unknown[]> {\n return this.get<unknown[]>(this.config.endpoints.mfaDevices, true);\n }\n\n /**\n * Setup MFA device (authenticated user).\n */\n async setupMfaDevice(method: string): Promise<unknown> {\n return this.post<unknown>(this.config.endpoints.mfaSetupData, { method }, true);\n }\n\n /**\n * Verify MFA setup (authenticated user).\n */\n async verifyMfaSetup(\n method: string,\n setupData: Record<string, unknown>,\n deviceName?: string,\n ): Promise<{ deviceId: number }> {\n return this.post<{ deviceId: number }>(\n this.config.endpoints.mfaVerifySetup,\n { method, setupData, deviceName },\n true,\n );\n }\n\n /**\n * Remove MFA method.\n */\n async removeMfaDevice(method: string): Promise<{ message: string }> {\n const path = `${this.config.endpoints.mfaRemove}/${method}`;\n return this.delete<{ message: string }>(path, true);\n }\n\n /**\n * Set preferred MFA method.\n *\n * @param method - Device method to set as preferred ('totp', 'sms', 'email', or 'passkey'). Cannot be 'backup'.\n * @returns Success message\n */\n async setPreferredMfaMethod(method: 'totp' | 'sms' | 'email' | 'passkey'): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.mfaPreferred, { method }, true);\n }\n\n /**\n * Generate backup codes.\n */\n async generateBackupCodes(): Promise<string[]> {\n const result = await this.post<{ codes: string[] }>(this.config.endpoints.mfaBackupCodes, {}, true);\n return result.codes;\n }\n\n /**\n * Set MFA exemption (admin/test scenarios).\n */\n async setMfaExemption(exempt: boolean, reason?: string): Promise<void> {\n await this.post(this.config.endpoints.mfaExemption, { exempt, reason }, true);\n }\n\n // ============================================================================\n // Event System\n // ============================================================================\n\n /**\n * Subscribe to authentication events.\n *\n * Emits events throughout the auth lifecycle for custom logic, analytics, or UI updates.\n *\n * @param event - Event type to listen for, or '*' for all events\n * @param listener - Callback function to handle the event\n * @returns Unsubscribe function\n *\n * @example\n * ```typescript\n * // Listen to successful authentication\n * const unsubscribe = client.on('auth:success', (event) => {\n * console.log('User logged in:', event.data.user);\n * analytics.track('login_success');\n * });\n *\n * // Listen to all events\n * client.on('*', (event) => {\n * console.log('Auth event:', event.type, event.data);\n * });\n *\n * // Unsubscribe when done\n * unsubscribe();\n * ```\n */\n on(event: AuthEventType | '*', listener: AuthEventListener): () => void {\n return this.eventEmitter.on(event, listener);\n }\n\n /**\n * Unsubscribe from authentication events.\n *\n * @param event - Event type\n * @param listener - Callback function to remove\n */\n off(event: AuthEventType | '*', listener: AuthEventListener): void {\n this.eventEmitter.off(event, listener);\n }\n\n // ============================================================================\n // Social Authentication\n // ============================================================================\n\n /**\n * Start redirect-first social OAuth flow (web).\n *\n * This performs a browser navigation to:\n * `GET {baseUrl}/social/:provider/redirect?returnTo=...&appState=...`\n *\n * The backend:\n * - generates and stores CSRF state (cluster-safe)\n * - redirects the user to the provider\n * - completes OAuth on callback and sets cookies (or issues an exchange token)\n * - redirects back to `returnTo` with `appState` (and `exchangeToken` for json/hybrid)\n *\n * @param provider - OAuth provider ('google', 'apple', 'facebook')\n * @param options - Optional redirect options\n *\n * @example\n * ```typescript\n * await client.loginWithSocial('google', { returnTo: '/auth/callback', appState: '12345' });\n * ```\n */\n async loginWithSocial(provider: SocialProvider, options?: SocialLoginOptions): Promise<void> {\n // Emit event\n this.eventEmitter.emit({ type: 'oauth:started', data: { provider }, timestamp: Date.now() });\n\n if (hasWindow()) {\n const startPath = this.config.endpoints.socialRedirectStart.replace(':provider', provider);\n const base = this.config.baseUrl.replace(/\\/$/, '');\n const startUrl = new URL(`${base}${startPath}`);\n\n const returnTo = options?.returnTo ?? this.config.redirects?.success ?? '/';\n\n startUrl.searchParams.set('returnTo', returnTo);\n // Only include action when deviating from the default ('login').\n if (options?.action === 'link') {\n startUrl.searchParams.set('action', 'link');\n }\n if (typeof options?.appState === 'string' && options.appState.trim() !== '') {\n startUrl.searchParams.set('appState', options.appState);\n }\n\n window.location.href = startUrl.toString();\n }\n }\n\n /**\n * Exchange an `exchangeToken` (from redirect callback URL) into an AuthResponse.\n *\n * Used for `tokenDelivery: 'json'` or hybrid flows where the backend redirects back\n * with `exchangeToken` instead of setting cookies.\n *\n * @param exchangeToken - One-time exchange token from the callback URL\n * @returns AuthResponse\n */\n async exchangeSocialRedirect(exchangeToken: string): Promise<AuthResponse> {\n const token = exchangeToken?.trim();\n if (!token) {\n throw new NAuthClientError(NAuthErrorCode.CHALLENGE_INVALID, 'Missing exchangeToken');\n }\n const result = await this.post<AuthResponse>(this.config.endpoints.socialExchange, { exchangeToken: token });\n await this.handleAuthResponse(result);\n return result;\n }\n\n /**\n * Verify native social token (mobile).\n */\n async verifyNativeSocial(request: SocialVerifyRequest): Promise<AuthResponse> {\n try {\n const path = this.config.endpoints.socialVerify.replace(':provider', request.provider);\n const result = await this.post<AuthResponse>(path, request);\n await this.handleAuthResponse(result);\n\n // Emit success or challenge event\n if (result.challengeName) {\n const challengeEvent = { type: 'auth:challenge' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(challengeEvent);\n } else {\n const successEvent = { type: 'auth:success' as const, data: result, timestamp: Date.now() };\n this.eventEmitter.emit(successEvent);\n }\n\n return result;\n } catch (error) {\n const authError =\n error instanceof NAuthClientError\n ? error\n : new NAuthClientError(\n NAuthErrorCode.SOCIAL_TOKEN_INVALID,\n (error as Error).message || 'Social verification failed',\n );\n const errorEvent = { type: 'auth:error' as const, data: authError, timestamp: Date.now() };\n this.eventEmitter.emit(errorEvent);\n throw authError;\n }\n }\n\n /**\n * Get linked accounts.\n */\n async getLinkedAccounts(): Promise<LinkedAccountsResponse> {\n return this.get<LinkedAccountsResponse>(this.config.endpoints.socialLinked, true);\n }\n\n /**\n * Link social account.\n */\n async linkSocialAccount(provider: string, code: string, state: string): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.socialLink, { provider, code, state }, true);\n }\n\n /**\n * Unlink social account.\n */\n async unlinkSocialAccount(provider: string): Promise<{ message: string }> {\n return this.post<{ message: string }>(this.config.endpoints.socialUnlink, { provider }, true);\n }\n\n /**\n * Trust current device.\n */\n async trustDevice(): Promise<{ deviceToken: string }> {\n const result = await this.post<{ deviceToken: string }>(this.config.endpoints.trustDevice, {}, true);\n await this.setDeviceToken(result.deviceToken);\n return result;\n }\n\n /**\n * Check if the current device is trusted.\n *\n * Returns whether the current device is trusted based on the device token\n * (from cookie in cookies mode, or header in JSON mode).\n *\n * This performs a server-side validation of the device token and checks:\n * - Device token exists and is valid\n * - Device token matches a trusted device record in the database\n * - Trust has not expired\n *\n * @returns Object with trusted status\n *\n * @example\n * ```typescript\n * const result = await client.isTrustedDevice();\n * if (result.trusted) {\n * console.log('This device is trusted');\n * }\n * ```\n */\n async isTrustedDevice(): Promise<{ trusted: boolean }> {\n return this.get<{ trusted: boolean }>(this.config.endpoints.isTrustedDevice, true);\n }\n\n /**\n * Get paginated audit history for the current user.\n *\n * Returns authentication and security events with full audit details including:\n * - Event type (login, logout, MFA, etc.)\n * - Event status (success, failure, suspicious)\n * - Device information, location, risk factors\n *\n * @param params - Query parameters for filtering and pagination\n * @returns Paginated audit history response\n *\n * @example\n * ```typescript\n * const history = await client.getAuditHistory({\n * page: 1,\n * limit: 20,\n * eventType: 'LOGIN_SUCCESS'\n * });\n * ```\n */\n async getAuditHistory(params?: Record<string, string | number | boolean>): Promise<AuditHistoryResponse> {\n const entries: [string, string][] = Object.entries(params ?? {}).map(([k, v]) => [k, String(v)]);\n const query = entries.length > 0 ? `?${new URLSearchParams(entries).toString()}` : '';\n const path = `${this.config.endpoints.auditHistory}${query}`;\n return this.get<AuditHistoryResponse>(path, true);\n }\n\n /**\n * Initialize client by hydrating state from storage.\n * Call this on app startup to restore auth state.\n */\n async initialize(): Promise<void> {\n const userJson = await this.config.storage.getItem(USER_KEY);\n if (userJson) {\n try {\n this.currentUser = JSON.parse(userJson) as AuthUser;\n this.config.onAuthStateChange?.(this.currentUser);\n } catch {\n // Invalid stored user - clear it\n await this.config.storage.removeItem(USER_KEY);\n }\n }\n }\n\n /**\n * Determine if user is authenticated (async - checks tokens).\n */\n async isAuthenticated(): Promise<boolean> {\n const tokens = await this.tokenManager.getTokens();\n return Boolean(tokens.accessToken);\n }\n\n /**\n * Determine if user is authenticated (sync - checks cached user).\n * Use this for guards and sync checks. Use `isAuthenticated()` for definitive check.\n */\n isAuthenticatedSync(): boolean {\n return this.currentUser !== null;\n }\n\n /**\n * Get current access token (may be null).\n */\n async getAccessToken(): Promise<string | null> {\n const tokens = await this.tokenManager.getTokens();\n return tokens.accessToken ?? null;\n }\n\n /**\n * Get current user (cached, sync).\n */\n getCurrentUser(): AuthUser | null {\n return this.currentUser;\n }\n\n /**\n * Get stored challenge session (for resuming challenge flows).\n */\n async getStoredChallenge(): Promise<AuthResponse | null> {\n const raw = await this.config.storage.getItem(CHALLENGE_KEY);\n if (!raw) return null;\n try {\n return JSON.parse(raw) as AuthResponse;\n } catch {\n return null;\n }\n }\n\n /**\n * Clear stored challenge session.\n */\n async clearStoredChallenge(): Promise<void> {\n await this.config.storage.removeItem(CHALLENGE_KEY);\n }\n\n /**\n * Internal: handle auth response (tokens or challenge).\n *\n * In cookies mode: Tokens are set as httpOnly cookies by backend, not stored in client storage.\n * In JSON mode: Tokens are stored in tokenManager for Authorization header.\n */\n private async handleAuthResponse(response: AuthResponse): Promise<void> {\n if (response.challengeName) {\n await this.persistChallenge(response);\n return;\n }\n\n // Only store tokens in JSON mode (cookies mode uses httpOnly cookies set by backend)\n if (this.config.tokenDelivery === 'json' && response.accessToken && response.refreshToken) {\n await this.tokenManager.setTokens({\n accessToken: response.accessToken,\n refreshToken: response.refreshToken,\n accessTokenExpiresAt: response.accessTokenExpiresAt ?? 0,\n refreshTokenExpiresAt: response.refreshTokenExpiresAt ?? 0,\n });\n }\n\n // Device token handling (only for JSON mode - cookies mode uses httpOnly cookie)\n if (this.config.tokenDelivery === 'json' && response.deviceToken) {\n await this.setDeviceToken(response.deviceToken);\n }\n\n // Always store user info (needed for both modes)\n if (response.user) {\n const user = response.user as AuthUser;\n // WHY: Consumers often need to know if the current session was created via password\n // or via a specific social provider (google/apple/facebook).\n user.sessionAuthMethod = response.authMethod ?? null;\n await this.setUser(user);\n }\n\n await this.clearChallenge();\n }\n\n /**\n * Persist challenge state.\n */\n private async persistChallenge(challenge: AuthResponse): Promise<void> {\n await this.config.storage.setItem(CHALLENGE_KEY, JSON.stringify(challenge));\n }\n\n /**\n * Clear challenge state.\n */\n private async clearChallenge(): Promise<void> {\n await this.config.storage.removeItem(CHALLENGE_KEY);\n }\n\n /**\n * Persist user.\n */\n private async setUser(user: AuthUser): Promise<void> {\n this.currentUser = user;\n await this.config.storage.setItem(USER_KEY, JSON.stringify(user));\n this.config.onAuthStateChange?.(user);\n }\n\n /**\n * Clear all auth state.\n *\n * @param forgetDevice - If true, also clear device token (for JSON mode)\n */\n private async clearAuthState(forgetDevice?: boolean): Promise<void> {\n this.currentUser = null;\n await this.tokenManager.clearTokens();\n await this.config.storage.removeItem(USER_KEY);\n\n // Clear device token in JSON mode (cookies mode uses httpOnly cookie cleared by backend)\n if (forgetDevice && this.config.tokenDelivery === 'json') {\n await this.config.storage.removeItem(this.config.deviceTrust.storageKey);\n }\n\n this.config.onAuthStateChange?.(null);\n }\n\n /**\n * Persist device token (json mode mobile).\n */\n private async setDeviceToken(token: string): Promise<void> {\n await this.config.storage.setItem(this.config.deviceTrust.storageKey, token);\n }\n\n /**\n * Determine token delivery mode for this environment.\n */\n private getTokenDeliveryMode(): 'json' | 'cookies' {\n return this.config.tokenDelivery;\n }\n\n /**\n * Build request URL by combining baseUrl with path.\n * @private\n */\n private buildUrl(path: string): string {\n return `${this.config.baseUrl}${path}`;\n }\n\n /**\n * Build request headers for authentication.\n * @private\n */\n private async buildHeaders(auth: boolean): Promise<Record<string, string>> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...this.config.headers,\n };\n\n // Add access token in JSON mode\n if (auth && this.config.tokenDelivery === 'json') {\n const accessToken = (await this.tokenManager.getTokens()).accessToken;\n if (accessToken) {\n headers['Authorization'] = `Bearer ${accessToken}`;\n }\n }\n\n // ============================================================================\n // Trusted Device Header (JSON mode)\n // ============================================================================\n // In cookies mode the device token is sent automatically via httpOnly cookie.\n // In JSON mode the backend expects the device token via a header (default: X-Device-Token).\n //\n // This is required for:\n // - Checking trust status (`isTrustedDevice`)\n // - Skipping MFA on future logins when a device is trusted\n //\n // We intentionally send it on all requests in JSON mode so the backend can\n // consistently associate requests with a trusted device when present.\n if (this.config.tokenDelivery === 'json') {\n try {\n const deviceToken = await this.config.storage.getItem(this.config.deviceTrust.storageKey);\n if (deviceToken) {\n headers[this.config.deviceTrust.headerName] = deviceToken;\n }\n } catch {\n // Non-fatal: storage can fail in restricted environments (private mode, SSR, etc.).\n }\n }\n\n // Add CSRF token for mutating requests in cookies mode\n if (this.config.tokenDelivery === 'cookies' && hasWindow()) {\n const csrfToken = this.getCsrfToken();\n if (csrfToken) {\n headers[this.config.csrf.headerName] = csrfToken;\n }\n }\n\n return headers;\n }\n\n /**\n * Get CSRF token from cookie (browser only).\n * @private\n */\n private getCsrfToken(): string | null {\n if (!hasWindow() || typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(^| )${this.config.csrf.cookieName}=([^;]+)`));\n return match ? decodeURIComponent(match[2]) : null;\n }\n\n /**\n * Execute GET request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async get<T>(path: string, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'GET',\n url,\n headers,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute POST request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async post<T>(path: string, body: unknown, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'POST',\n url,\n headers,\n body,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute PUT request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async put<T>(path: string, body: unknown, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'PUT',\n url,\n headers,\n body,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Execute DELETE request.\n * Note: 401 refresh is handled by framework interceptors (Angular) or manually.\n */\n private async delete<T>(path: string, auth = false): Promise<T> {\n const url = this.buildUrl(path);\n const headers = await this.buildHeaders(auth);\n const credentials = this.config.tokenDelivery === 'cookies' ? 'include' : 'omit';\n\n const response = await this.config.httpAdapter.request<T>({\n method: 'DELETE',\n url,\n headers,\n credentials,\n });\n return response.data;\n }\n\n /**\n * Handle cross-tab storage updates.\n */\n private readonly handleStorageEvent = (event: StorageEvent): void => {\n if (event.key === 'nauth_sync') {\n // Best-effort reload of user state\n this.config.storage\n .getItem(USER_KEY)\n .then((value: string | null) => (value ? (JSON.parse(value) as AuthUser) : null))\n .then((user: AuthUser | null) => {\n this.currentUser = user;\n this.config.onAuthStateChange?.(user);\n })\n .catch(() => {\n // ignore\n });\n }\n };\n}\n","import { inject, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { HttpHandlerFn, HttpInterceptorFn, HttpRequest, HttpClient, HttpErrorResponse } from '@angular/common/http';\nimport { Router } from '@angular/router';\nimport { catchError, switchMap, throwError, filter, take, BehaviorSubject, from } from 'rxjs';\nimport { NAUTH_CLIENT_CONFIG } from './tokens';\nimport { AuthService } from './auth.service';\n\n/**\n * Refresh state management.\n * BehaviorSubject pattern is the industry-standard for token refresh.\n */\nlet isRefreshing = false;\nconst refreshTokenSubject = new BehaviorSubject<string | null>(null);\n\n/**\n * Track retried requests to prevent infinite loops.\n */\nconst retriedRequests = new WeakSet<HttpRequest<unknown>>();\n\n/**\n * Get CSRF token from cookie.\n */\nfunction getCsrfToken(cookieName: string): string | null {\n if (typeof document === 'undefined') return null;\n const match = document.cookie.match(new RegExp(`(^| )${cookieName}=([^;]+)`));\n return match ? decodeURIComponent(match[2]) : null;\n}\n\n/**\n * Angular HTTP interceptor for nauth-toolkit.\n *\n * Handles:\n * - Cookies mode: withCredentials + CSRF tokens + refresh via POST\n * - JSON mode: refresh via SDK, retry with new token\n */\nexport const authInterceptor: HttpInterceptorFn = (req: HttpRequest<unknown>, next: HttpHandlerFn) => {\n const config = inject(NAUTH_CLIENT_CONFIG);\n const http = inject(HttpClient);\n const authService = inject(AuthService);\n const platformId = inject(PLATFORM_ID);\n const router = inject(Router);\n const isBrowser = isPlatformBrowser(platformId);\n\n if (!isBrowser) {\n return next(req);\n }\n\n const tokenDelivery = config.tokenDelivery;\n const baseUrl = config.baseUrl;\n const endpoints = config.endpoints ?? {};\n const refreshPath = endpoints.refresh ?? '/refresh';\n const loginPath = endpoints.login ?? '/login';\n const signupPath = endpoints.signup ?? '/signup';\n const socialExchangePath = endpoints.socialExchange ?? '/social/exchange';\n const refreshUrl = `${baseUrl}${refreshPath}`;\n\n const isAuthApiRequest = req.url.includes(baseUrl);\n const isRefreshEndpoint = req.url.includes(refreshPath);\n const isPublicEndpoint =\n req.url.includes(loginPath) || req.url.includes(signupPath) || req.url.includes(socialExchangePath);\n\n // Build request with credentials (cookies mode only)\n let authReq = req;\n if (tokenDelivery === 'cookies') {\n authReq = authReq.clone({ withCredentials: true });\n\n if (['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method)) {\n const csrfCookieName = config.csrf?.cookieName ?? 'nauth_csrf_token';\n const csrfHeaderName = config.csrf?.headerName ?? 'x-csrf-token';\n const csrfToken = getCsrfToken(csrfCookieName);\n if (csrfToken) {\n authReq = authReq.clone({ setHeaders: { [csrfHeaderName]: csrfToken } });\n }\n }\n }\n\n return next(authReq).pipe(\n catchError((error: unknown) => {\n const shouldHandle =\n error instanceof HttpErrorResponse &&\n error.status === 401 &&\n isAuthApiRequest &&\n !isRefreshEndpoint &&\n !isPublicEndpoint &&\n !retriedRequests.has(req);\n\n if (!shouldHandle) {\n return throwError(() => error);\n }\n\n if (config.debug) {\n console.warn('[nauth-interceptor] 401 detected:', req.url);\n }\n\n if (!isRefreshing) {\n isRefreshing = true;\n refreshTokenSubject.next(null);\n\n if (config.debug) {\n console.warn('[nauth-interceptor] Starting refresh...');\n }\n\n // Refresh based on mode\n const refresh$ =\n tokenDelivery === 'cookies'\n ? http.post<{ accessToken?: string }>(refreshUrl, {}, { withCredentials: true })\n : from(authService.refreshTokensPromise());\n\n return refresh$.pipe(\n switchMap((response) => {\n if (config.debug) {\n console.warn('[nauth-interceptor] Refresh successful');\n }\n isRefreshing = false;\n\n // Get new token (JSON mode) or signal success (cookies mode)\n const newToken = 'accessToken' in response ? response.accessToken : 'success';\n refreshTokenSubject.next(newToken ?? 'success');\n\n // Build retry request\n const retryReq = buildRetryRequest(authReq, tokenDelivery, newToken);\n retriedRequests.add(retryReq);\n\n if (config.debug) {\n console.warn('[nauth-interceptor] Retrying:', req.url);\n }\n return next(retryReq);\n }),\n catchError((err) => {\n if (config.debug) {\n console.error('[nauth-interceptor] Refresh failed:', err);\n }\n isRefreshing = false;\n refreshTokenSubject.next(null);\n\n // Handle session expiration - redirect to configured URL\n if (config.redirects?.sessionExpired) {\n router.navigateByUrl(config.redirects.sessionExpired).catch((navError) => {\n if (config.debug) {\n console.error('[nauth-interceptor] Navigation failed:', navError);\n }\n });\n }\n\n return throwError(() => err);\n }),\n );\n } else {\n // Wait for ongoing refresh\n if (config.debug) {\n console.warn('[nauth-interceptor] Waiting for refresh...');\n }\n return refreshTokenSubject.pipe(\n filter((token): token is string => token !== null),\n take(1),\n switchMap((token) => {\n if (config.debug) {\n console.warn('[nauth-interceptor] Refresh done, retrying:', req.url);\n }\n const retryReq = buildRetryRequest(authReq, tokenDelivery, token);\n retriedRequests.add(retryReq);\n return next(retryReq);\n }),\n );\n }\n }),\n );\n};\n\n/**\n * Build retry request with appropriate auth.\n */\nfunction buildRetryRequest(\n originalReq: HttpRequest<unknown>,\n tokenDelivery: string,\n newToken?: string,\n): HttpRequest<unknown> {\n if (tokenDelivery === 'json' && newToken && newToken !== 'success') {\n return originalReq.clone({\n setHeaders: { Authorization: `Bearer ${newToken}` },\n });\n }\n return originalReq.clone();\n}\n\n/**\n * Class-based interceptor for NgModule compatibility.\n */\nexport class AuthInterceptor {\n intercept(req: HttpRequest<unknown>, next: HttpHandlerFn) {\n return authInterceptor(req, next);\n }\n}\n","import { inject } from '@angular/core';\nimport { CanActivateFn, Router, UrlTree } from '@angular/router';\nimport { AuthService } from './auth.service';\n\n/**\n * Functional route guard for authentication (Angular 17+).\n *\n * Protects routes by checking if user is authenticated.\n * Redirects to login page if not authenticated.\n *\n * @param redirectTo - Path to redirect to if not authenticated (default: '/login')\n * @returns CanActivateFn guard function\n *\n * @example\n * ```typescript\n * // In route configuration\n * const routes: Routes = [\n * {\n * path: 'home',\n * component: HomeComponent,\n * canActivate: [authGuard()]\n * },\n * {\n * path: 'admin',\n * component: AdminComponent,\n * canActivate: [authGuard('/admin/login')]\n * }\n * ];\n * ```\n */\nexport function authGuard(redirectTo = '/login'): CanActivateFn {\n return (): boolean | UrlTree => {\n const auth = inject(AuthService);\n const router = inject(Router);\n\n if (auth.isAuthenticated()) {\n return true;\n }\n\n return router.createUrlTree([redirectTo]);\n };\n}\n\n/**\n * Class-based authentication guard for NgModule compatibility.\n *\n * @example\n * ```typescript\n * // In route configuration (NgModule)\n * const routes: Routes = [\n * {\n * path: 'home',\n * component: HomeComponent,\n * canActivate: [AuthGuard]\n * }\n * ];\n *\n * // In module providers\n * @NgModule({\n * providers: [AuthGuard]\n * })\n * ```\n */\nexport class AuthGuard {\n /**\n * @param auth - Authentication service\n * @param router - Angular router\n */\n constructor(\n private auth: AuthService,\n private router: Router,\n ) {}\n\n /**\n * Check if route can be activated.\n *\n * @returns True if authenticated, otherwise redirects to login\n */\n canActivate(): boolean | UrlTree {\n if (this.auth.isAuthenticated()) {\n return true;\n }\n\n return this.router.createUrlTree(['/login']);\n }\n}\n","import { inject, PLATFORM_ID } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { type CanActivateFn } from '@angular/router';\nimport { AuthService } from './auth.service';\nimport { NAUTH_CLIENT_CONFIG } from './tokens';\n\n/**\n * Social redirect callback route guard.\n *\n * This guard supports the redirect-first social flow where the backend redirects\n * back to the frontend with:\n * - `appState` (always optional)\n * - `exchangeToken` (present for json/hybrid flows, and for cookie flows that return a challenge)\n * - `error` / `error_description` (provider errors)\n *\n * Behavior:\n * - If `exchangeToken` exists: exchanges it via backend and redirects to success or challenge routes.\n * - If no `exchangeToken`: treat as cookie-success path and redirect to success route.\n * - If `error` exists: redirects to oauthError route.\n *\n * @example\n * ```typescript\n * import { socialRedirectCallbackGuard } from '@nauth-toolkit/client/angular';\n *\n * export const routes: Routes = [\n * { path: 'auth/callback', canActivate: [socialRedirectCallbackGuard], component: CallbackComponent },\n * ];\n * ```\n */\nexport const socialRedirectCallbackGuard: CanActivateFn = async (): Promise<boolean> => {\n const auth = inject(AuthService);\n const config = inject(NAUTH_CLIENT_CONFIG);\n const platformId = inject(PLATFORM_ID);\n const isBrowser = isPlatformBrowser(platformId);\n\n if (!isBrowser) {\n return false;\n }\n\n const params = new URLSearchParams(window.location.search);\n const error = params.get('error');\n const exchangeToken = params.get('exchangeToken');\n\n // Provider error: redirect to oauthError\n if (error) {\n const errorUrl = config.redirects?.oauthError || '/login';\n window.location.replace(errorUrl);\n return false;\n }\n\n // No exchangeToken: cookie success path; redirect to success.\n //\n // Note: we do not \"activate\" the callback route to avoid consumers needing to render a page.\n if (!exchangeToken) {\n // ============================================================================\n // Cookies mode: hydrate user state before redirecting\n // ============================================================================\n // WHY: In cookie delivery, the OAuth callback completes via browser redirects, so the frontend\n // does not receive a JSON AuthResponse to populate the SDK's cached `currentUser`.\n //\n // Without this, sync guards (`authGuard`) can immediately redirect to /login because\n // `currentUser` is still null even though cookies were set successfully.\n try {\n await auth.getProfilePromise();\n } catch {\n const errorUrl = config.redirects?.oauthError || '/login';\n window.location.replace(errorUrl);\n return false;\n }\n const successUrl = config.redirects?.success || '/';\n window.location.replace(successUrl);\n return false;\n }\n\n // Exchange token and route accordingly\n const response = await auth.exchangeSocialRedirectPromise(exchangeToken);\n if (response.challengeName) {\n const challengeBase = config.redirects?.challengeBase || '/auth/challenge';\n const challengeRoute = response.challengeName.toLowerCase().replace(/_/g, '-');\n window.location.replace(`${challengeBase}/${challengeRoute}`);\n return false;\n }\n\n const successUrl = config.redirects?.success || '/';\n window.location.replace(successUrl);\n return false;\n};\n","import { ModuleWithProviders, NgModule } from '@angular/core';\nimport { HTTP_INTERCEPTORS } from '@angular/common/http';\nimport { NAUTH_CLIENT_CONFIG } from './tokens';\nimport { AuthInterceptor } from './auth.interceptor';\nimport { NAuthClientConfig } from '../types/config.types';\n\n/**\n * NgModule wrapper to provide configuration and interceptor.\n */\n@NgModule({})\nexport class NAuthModule {\n /**\n * Configure the module with client settings.\n *\n * @param config - Client configuration\n */\n static forRoot(config: NAuthClientConfig): ModuleWithProviders<NAuthModule> {\n return {\n ngModule: NAuthModule,\n providers: [\n { provide: NAUTH_CLIENT_CONFIG, useValue: config },\n { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },\n ],\n };\n }\n}\n"],"mappings":"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","names":["import_core","import_rxjs","import_core","USER_KEY","CHALLENGE_KEY","import_core","import_http","import_rxjs","import_core","import_router","import_core","import_common","successUrl","import_core","import_http"]}