UNPKG

@acontplus/ng-auth

Version:

Comprehensive Angular authentication module with JWT token management, route guards, CSRF protection, URL redirection, session handling, and clean architecture patterns. Includes login components, auth interceptors, and DDD-based repositories.

284 lines (266 loc) 10.9 kB
import { AuthTokenRepository } from '@acontplus/ng-config'; export { AUTH_TOKEN, AuthTokenRepository } from '@acontplus/ng-config'; import { Observable } from 'rxjs'; import { BaseUseCase } from '@acontplus/ng-infrastructure'; import { AuthTokens, UserData } from '@acontplus/core'; import * as i0 from '@angular/core'; import { Provider, OnDestroy, OnInit, TemplateRef } from '@angular/core'; import { CanActivateFn } from '@angular/router'; import { HttpInterceptorFn, HttpContextToken } from '@angular/common/http'; import { AbstractControl, FormGroup } from '@angular/forms'; interface LoginRequest { email: string; password: string; rememberMe?: boolean; } interface RegisterRequest { email: string; displayName: string; password: string; } interface RefreshTokenRequest { email: string; refreshToken: string; } declare class LoginUseCase extends BaseUseCase<LoginRequest, AuthTokens> { private readonly authRepository; private readonly authStore; private readonly router; private readonly urlRedirectService; execute(request: LoginRequest): Observable<AuthTokens>; static ɵfac: i0.ɵɵFactoryDeclaration<LoginUseCase, never>; static ɵprov: i0.ɵɵInjectableDeclaration<LoginUseCase>; } declare class RegisterUseCase extends BaseUseCase<RegisterRequest, AuthTokens> { private readonly authRepository; private readonly authStore; private readonly router; execute(request: RegisterRequest): Observable<AuthTokens>; static ɵfac: i0.ɵɵFactoryDeclaration<RegisterUseCase, never>; static ɵprov: i0.ɵɵInjectableDeclaration<RegisterUseCase>; } declare class RefreshTokenUseCase extends BaseUseCase<void, AuthTokens> { private readonly authRepository; private readonly tokenRepository; private readonly authStore; execute(): Observable<AuthTokens>; static ɵfac: i0.ɵɵFactoryDeclaration<RefreshTokenUseCase, never>; static ɵprov: i0.ɵɵInjectableDeclaration<RefreshTokenUseCase>; } declare class LogoutUseCase extends BaseUseCase<void, void> { private readonly authRepository; private readonly tokenRepository; private readonly authStore; execute(): Observable<void>; private cleanup; static ɵfac: i0.ɵɵFactoryDeclaration<LogoutUseCase, never>; static ɵprov: i0.ɵɵInjectableDeclaration<LogoutUseCase>; } declare abstract class AuthRepository { abstract login(request: LoginRequest): Observable<AuthTokens>; abstract register(request: RegisterRequest): Observable<AuthTokens>; abstract refreshToken(request: RefreshTokenRequest): Observable<AuthTokens>; abstract logout(email: string, refreshToken: string): Observable<void>; } declare class AuthHttpRepository extends AuthRepository { private readonly http; private readonly URL; login(request: LoginRequest): Observable<AuthTokens>; register(request: RegisterRequest): Observable<AuthTokens>; refreshToken(request: RefreshTokenRequest): Observable<AuthTokens>; logout(email: string, refreshToken: string): Observable<void>; static ɵfac: i0.ɵɵFactoryDeclaration<AuthHttpRepository, never>; static ɵprov: i0.ɵɵInjectableDeclaration<AuthHttpRepository>; } declare const authGuard: CanActivateFn; /** * Interceptor that handles authentication errors and manages URL redirection * Captures the current URL when a 401 error occurs and redirects to login */ declare const authRedirectInterceptor: HttpInterceptorFn; declare const SKIP_CSRF: HttpContextToken<boolean>; /** * HTTP interceptor that automatically adds CSRF tokens to state-changing requests * Only applies to requests to the same origin to avoid leaking tokens to external APIs */ declare const csrfInterceptor: HttpInterceptorFn; declare const authProviders: Provider[]; declare class AuthTokenRepositoryImpl implements AuthTokenRepository { private environment; private platformId; saveTokens(tokens: AuthTokens, rememberMe?: boolean): void; getToken(): string | null; getRefreshToken(): string | null; setToken(token: string, rememberMe?: boolean): void; setRefreshToken(refreshToken: string, rememberMe?: boolean): void; clearTokens(): void; isAuthenticated(): boolean; needsRefresh(): boolean; getTokenPayload(): unknown; /** * Determines if tokens are stored persistently (localStorage) vs session (sessionStorage) */ isRememberMeEnabled(): boolean; getUserData(): UserData | null; /** * Extract array field from decoded token, trying multiple possible field names */ private extractArrayField; static ɵfac: i0.ɵɵFactoryDeclaration<AuthTokenRepositoryImpl, never>; static ɵprov: i0.ɵɵInjectableDeclaration<AuthTokenRepositoryImpl>; } /** * Service to manage URL redirection after authentication * Stores the intended URL when session is lost and redirects to it after successful login * SSR-compatible by checking platform before accessing sessionStorage */ declare class AuthUrlRedirect { private readonly REDIRECT_URL_KEY; private readonly EXCLUDED_ROUTES; private readonly router; private readonly platformId; private readonly document; /** * Stores the current URL for later redirection * @param url - The URL to store (defaults to current URL) */ storeIntendedUrl(url?: string): void; /** * Gets the stored intended URL * @returns The stored URL or null if none exists */ getIntendedUrl(): string | null; /** * Redirects to the stored URL and clears it from storage * @param defaultRoute - The default route to navigate to if no URL is stored */ redirectToIntendedUrl(defaultRoute?: string): void; /** * Clears the stored intended URL */ clearIntendedUrl(): void; /** * Checks if a URL should be excluded from redirection * @param url - The URL to check * @returns True if the URL should be excluded */ private isExcludedRoute; /** * Stores the current URL if it's not an excluded route * Useful for guards and interceptors */ storeCurrentUrlIfAllowed(): void; /** * Checks if we're running in a browser environment * @returns True if running in browser, false if SSR */ private isBrowser; /** * Safely gets sessionStorage reference * @returns sessionStorage object or null if not available */ private getSessionStorage; static ɵfac: i0.ɵɵFactoryDeclaration<AuthUrlRedirect, never>; static ɵprov: i0.ɵɵInjectableDeclaration<AuthUrlRedirect>; } declare class CsrfApi { private http; private csrfToken; /** * Get CSRF token, fetching it if not available */ getCsrfToken(): Promise<string>; /** * Clear stored CSRF token (useful on logout) */ clearCsrfToken(): void; static ɵfac: i0.ɵɵFactoryDeclaration<CsrfApi, never>; static ɵprov: i0.ɵɵInjectableDeclaration<CsrfApi>; } declare class AuthStore implements OnDestroy { private readonly authRepository; private readonly tokenRepository; private readonly router; private readonly ngZone; private readonly _isAuthenticated; private readonly _isLoading; private readonly _user; readonly isAuthenticated: i0.Signal<boolean>; readonly isLoading: i0.Signal<boolean>; readonly user: i0.Signal<UserData | null>; private refreshTokenTimeout?; private refreshInProgress$?; constructor(); /** * Initialize authentication state on app startup */ private initializeAuthentication; /** * Schedule token refresh based on actual expiration time */ private scheduleTokenRefresh; /** * Stop token refresh timer */ private stopTokenRefreshTimer; /** * Refresh authentication tokens */ refreshToken(): Observable<AuthTokens | null>; /** * Set authentication state after successful login */ setAuthenticated(tokens: AuthTokens, rememberMe?: boolean): void; /** * Logout user and clear all authentication data */ logout(): void; /** * Perform client-side logout operations */ private performClientLogout; /** * Check if user is authenticated */ checkAuthentication(): boolean; /** * Decode JWT token */ private decodeToken; /** * Cleanup on store destruction */ ngOnDestroy(): void; static ɵfac: i0.ɵɵFactoryDeclaration<AuthStore, never>; static ɵprov: i0.ɵɵInjectableDeclaration<AuthStore>; } declare class Login implements OnInit { title: i0.InputSignal<string>; showRegisterButton: i0.InputSignal<boolean>; showRememberMe: i0.InputSignal<boolean>; additionalSigninControls: i0.InputSignal<Record<string, AbstractControl<any, any, any>>>; additionalSignupControls: i0.InputSignal<Record<string, AbstractControl<any, any, any>>>; additionalSigninFields: i0.InputSignal<TemplateRef<unknown> | null>; additionalSignupFields: i0.InputSignal<TemplateRef<unknown> | null>; footerContent: i0.InputSignal<TemplateRef<unknown> | null>; hasFooterContent: i0.Signal<boolean>; private readonly fb; private readonly authStore; private readonly loginUseCase; private readonly registerUseCase; private readonly loggingService; isLoginMode: i0.WritableSignal<boolean>; isLoading: i0.WritableSignal<boolean>; errorMessage: i0.WritableSignal<string | null>; signinForm: FormGroup; signupForm: FormGroup; constructor(); ngOnInit(): void; switchMode(): void; signIn(): void; registerUser(): void; static ɵfac: i0.ɵɵFactoryDeclaration<Login, never>; static ɵcmp: i0.ɵɵComponentDeclaration<Login, "acp-login", never, { "title": { "alias": "title"; "required": false; "isSignal": true; }; "showRegisterButton": { "alias": "showRegisterButton"; "required": false; "isSignal": true; }; "showRememberMe": { "alias": "showRememberMe"; "required": false; "isSignal": true; }; "additionalSigninControls": { "alias": "additionalSigninControls"; "required": false; "isSignal": true; }; "additionalSignupControls": { "alias": "additionalSignupControls"; "required": false; "isSignal": true; }; "additionalSigninFields": { "alias": "additionalSigninFields"; "required": false; "isSignal": true; }; "additionalSignupFields": { "alias": "additionalSignupFields"; "required": false; "isSignal": true; }; "footerContent": { "alias": "footerContent"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>; } export { AuthHttpRepository, AuthRepository, AuthStore, AuthTokenRepositoryImpl, AuthUrlRedirect, CsrfApi, Login, LoginUseCase, LogoutUseCase, RefreshTokenUseCase, RegisterUseCase, SKIP_CSRF, authGuard, authProviders, authRedirectInterceptor, csrfInterceptor }; export type { LoginRequest, RefreshTokenRequest, RegisterRequest };