import { Repository } from 'typeorm'; import { IUser } from '../interfaces/entities.interface'; import { BaseUser, BaseLoginAttempt, BaseMFADevice, BaseChallengeSession, BaseVerificationToken, BaseSocialAccount, BaseAuthAudit, BaseTrustedDevice, BaseSession } from '../entities'; import { PasswordService } from './password.service'; import { JwtService } from './jwt.service'; import { SessionService } from './session.service'; import { EmailVerificationService } from './email-verification.service'; import { PhoneVerificationService } from './phone-verification.service'; import { ClientInfoService } from './client-info.service'; import { ChallengeService } from './challenge.service'; import { AuthChallengeHelperService } from './auth-challenge-helper.service'; import { AccountLockoutStorageService } from '../storage/account-lockout-storage.service'; import { InternalAuthAuditService as AuthAuditService } from './auth-audit.service'; import { TrustedDeviceService } from './trusted-device.service'; import { MFAService } from './mfa.service'; import { SignupDTO } from '../dto/signup.dto'; import { LoginDTO } from '../dto/login.dto'; import { ChangePasswordDTO } from '../dto/change-password.dto'; import { ChangePasswordResponseDTO } from '../dto/change-password-response.dto'; import { UpdateUserAttributesDTO } from '../dto/update-user-attributes.dto'; import { UserResponseDTO } from '../dto/user-response.dto'; import { AuthResponseDTO, TokenResponse } from '../dto/auth-response.dto'; import { RespondChallengeDTO } from '../dto/respond-challenge.dto'; import { LogoutDTO } from '../dto/logout.dto'; import { LogoutResponseDTO } from '../dto/logout-response.dto'; import { LogoutAllDTO } from '../dto/logout-all.dto'; import { LogoutAllResponseDTO } from '../dto/logout-all-response.dto'; import { GetUserSessionsResponseDTO } from '../dto/get-user-sessions-response.dto'; import { LogoutSessionDTO } from '../dto/logout-session.dto'; import { LogoutSessionResponseDTO } from '../dto/logout-session-response.dto'; import { RefreshTokenDTO } from '../dto/refresh-token.dto'; import { ResendCodeDTO } from '../dto/resend-code.dto'; import { ResendCodeResponseDTO } from '../dto/resend-code-response.dto'; import { ValidateAccessTokenDTO } from '../dto/validate-access-token.dto'; import { ValidateAccessTokenResponseDTO } from '../dto/validate-access-token-response.dto'; import { ForgotPasswordDTO, ForgotPasswordResponseDTO } from '../dto/forgot-password.dto'; import { ConfirmForgotPasswordDTO, ConfirmForgotPasswordResponseDTO } from '../dto/confirm-forgot-password.dto'; import { TrustDeviceResponseDTO } from '../dto/trust-device-response.dto'; import { IsTrustedDeviceResponseDTO } from '../dto/is-trusted-device-response.dto'; import { GetUserAuthHistoryDTO } from '../dto/get-user-auth-history.dto'; import { GetUserAuthHistoryResponseDTO } from '../dto/admin-get-user-auth-history.dto'; import { PasswordResetService } from './password-reset.service'; import { SocialAuthService } from './social-auth.service'; import { HookRegistryService } from './hook-registry.service'; import { NAuthConfig } from '../interfaces/config.interface'; import { NAuthLogger } from '../utils/nauth-logger'; /** * Core user-facing authentication service * * This service implements **self-service** authentication flows for the currently authenticated user: * - Signup, login, challenge completion, refresh token rotation * - Logout / logout-all / logout-session (self-management) * - Profile management and password change (self-management) * * Admin-only operations (explicit targeting via `sub`) are intentionally owned by {@link AdminAuthService}. * * @example * ```typescript * // Login (self-service) * const result = await authService.login({ identifier: 'user@example.com', password: 'Password123!' }); * * // Refresh (self-service; cookies or JSON depending on config) * const refreshed = await authService.refreshToken({ refreshToken: '...' }); * ``` */ export declare class AuthService { private readonly userRepository; private readonly loginAttemptRepository; private readonly passwordService; private readonly jwtService; private readonly sessionService; private readonly challengeService; private readonly challengeHelper; private readonly emailVerificationService; private readonly clientInfoService; private readonly accountLockoutStorage; private readonly config; private readonly logger; private readonly hookRegistry; private readonly auditService?; private readonly phoneVerificationService?; private readonly mfaService?; private readonly mfaDeviceRepository?; private readonly trustedDeviceService?; private readonly passwordResetService?; private readonly socialAuthService?; private readonly sessionRepository?; private readonly verificationTokenRepository?; private readonly socialAccountRepository?; private readonly challengeSessionRepository?; private readonly authAuditRepository?; private readonly trustedDeviceRepository?; private readonly helpers; private readonly userService; constructor(userRepository: Repository, loginAttemptRepository: Repository, passwordService: PasswordService, jwtService: JwtService, sessionService: SessionService, challengeService: ChallengeService, challengeHelper: AuthChallengeHelperService, emailVerificationService: EmailVerificationService, clientInfoService: ClientInfoService, accountLockoutStorage: AccountLockoutStorageService, config: NAuthConfig, logger: NAuthLogger, hookRegistry: HookRegistryService, auditService?: AuthAuditService | undefined, // Optional - audit trail service (enabled via config.auditLogs.enabled) phoneVerificationService?: PhoneVerificationService | undefined, // Optional - only available when SMS provider is configured mfaService?: MFAService | undefined, // Optional - available when MFA modules are imported mfaDeviceRepository?: Repository | undefined, // Optional - available when MFA modules are imported trustedDeviceService?: TrustedDeviceService | undefined, // Optional - only available when rememberDevices is not 'never' passwordResetService?: PasswordResetService | undefined, // Optional - only available when configured by framework adapter socialAuthService?: SocialAuthService | undefined, // Optional - only available when social auth is configured sessionRepository?: Repository | undefined, // Optional - for cascade deletion verificationTokenRepository?: Repository | undefined, // Optional - for cascade deletion socialAccountRepository?: Repository | undefined, // Optional - for cascade deletion challengeSessionRepository?: Repository | undefined, // Optional - for cascade deletion authAuditRepository?: Repository | undefined, // Optional - for cascade deletion trustedDeviceRepository?: Repository | undefined); /** * Register a new user. * * Checks for duplicates (email, username, phone), validates password, hashes it, * creates the user, and returns tokens or a challenge if verification is required. * * @param dto - Signup payload * @returns Auth response with tokens or a verification challenge * @throws {NAuthException} If user exists, password is invalid, or signup is disabled * * @example * ```typescript * const result = await authService.signup({ * email: 'user@example.com', * password: 'Password123!', * username: 'johndoe', * }); * ``` */ signup(dto: SignupDTO): Promise; /** * Log in a user with identifier (email, username, or phone) and password. * * Handles client/device context, login hooks, lockout checks, audit logging, password verification, * and challenge flow (MFA/verification) if required. * * @param dto - Login credentials (identifier and password) * @returns Authentication response containing challenge details if required, or tokens on success * @throws {NAuthException} On login failure, forbidden access, or account lockout * * @example * ```typescript * const res = await authService.login({ identifier: 'user@email.com', password: 'Pass123!' }); * if (res.challengeName) { * // prompt user for verification code * } * ``` */ login(dto: LoginDTO): Promise; /** * Complete an authentication challenge using the provided response data. * * Handles all challenge types (email verification, phone verification, MFA, password change, MFA setup). * Validates the session, challenge type, and parameters, and returns the result (tokens or next challenge). * * @param responseData - Data for responding to the challenge * @returns The authentication response (tokens or next challenge requirement) * @throws {NAuthException} If validation fails or the challenge type is unknown * * @example * ```typescript * // Example for email verification: * const dto = Object.assign(new RespondChallengeDTO(), { * session: 'session-token', * type: 'VERIFY_EMAIL', * code: '123456', * }); * await authService.respondToChallenge(dto); * ``` */ respondToChallenge(dto: RespondChallengeDTO): Promise; /** * Resend verification code for current challenge * * Determines the challenge type from the session and resends the appropriate code: * - VERIFY_EMAIL: Resends email verification code * - VERIFY_PHONE: Resends SMS verification code * - MFA_REQUIRED: Resends MFA code (for SMS MFA) * * Rate limits are enforced internally by the verification services. * * @param dto - Resend code request with challenge session token * @returns Destination info (masked email/phone) * @throws {NAuthException} INVALID_CHALLENGE_SESSION | RATE_LIMIT_* | VALIDATION_FAILED * * @example * ```typescript * const result = await authService.resendCode({ session: 'challenge-token' }); * // Returns: { destination: 'u***r@example.com' } * ``` */ resendCode(dto: ResendCodeDTO): Promise; /** * Registers the current device as trusted for the user (opt-in). * * Only available when rememberDevices is set to 'user_opt_in'. Generates and returns a trusted device token for the device associated with the current authenticated session. * * Session ID is automatically extracted from the JWT token context (via ClientInfoService), similar to how IP address and user agent are handled. * * @returns Object containing the new device token * @throws {NAuthException} If the feature is unavailable, service is not enabled, or session ID is not available * * @example * ```typescript * const result = await authService.trustDevice(); * // { deviceToken: 'abc123' } * ``` */ trustDevice(): Promise; /** * Check if the current device is trusted * * Returns whether the device associated with the current authenticated session * is trusted. Works for both cookies mode (reads from httpOnly cookie) and * JSON mode (reads from X-Device-Token header). * * This endpoint validates the device token on the server side and checks: * - Device token exists and is valid * - Device token matches a trusted device record in the database * - Trust has not expired * * @returns Object containing the trusted status * @throws {NAuthException} If the session is not found or user is not authenticated * * @example * ```typescript * const result = await authService.isTrustedDevice(); * // { trusted: true } * ``` */ isTrustedDevice(): Promise; /** * Refresh the access token using a refresh token. * * Handles secure token rotation with distributed locking, reuse detection, * and family revocation to prevent race conditions and replay attacks. * * @param refreshToken - The refresh token issued to the client * @returns Newly generated access and refresh tokens * @throws {NAuthException} If the session is not found, revoked, or refresh is abused * * @example * ```typescript * const tokens = await authService.refreshToken(refreshToken); * ``` */ refreshToken(dto: RefreshTokenDTO): Promise; /** * Clear auth cookies (access/refresh/csrf) on refresh failures that imply the session is invalid. * * WHY: * - In cookie delivery, httpOnly cookies can only be cleared server-side. * - Clearing them on refresh failure prevents client loops and aligns client state with server reality. * * SECURITY NOTE: * - Device token cookie is intentionally NOT cleared by default (remember-device feature). * * @param code - Error code to evaluate */ /** * Resolve the per-request refresh token TTL override. * * Pulls the current request from ContextStorage and delegates to the * hybrid-policy resolver. Returns `undefined` when no override applies, * in which case callers fall back to `jwt.refreshToken.expiresIn`. */ private resolveRefreshExpiresInForRequest; /** * Resolve the per-request refresh TTL AND publish it to ContextStorage so * downstream services (AuthChallengeHelperService) that mint token pairs * can pick it up without needing direct config access. This keeps the * helper's constructor signature stable for framework adapters that wire * it up with the legacy (pre-hybrid-TTL) argument list. * * No-ops silently when no ContextStorage context is active (e.g. unit * tests that call AuthService methods directly without ContextStorage.run). */ private publishResolvedRefreshExpiresIn; private clearAuthCookiesOnRefreshFailure; /** * Logout user from current session * * Revokes the current authenticated session. Session ID is automatically extracted * from the JWT token context (via ClientInfoService), similar to how IP address * and user agent are handled. * * Usage Pattern: * - **User-context only**: This method operates on the current authenticated session * - Session ID is transparently extracted from JWT token in request context * - User can only logout their own current session (not other sessions) * - For logging out other sessions, use logoutSession() or logoutAll() * * Security: * - Requires authentication - session ID must be present in request context * - Endpoint MUST be protected by authentication guards * - User cannot specify which session to logout (always current session) * * @param dto - Logout options (optional forgetMe flag) * @returns Success status * @throws {NAuthException} SESSION_NOT_FOUND if session ID not found in request context * * @example * ```typescript * @UseGuards(AuthGuard) * @Get('logout') * async logout(@CurrentUser() user: IUser, @Query('forgetMe') forgetMe?: string) { * return this.authService.logout({ forgetMe: forgetMe === 'true' }); * } * ``` */ logout(dto: LogoutDTO): Promise; /** * Global signout (revoke all user sessions) * * Revokes all active sessions for a user across all devices. * Optionally revokes all trusted devices if forgetDevices flag is set. * * Usage Patterns: * - **User-initiated**: User logs out from all their own sessions (protected endpoint) * * Security: * - Uses authenticated user context for sub * - Endpoint MUST be protected by authentication guards * * @param dto - Logout options (forgetDevices flag) * @returns Number of sessions revoked * @throws {NAuthException} NOT_FOUND if user not found * * @example User-initiated (user context) * ```typescript * // Controller extracts sub from authenticated user * @UseGuards(AuthGuard) * @Post('logout/all') * async logoutAll(@CurrentUser() user: IUser, @Body() body: { forgetDevices?: boolean }) { * return this.authService.logoutAll({ forgetDevices: body.forgetDevices }); * } * ``` * * @example Admin-initiated (admin manages any user) * ```typescript * // Use AdminAuthService.logoutAll with target sub * @UseGuards(AuthGuard, AdminGuard) * @Post('admin/users/:sub/logout-all') * async adminLogoutAll(@Param('sub') sub: string, @Body() body: { forgetDevices?: boolean }) { * return this.adminAuthService.logoutAll({ sub, forgetDevices: body.forgetDevices }); * } * ``` */ logoutAll(dto: LogoutAllDTO): Promise; /** * Get all active sessions for a user * * Returns session details including authentication method (password, social, admin). * For social logins, check session metadata for the specific OAuth provider. * Current session (if called from authenticated context) is marked with isCurrent=true. * * Usage Patterns: * - **User viewing own sessions**: User views their active sessions (protected endpoint) * * Security: * - Uses authenticated user context for sub * - Endpoint MUST be protected by authentication guards * * @returns Array of sessions with device info, auth method, and isCurrent flag * @throws {NAuthException} NOT_FOUND if user not found * * @example User viewing own sessions * ```typescript * @UseGuards(AuthGuard) * @Get('sessions') * async getSessions(@CurrentUser() user: IUser) { * return this.authService.getUserSessions(); * } * ``` * * @example Admin viewing any user's sessions * ```typescript * @UseGuards(AuthGuard, AdminGuard) * @Get('admin/users/:sub/sessions') * async adminGetSessions(@Param('sub') sub: string) { * return this.adminAuthService.getUserSessions({ sub }); * } * ``` */ getUserSessions(): Promise; /** * Get authentication audit history for current authenticated user * * Returns paginated audit trail of authentication events for the user: * - Login attempts (success/failure) * - Password changes * - MFA setup/verification * - Device trust events * - Device information, location, risk factors * * Usage Patterns: * - **User viewing own audit history**: User views their authentication history (protected endpoint) * * Security: * - Uses authenticated user context for sub * - Endpoint MUST be protected by authentication guards * * @param dto - Optional query parameters for filtering and pagination * @returns Paginated audit history response * @throws {NAuthException} FORBIDDEN if user not authenticated * @throws {NAuthException} NOT_FOUND if user not found * * @example User viewing own audit history * ```typescript * @UseGuards(AuthGuard) * @Get('audit/history') * async getAuditHistory(@Query() query: GetUserAuthHistoryDTO) { * return this.authService.getUserAuthHistory(query); * } * ``` */ getUserAuthHistory(dto?: GetUserAuthHistoryDTO): Promise; /** * Logout a specific session by ID * * Revokes a specific session for a user. Validates session belongs to requesting user. * Automatically clears cookies if logging out the current session. * Useful for "sign out from device" functionality in user dashboards. * * Usage Patterns: * - **User logging out own session**: User revokes specific session (protected endpoint) * * Security: * - Uses authenticated user context for sub * - Validates session belongs to user (prevents unauthorized session revocation) * - Endpoint MUST be protected by authentication guards * * @param dto - Contains sessionId * @returns Success status and whether it was the current session * @throws {NAuthException} NOT_FOUND if user not found * @throws {NAuthException} SESSION_NOT_FOUND if session not found * @throws {NAuthException} FORBIDDEN if session doesn't belong to user * * @example User logging out own session * ```typescript * @UseGuards(AuthGuard) * @Delete('sessions/:sessionId') * async logoutSession(@CurrentUser() user: IUser, @Param('sessionId') sessionId: string) { * return this.authService.logoutSession({ sessionId }); * } * ``` * * @example Admin revoking any user's session (if needed) * ```typescript * @UseGuards(AuthGuard, AdminGuard) * @Delete('admin/users/:sub/sessions/:sessionId') * async adminRevokeSession(@Param('sub') sub: string, @Param('sessionId') sessionId: string) { * return this.adminAuthService.revokeUserSession({ sub, sessionId }); * } * ``` */ logoutSession(dto: LogoutSessionDTO): Promise; /** * Change the password for an existing user. * * Verifies the current password, validates the new password, * checks password reuse policy, and updates the user's password hash and history. * Executes configured pre-change hooks if provided. * * @param dto - ChangePasswordDTO containing old and new password * @returns void * @throws {NAuthException} If the user is not found, current password is incorrect, the new password is weak, password reuse is detected, or password change is disallowed by hooks. * * @example * ```typescript * await authService.changePassword({ * oldPassword: 'currentPass123!', * newPassword: 'newStr0ngPass!@#', * }); * ``` */ changePassword(dto: ChangePasswordDTO): Promise; /** * Update user profile attributes. * * Updates user fields (name, email, phone, username, metadata) and enforces unique constraints and verification rules. * * @param dto - UpdateUserAttributesDTO containing fields to update * @returns Updated user object * @throws {NAuthException} If user not found or unique constraint violated * * @example * await authService.updateUserAttributes({ email: 'test@example.com' }); */ updateUserAttributes(dto: UpdateUserAttributesDTO): Promise; /** * Get user for authentication context * * Loads user by sub (external identifier) with all fields needed for auth context. * Computes hasPasswordHash from passwordHash, then removes passwordHash and other sensitive fields. * * This method is used by AuthHandler and AuthGuard to load authenticated users. * It ensures consistent user object shape across platforms (core + NestJS). * * @param sub - External user identifier (UUID) * @returns User object with hasPasswordHash flag, without sensitive fields * @throws {NAuthException} If user not found or account is inactive * * @example * ```typescript * const user = await authService.getUserForAuthContext('user-uuid'); * ``` */ getUserForAuthContext(sub: string): Promise; /** * Validate JWT access token * * Validates JWT access token signature, expiration, and format. * Returns decoded payload if valid, or error information if invalid. * * Use cases: * - Manual token validation in consumer applications * - Token introspection for debugging * - Custom authorization logic requiring token payload * - API gateway token validation * * Security: * - Verifies token signature using configured secret/public key * - Validates expiration timestamp * - Ensures token type is 'access' * - Checks issuer and audience claims * * @param dto - ValidateAccessTokenDTO containing access token * @returns ValidateAccessTokenResponseDTO with validation result and optional payload * * @example * ```typescript * const result = await authService.validateAccessToken({ * accessToken: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' * }); * * if (result.valid) { * console.log('User ID:', result.payload.sub); * console.log('Session ID:', result.payload.sessionId); * } else { * console.error('Validation failed:', result.error, result.errorType); * } * ``` */ validateAccessToken(dto: ValidateAccessTokenDTO): Promise; /** * Request a password reset code for an account. * * Security: * - Avoids account enumeration: returns success even when user is not found. * - Delivery is best-effort; errors are logged but should not reveal account existence. * * Channel selection (per config.signup.verificationMethod): * - 'none': send to email if available; else phone (if available) * - 'email': only send to verified email * - 'phone': only send to verified phone * - 'both': prefer verified email; fallback to verified phone * * @param dto - Forgot password request payload * @returns Delivery metadata (masked destination) when available */ forgotPassword(dto: ForgotPasswordDTO): Promise; /** * Confirm a password reset by validating the reset code and setting a new password. * * Security: * - Uses platform-agnostic errors via NAuthException * - Verifies reset code via PasswordResetService * - Enforces password policy and history * - Revokes all sessions upon successful reset * * @param dto - Confirm forgot password payload * @returns Success response * @throws {NAuthException} PASSWORD_RESET_CODE_INVALID | PASSWORD_RESET_CODE_EXPIRED | PASSWORD_RESET_MAX_ATTEMPTS */ confirmForgotPassword(dto: ConfirmForgotPasswordDTO): Promise; private getCurrentUserOrThrow; /** * Calculate grace period status for a user. * * @param user - User to check * @returns Grace period status with isActive flag and endsAt date */ private calculateGracePeriodForUser; } //# sourceMappingURL=auth.service.d.ts.map