@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
TypeScript
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 };