@lenan-soft/auth 1.0.1
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.
- package/README.md +591 -0
- package/dist/index.cjs +45 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +129 -0
- package/dist/index.d.ts +129 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/nestjs/index.cjs +738 -0
- package/dist/nestjs/index.cjs.map +1 -0
- package/dist/nestjs/index.d.cts +510 -0
- package/dist/nestjs/index.d.ts +510 -0
- package/dist/nestjs/index.js +709 -0
- package/dist/nestjs/index.js.map +1 -0
- package/dist/react/index.cjs +560 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +285 -0
- package/dist/react/index.d.ts +285 -0
- package/dist/react/index.js +531 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/native/index.cjs +60 -0
- package/dist/react/native/index.cjs.map +1 -0
- package/dist/react/native/index.d.cts +50 -0
- package/dist/react/native/index.d.ts +50 -0
- package/dist/react/native/index.js +41 -0
- package/dist/react/native/index.js.map +1 -0
- package/dist/shared/index.cjs +45 -0
- package/dist/shared/index.cjs.map +1 -0
- package/dist/shared/index.d.cts +129 -0
- package/dist/shared/index.d.ts +129 -0
- package/dist/shared/index.js +17 -0
- package/dist/shared/index.js.map +1 -0
- package/package.json +151 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/nestjs/index.ts","../../src/nestjs/lenan-auth.module.ts","../../src/nestjs/controllers/auth.controller.ts","../../src/nestjs/decorators/index.ts","../../src/nestjs/dto/index.ts","../../src/nestjs/guards/jwt-auth.guard.ts","../../src/nestjs/guards/refresh-token.guard.ts","../../src/nestjs/interfaces/index.ts","../../src/nestjs/services/auth.service.ts","../../src/nestjs/services/jwt-token.service.ts","../../src/nestjs/services/password.service.ts","../../src/nestjs/strategies/jwt.strategy.ts","../../src/nestjs/strategies/refresh-token.strategy.ts"],"sourcesContent":["// Module\nexport { LenanAuthModule } from \"./lenan-auth.module\";\n\n// Interfaces\nexport { LENAN_AUTH_OPTIONS, LENAN_USER_SERVICE } from \"./interfaces\";\nexport type {\n AccessTokenPayload,\n AuthModuleAsyncOptions,\n AuthModuleOptions,\n AuthOptionsFactory,\n AuthenticatedRequest,\n RefreshTokenPayload,\n UserServiceInterface,\n} from \"./interfaces\";\n\n// Services\nexport { AuthService, JwtTokenService, PasswordService } from \"./services\";\n\n// Guards\nexport { JwtAuthGuard, RefreshTokenGuard } from \"./guards\";\n\n// Strategies\nexport { JwtStrategy, RefreshTokenStrategy } from \"./strategies\";\n\n// Decorators\nexport { CurrentUser, IS_PUBLIC_KEY, Public } from \"./decorators\";\n\n// DTOs\nexport {\n LoginDto,\n MessageResponseDto,\n RefreshTokenDto,\n RegisterDto,\n TokensResponseDto,\n} from \"./dto\";\n\n// Controller\nexport { AuthController } from \"./controllers\";\n\n// Re-export shared types for convenience\nexport type {\n AuthTokens,\n AuthUser,\n BaseUser,\n JwtPayload,\n LoginCredentials,\n RegisterData,\n} from \"../shared\";\n","import { DynamicModule, Module, Provider, Type } from \"@nestjs/common\";\nimport { JwtModule } from \"@nestjs/jwt\";\nimport { PassportModule } from \"@nestjs/passport\";\nimport { AuthController } from \"./controllers\";\nimport {\n LENAN_AUTH_OPTIONS,\n LENAN_USER_SERVICE,\n type AuthModuleAsyncOptions,\n type AuthModuleOptions,\n type AuthOptionsFactory,\n type UserServiceInterface,\n} from \"./interfaces\";\nimport { AuthService, JwtTokenService, PasswordService } from \"./services\";\nimport { JwtStrategy, RefreshTokenStrategy } from \"./strategies\";\n\n/**\n * Lenan Auth Module for NestJS\n *\n * A flexible authentication module supporting JWT access/refresh tokens.\n * Requires consumers to implement UserServiceInterface.\n *\n * @example\n * ```typescript\n * // Sync registration\n * @Module({\n * imports: [\n * LenanAuthModule.register({\n * jwtSecret: 'your-secret',\n * jwtAccessExpiry: '15m',\n * jwtRefreshExpiry: '7d',\n * }, UserService),\n * ],\n * })\n * export class AppModule {}\n *\n * // Async registration with ConfigService\n * @Module({\n * imports: [\n * LenanAuthModule.registerAsync({\n * imports: [ConfigModule],\n * useFactory: (config: ConfigService) => ({\n * jwtSecret: config.get('JWT_SECRET'),\n * jwtAccessExpiry: config.get('JWT_ACCESS_EXPIRY', '15m'),\n * jwtRefreshExpiry: config.get('JWT_REFRESH_EXPIRY', '7d'),\n * }),\n * inject: [ConfigService],\n * }, UserService),\n * ],\n * })\n * export class AppModule {}\n * ```\n */\n@Module({})\nexport class LenanAuthModule {\n /**\n * Register the auth module with synchronous configuration\n *\n * @param options - Auth module configuration options\n * @param userService - Your UserService class implementing UserServiceInterface\n */\n static register(\n options: AuthModuleOptions,\n userService: Type<UserServiceInterface>,\n ): DynamicModule {\n const providers = this.createProviders(options, userService);\n const controllers = options.useController !== false ? [AuthController] : [];\n\n return {\n module: LenanAuthModule,\n imports: [\n PassportModule.register({ defaultStrategy: \"lenan-jwt\" }),\n JwtModule.register({\n secret: options.jwtSecret,\n signOptions: { expiresIn: (options.jwtAccessExpiry ?? \"15m\") as any },\n }),\n ],\n providers,\n controllers,\n exports: [\n AuthService,\n PasswordService,\n JwtTokenService,\n JwtStrategy,\n LENAN_USER_SERVICE,\n ],\n };\n }\n\n /**\n * Register the auth module with async configuration\n *\n * @param asyncOptions - Async configuration options\n * @param userService - Your UserService class implementing UserServiceInterface\n */\n static registerAsync(\n asyncOptions: AuthModuleAsyncOptions,\n userService: Type<UserServiceInterface>,\n ): DynamicModule {\n const providers = this.createAsyncProviders(asyncOptions, userService);\n\n return {\n module: LenanAuthModule,\n imports: [\n ...(asyncOptions.imports ?? []),\n PassportModule.register({ defaultStrategy: \"lenan-jwt\" }),\n JwtModule.registerAsync({\n imports: asyncOptions.imports,\n useFactory: async (...args: any[]) => {\n let options: AuthModuleOptions;\n\n if (asyncOptions.useFactory) {\n options = await asyncOptions.useFactory(...args);\n } else {\n throw new Error(\"useFactory is required for async registration\");\n }\n\n return {\n secret: options.jwtSecret,\n signOptions: {\n expiresIn: (options.jwtAccessExpiry ?? \"15m\") as any,\n },\n };\n },\n inject: asyncOptions.inject ?? [],\n }),\n ],\n providers,\n controllers: [AuthController],\n exports: [\n AuthService,\n PasswordService,\n JwtTokenService,\n JwtStrategy,\n LENAN_USER_SERVICE,\n ],\n };\n }\n\n private static createProviders(\n options: AuthModuleOptions,\n userService: Type<UserServiceInterface>,\n ): Provider[] {\n return [\n {\n provide: LENAN_AUTH_OPTIONS,\n useValue: options,\n },\n {\n provide: LENAN_USER_SERVICE,\n useClass: userService,\n },\n AuthService,\n PasswordService,\n JwtTokenService,\n JwtStrategy,\n RefreshTokenStrategy,\n ];\n }\n\n private static createAsyncProviders(\n asyncOptions: AuthModuleAsyncOptions,\n userService: Type<UserServiceInterface>,\n ): Provider[] {\n const asyncOptionsProvider = this.createAsyncOptionsProvider(asyncOptions);\n\n return [\n asyncOptionsProvider,\n {\n provide: LENAN_USER_SERVICE,\n useClass: userService,\n },\n AuthService,\n PasswordService,\n JwtTokenService,\n JwtStrategy,\n RefreshTokenStrategy,\n ];\n }\n\n private static createAsyncOptionsProvider(\n asyncOptions: AuthModuleAsyncOptions,\n ): Provider {\n if (asyncOptions.useFactory) {\n return {\n provide: LENAN_AUTH_OPTIONS,\n useFactory: asyncOptions.useFactory,\n inject: asyncOptions.inject ?? [],\n };\n }\n\n if (asyncOptions.useClass) {\n return {\n provide: LENAN_AUTH_OPTIONS,\n useFactory: async (optionsFactory: AuthOptionsFactory) => {\n return optionsFactory.createAuthOptions();\n },\n inject: [asyncOptions.useClass],\n };\n }\n\n if (asyncOptions.useExisting) {\n return {\n provide: LENAN_AUTH_OPTIONS,\n useFactory: async (optionsFactory: AuthOptionsFactory) => {\n return optionsFactory.createAuthOptions();\n },\n inject: [asyncOptions.useExisting],\n };\n }\n\n throw new Error(\n \"Invalid async options: must provide useFactory, useClass, or useExisting\",\n );\n }\n}\n","import {\n Body,\n Controller,\n Get,\n HttpCode,\n HttpStatus,\n Post,\n UseGuards,\n} from \"@nestjs/common\";\nimport type { BaseUser } from \"../../shared\";\nimport { CurrentUser, Public } from \"../decorators\";\nimport {\n LoginDto,\n MessageResponseDto,\n RegisterDto,\n TokensResponseDto,\n} from \"../dto\";\nimport { JwtAuthGuard, RefreshTokenGuard } from \"../guards\";\nimport { AuthService } from \"../services/auth.service\";\n\n/**\n * Authentication controller providing standard auth endpoints\n * This controller is optional - consumers can disable it and implement their own\n */\n@Controller(\"auth\")\nexport class AuthController {\n constructor(private readonly authService: AuthService) {}\n\n /**\n * Register a new user\n * POST /auth/register\n */\n @Public()\n @Post(\"register\")\n @HttpCode(HttpStatus.CREATED)\n async register(@Body() dto: RegisterDto): Promise<TokensResponseDto> {\n const tokens = await this.authService.register(dto);\n return new TokensResponseDto(tokens.accessToken, tokens.refreshToken);\n }\n\n /**\n * Login with email and password\n * POST /auth/login\n */\n @Public()\n @Post(\"login\")\n @HttpCode(HttpStatus.OK)\n async login(@Body() dto: LoginDto): Promise<TokensResponseDto> {\n const tokens = await this.authService.login(dto);\n return new TokensResponseDto(tokens.accessToken, tokens.refreshToken);\n }\n\n /**\n * Refresh access token using refresh token\n * POST /auth/refresh\n */\n @Public()\n @UseGuards(RefreshTokenGuard)\n @Post(\"refresh\")\n @HttpCode(HttpStatus.OK)\n async refresh(\n @CurrentUser() user: BaseUser & { refreshToken: string },\n ): Promise<TokensResponseDto> {\n const tokens = await this.authService.refreshTokens(\n user.id,\n user.refreshToken,\n );\n return new TokensResponseDto(tokens.accessToken, tokens.refreshToken);\n }\n\n /**\n * Logout (invalidate refresh token)\n * POST /auth/logout\n */\n @UseGuards(JwtAuthGuard)\n @Post(\"logout\")\n @HttpCode(HttpStatus.OK)\n async logout(@CurrentUser(\"id\") userId: string): Promise<MessageResponseDto> {\n await this.authService.logout(userId);\n return new MessageResponseDto(\"Logged out successfully\");\n }\n\n /**\n * Get current authenticated user\n * GET /auth/me\n */\n @UseGuards(JwtAuthGuard)\n @Get(\"me\")\n async me(@CurrentUser() user: BaseUser) {\n return user;\n }\n}\n","import {\n createParamDecorator,\n ExecutionContext,\n SetMetadata,\n} from \"@nestjs/common\";\n\n/**\n * Metadata key for public routes\n */\nexport const IS_PUBLIC_KEY = \"isPublic\";\n\n/**\n * Mark a route as public (no authentication required)\n * Use this decorator on routes that should be accessible without a valid JWT\n *\n * @example\n * ```typescript\n * @Public()\n * @Get('health')\n * healthCheck() {\n * return { status: 'ok' };\n * }\n * ```\n */\nexport const Public = () => SetMetadata(IS_PUBLIC_KEY, true);\n\n/**\n * Extract the current authenticated user from the request\n * Can optionally extract a specific property from the user object\n *\n * @example\n * ```typescript\n * // Get the entire user object\n * @Get('profile')\n * getProfile(@CurrentUser() user: User) {\n * return user;\n * }\n *\n * // Get a specific property\n * @Get('my-id')\n * getMyId(@CurrentUser('id') userId: string) {\n * return { id: userId };\n * }\n * ```\n */\nexport const CurrentUser = createParamDecorator(\n (data: string | undefined, ctx: ExecutionContext) => {\n const request = ctx.switchToHttp().getRequest();\n const user = request.user;\n\n if (!user) {\n return null;\n }\n\n return data ? user[data] : user;\n },\n);\n","import {\n IsEmail,\n IsString,\n Matches,\n MaxLength,\n MinLength,\n} from \"class-validator\";\n\n/**\n * Login request DTO\n */\nexport class LoginDto {\n @IsEmail({}, { message: \"Please provide a valid email address\" })\n email!: string;\n\n @IsString()\n @MinLength(1, { message: \"Password is required\" })\n password!: string;\n}\n\n/**\n * Registration request DTO\n */\nexport class RegisterDto {\n @IsEmail({}, { message: \"Please provide a valid email address\" })\n email!: string;\n\n @IsString()\n @MinLength(8, { message: \"Password must be at least 8 characters long\" })\n @MaxLength(128, { message: \"Password must be at most 128 characters long\" })\n @Matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)/, {\n message:\n \"Password must contain at least one lowercase letter, one uppercase letter, and one number\",\n })\n password!: string;\n\n @IsString()\n @MinLength(1, { message: \"Password confirmation is required\" })\n confirmPassword!: string;\n}\n\n/**\n * Refresh token request DTO\n */\nexport class RefreshTokenDto {\n @IsString()\n @MinLength(1, { message: \"Refresh token is required\" })\n refreshToken!: string;\n}\n\n/**\n * Token response DTO\n */\nexport class TokensResponseDto {\n accessToken!: string;\n refreshToken!: string;\n\n constructor(accessToken: string, refreshToken: string) {\n this.accessToken = accessToken;\n this.refreshToken = refreshToken;\n }\n}\n\n/**\n * Message response DTO\n */\nexport class MessageResponseDto {\n message!: string;\n\n constructor(message: string) {\n this.message = message;\n }\n}\n","import { ExecutionContext, Injectable } from \"@nestjs/common\";\nimport { Reflector } from \"@nestjs/core\";\nimport { AuthGuard } from \"@nestjs/passport\";\nimport { IS_PUBLIC_KEY } from \"../decorators\";\n\n/**\n * JWT Auth Guard for protecting routes\n * Uses the 'lenan-jwt' strategy to validate access tokens\n * Respects the @Public() decorator to skip authentication\n */\n@Injectable()\nexport class JwtAuthGuard extends AuthGuard(\"lenan-jwt\") {\n constructor(private reflector: Reflector) {\n super();\n }\n\n canActivate(context: ExecutionContext) {\n // Check if route is marked as public\n const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [\n context.getHandler(),\n context.getClass(),\n ]);\n\n if (isPublic) {\n return true;\n }\n\n return super.canActivate(context);\n }\n}\n","import { Injectable } from \"@nestjs/common\";\nimport { AuthGuard } from \"@nestjs/passport\";\n\n/**\n * Refresh Token Guard for protecting the refresh endpoint\n * Uses the 'lenan-jwt-refresh' strategy to validate refresh tokens\n */\n@Injectable()\nexport class RefreshTokenGuard extends AuthGuard(\"lenan-jwt-refresh\") {}\n","import type { AuthUser, BaseUser } from \"../../shared\";\n\n/**\n * User service interface that consumers must implement\n * This is the contract between the auth library and your application's user management\n */\nexport interface UserServiceInterface<TUser extends AuthUser = AuthUser> {\n /**\n * Find a user by their email address\n * Used during login to validate credentials\n */\n findByEmail(email: string): Promise<TUser | null>;\n\n /**\n * Find a user by their ID\n * Used for token validation and user retrieval\n */\n findById(id: string): Promise<TUser | null>;\n\n /**\n * Create a new user with hashed password\n * Called during registration\n */\n createUser(data: { email: string; passwordHash: string }): Promise<TUser>;\n\n /**\n * Update the user's hashed refresh token\n * Called after login/refresh to store the new refresh token\n * Pass null to clear the token (logout)\n */\n updateRefreshToken(userId: string, hashedToken: string | null): Promise<void>;\n\n /**\n * Validate that the provided refresh token matches the stored one\n * Should compare hashed values\n */\n validateRefreshToken(userId: string, hashedToken: string): Promise<boolean>;\n}\n\n/**\n * Injection token for the user service\n */\nexport const LENAN_USER_SERVICE = Symbol(\"LENAN_USER_SERVICE\");\n\n/**\n * Configuration options for the auth module\n */\nexport interface AuthModuleOptions {\n /** Secret key for signing JWT access tokens */\n jwtSecret: string;\n\n /** Access token expiration time (e.g., '15m', '1h') */\n jwtAccessExpiry?: string;\n\n /** Refresh token expiration time (e.g., '7d', '30d') */\n jwtRefreshExpiry?: string;\n\n /** Optional separate secret for refresh tokens (defaults to jwtSecret + '_refresh') */\n jwtRefreshSecret?: string;\n\n /** Whether to register the default AuthController (default: true) */\n useController?: boolean;\n\n /** Global route prefix for auth endpoints (default: 'auth') */\n routePrefix?: string;\n}\n\n/**\n * Async configuration options for the auth module\n */\nexport interface AuthModuleAsyncOptions {\n /**\n * Imports required for the factory/useClass\n */\n imports?: any[];\n\n /**\n * Factory function to create the options\n */\n useFactory?: (\n ...args: any[]\n ) => Promise<AuthModuleOptions> | AuthModuleOptions;\n\n /**\n * Dependencies to inject into the factory\n */\n inject?: any[];\n\n /**\n * Class that implements AuthOptionsFactory\n */\n useClass?: new (...args: any[]) => AuthOptionsFactory;\n\n /**\n * Existing provider to use\n */\n useExisting?: new (...args: any[]) => AuthOptionsFactory;\n}\n\n/**\n * Factory interface for creating auth options\n */\nexport interface AuthOptionsFactory {\n createAuthOptions(): Promise<AuthModuleOptions> | AuthModuleOptions;\n}\n\n/**\n * Injection token for auth module options\n */\nexport const LENAN_AUTH_OPTIONS = Symbol(\"LENAN_AUTH_OPTIONS\");\n\n/**\n * Request with user attached (after authentication)\n */\nexport interface AuthenticatedRequest<\n TUser extends BaseUser = BaseUser,\n> extends Request {\n user: TUser;\n}\n\n/**\n * JWT payload for access tokens\n */\nexport interface AccessTokenPayload {\n sub: string;\n email: string;\n type: \"access\";\n}\n\n/**\n * JWT payload for refresh tokens\n */\nexport interface RefreshTokenPayload {\n sub: string;\n email: string;\n type: \"refresh\";\n}\n","import {\n BadRequestException,\n ConflictException,\n Inject,\n Injectable,\n UnauthorizedException,\n} from \"@nestjs/common\";\nimport type { AuthTokens, AuthUser } from \"../../shared\";\nimport type { LoginDto, RegisterDto } from \"../dto\";\nimport { LENAN_USER_SERVICE, type UserServiceInterface } from \"../interfaces\";\nimport { JwtTokenService } from \"./jwt-token.service\";\nimport { PasswordService } from \"./password.service\";\n\n/**\n * Main authentication service\n * Orchestrates user authentication, registration, and token management\n */\n@Injectable()\nexport class AuthService {\n constructor(\n @Inject(LENAN_USER_SERVICE)\n private readonly userService: UserServiceInterface,\n private readonly passwordService: PasswordService,\n private readonly jwtTokenService: JwtTokenService,\n ) {}\n\n /**\n * Register a new user\n * @throws ConflictException if email already exists\n */\n async register(dto: RegisterDto): Promise<AuthTokens> {\n // Check if user already exists\n const existingUser = await this.userService.findByEmail(dto.email);\n if (existingUser) {\n throw new ConflictException(\"Email already registered\");\n }\n\n // Validate password confirmation\n if (dto.password !== dto.confirmPassword) {\n throw new BadRequestException(\"Passwords do not match\");\n }\n\n // Hash password and create user\n const passwordHash = await this.passwordService.hash(dto.password);\n const user = await this.userService.createUser({\n email: dto.email,\n passwordHash,\n });\n\n // Generate tokens\n const tokens = await this.jwtTokenService.generateTokens(\n user.id,\n user.email,\n );\n\n // Store hashed refresh token\n const hashedRefreshToken = await this.passwordService.hashToken(\n tokens.refreshToken,\n );\n await this.userService.updateRefreshToken(user.id, hashedRefreshToken);\n\n return tokens;\n }\n\n /**\n * Authenticate a user with email and password\n * @throws UnauthorizedException if credentials are invalid\n */\n async login(dto: LoginDto): Promise<AuthTokens> {\n const user = await this.userService.findByEmail(dto.email);\n if (!user) {\n throw new UnauthorizedException(\"Invalid credentials\");\n }\n\n const isPasswordValid = await this.passwordService.compare(\n dto.password,\n user.passwordHash,\n );\n if (!isPasswordValid) {\n throw new UnauthorizedException(\"Invalid credentials\");\n }\n\n // Generate tokens\n const tokens = await this.jwtTokenService.generateTokens(\n user.id,\n user.email,\n );\n\n // Store hashed refresh token\n const hashedRefreshToken = await this.passwordService.hashToken(\n tokens.refreshToken,\n );\n await this.userService.updateRefreshToken(user.id, hashedRefreshToken);\n\n return tokens;\n }\n\n /**\n * Refresh tokens using a valid refresh token\n * @throws UnauthorizedException if refresh token is invalid\n */\n async refreshTokens(\n userId: string,\n refreshToken: string,\n ): Promise<AuthTokens> {\n const user = await this.userService.findById(userId);\n if (!user || !user.hashedRefreshToken) {\n throw new UnauthorizedException(\"Invalid refresh token\");\n }\n\n // Verify the refresh token matches\n const isValid = await this.passwordService.compareToken(\n refreshToken,\n user.hashedRefreshToken,\n );\n if (!isValid) {\n throw new UnauthorizedException(\"Invalid refresh token\");\n }\n\n // Generate new tokens\n const tokens = await this.jwtTokenService.generateTokens(\n user.id,\n user.email,\n );\n\n // Store new hashed refresh token\n const hashedRefreshToken = await this.passwordService.hashToken(\n tokens.refreshToken,\n );\n await this.userService.updateRefreshToken(user.id, hashedRefreshToken);\n\n return tokens;\n }\n\n /**\n * Log out a user by clearing their refresh token\n */\n async logout(userId: string): Promise<void> {\n await this.userService.updateRefreshToken(userId, null);\n }\n\n /**\n * Validate a user exists by ID\n * Used by JWT strategy to validate token payloads\n */\n async validateUser(userId: string): Promise<AuthUser | null> {\n return this.userService.findById(userId);\n }\n\n /**\n * Get current user by ID (without sensitive fields)\n */\n async getCurrentUser(\n userId: string,\n ): Promise<Omit<AuthUser, \"passwordHash\" | \"hashedRefreshToken\"> | null> {\n const user = await this.userService.findById(userId);\n if (!user) {\n return null;\n }\n\n // Remove sensitive fields\n const { passwordHash, hashedRefreshToken, ...safeUser } = user;\n return safeUser;\n }\n}\n","import { Inject, Injectable } from \"@nestjs/common\";\nimport { JwtService } from \"@nestjs/jwt\";\nimport type { AuthTokens } from \"../../shared\";\nimport {\n LENAN_AUTH_OPTIONS,\n type AccessTokenPayload,\n type AuthModuleOptions,\n type RefreshTokenPayload,\n} from \"../interfaces\";\n\n/**\n * Service for JWT token generation and verification\n */\n@Injectable()\nexport class JwtTokenService {\n private readonly accessExpiry: string;\n private readonly refreshExpiry: string;\n private readonly accessSecret: string;\n private readonly refreshSecret: string;\n\n constructor(\n private readonly jwtService: JwtService,\n @Inject(LENAN_AUTH_OPTIONS) options: AuthModuleOptions,\n ) {\n this.accessSecret = options.jwtSecret;\n this.refreshSecret =\n options.jwtRefreshSecret ?? `${options.jwtSecret}_refresh`;\n this.accessExpiry = options.jwtAccessExpiry ?? \"15m\";\n this.refreshExpiry = options.jwtRefreshExpiry ?? \"7d\";\n }\n\n /**\n * Generate access and refresh tokens for a user\n */\n async generateTokens(userId: string, email: string): Promise<AuthTokens> {\n const [accessToken, refreshToken] = await Promise.all([\n this.generateAccessToken(userId, email),\n this.generateRefreshToken(userId, email),\n ]);\n\n return { accessToken, refreshToken };\n }\n\n /**\n * Generate an access token\n */\n async generateAccessToken(userId: string, email: string): Promise<string> {\n const payload: AccessTokenPayload = {\n sub: userId,\n email,\n type: \"access\",\n };\n\n return this.jwtService.signAsync(payload, {\n secret: this.accessSecret,\n expiresIn: this.accessExpiry as any,\n });\n }\n\n /**\n * Generate a refresh token\n */\n async generateRefreshToken(userId: string, email: string): Promise<string> {\n const payload: RefreshTokenPayload = {\n sub: userId,\n email,\n type: \"refresh\",\n };\n\n return this.jwtService.signAsync(payload, {\n secret: this.refreshSecret,\n expiresIn: this.refreshExpiry as any,\n });\n }\n\n /**\n * Verify an access token and return its payload\n */\n async verifyAccessToken(token: string): Promise<AccessTokenPayload | null> {\n try {\n const payload = await this.jwtService.verifyAsync<AccessTokenPayload>(\n token,\n {\n secret: this.accessSecret,\n },\n );\n\n if (payload.type !== \"access\") {\n return null;\n }\n\n return payload;\n } catch {\n return null;\n }\n }\n\n /**\n * Verify a refresh token and return its payload\n */\n async verifyRefreshToken(token: string): Promise<RefreshTokenPayload | null> {\n try {\n const payload = await this.jwtService.verifyAsync<RefreshTokenPayload>(\n token,\n {\n secret: this.refreshSecret,\n },\n );\n\n if (payload.type !== \"refresh\") {\n return null;\n }\n\n return payload;\n } catch {\n return null;\n }\n }\n\n /**\n * Decode a token without verification (useful for debugging)\n */\n decodeToken<T = any>(token: string): T | null {\n try {\n return this.jwtService.decode(token) as T;\n } catch {\n return null;\n }\n }\n}\n","import { Injectable } from \"@nestjs/common\";\nimport * as bcrypt from \"bcryptjs\";\n\n/**\n * Service for password hashing and comparison using bcrypt\n */\n@Injectable()\nexport class PasswordService {\n private readonly saltRounds = 12;\n\n /**\n * Hash a plain text password\n */\n async hash(password: string): Promise<string> {\n return bcrypt.hash(password, this.saltRounds);\n }\n\n /**\n * Compare a plain text password with a hash\n */\n async compare(password: string, hash: string): Promise<boolean> {\n return bcrypt.compare(password, hash);\n }\n\n /**\n * Hash a refresh token for storage\n * Uses fewer rounds since refresh tokens are already random\n */\n async hashToken(token: string): Promise<string> {\n return bcrypt.hash(token, 10);\n }\n\n /**\n * Compare a refresh token with its hash\n */\n async compareToken(token: string, hash: string): Promise<boolean> {\n return bcrypt.compare(token, hash);\n }\n}\n","import { Inject, Injectable, UnauthorizedException } from \"@nestjs/common\";\nimport { PassportStrategy } from \"@nestjs/passport\";\nimport { ExtractJwt, Strategy } from \"passport-jwt\";\nimport {\n LENAN_AUTH_OPTIONS,\n LENAN_USER_SERVICE,\n type AccessTokenPayload,\n type AuthModuleOptions,\n type UserServiceInterface,\n} from \"../interfaces\";\n\n/**\n * JWT Strategy for validating access tokens\n * Extracts token from Authorization header and validates against the user service\n */\n@Injectable()\nexport class JwtStrategy extends PassportStrategy(Strategy, \"lenan-jwt\") {\n constructor(\n @Inject(LENAN_AUTH_OPTIONS) options: AuthModuleOptions,\n @Inject(LENAN_USER_SERVICE)\n private readonly userService: UserServiceInterface,\n ) {\n super({\n jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),\n ignoreExpiration: false,\n secretOrKey: options.jwtSecret,\n });\n }\n\n /**\n * Validate the JWT payload and return the user\n * This is called by Passport after successfully verifying the token signature\n */\n async validate(payload: AccessTokenPayload) {\n // Ensure this is an access token, not a refresh token\n if (payload.type !== \"access\") {\n throw new UnauthorizedException(\"Invalid token type\");\n }\n\n const user = await this.userService.findById(payload.sub);\n if (!user) {\n throw new UnauthorizedException(\"User not found\");\n }\n\n // Return user without sensitive fields\n const { passwordHash, hashedRefreshToken, ...safeUser } = user;\n return safeUser;\n }\n}\n","import { Inject, Injectable, UnauthorizedException } from \"@nestjs/common\";\nimport { PassportStrategy } from \"@nestjs/passport\";\nimport { Request } from \"express\";\nimport { ExtractJwt, Strategy } from \"passport-jwt\";\nimport {\n LENAN_AUTH_OPTIONS,\n LENAN_USER_SERVICE,\n type AuthModuleOptions,\n type RefreshTokenPayload,\n type UserServiceInterface,\n} from \"../interfaces\";\n\n/**\n * Refresh Token Strategy for validating refresh tokens\n * Extracts token from request body and validates it\n */\n@Injectable()\nexport class RefreshTokenStrategy extends PassportStrategy(\n Strategy,\n \"lenan-jwt-refresh\",\n) {\n constructor(\n @Inject(LENAN_AUTH_OPTIONS) options: AuthModuleOptions,\n @Inject(LENAN_USER_SERVICE)\n private readonly userService: UserServiceInterface,\n ) {\n const refreshSecret =\n options.jwtRefreshSecret ?? `${options.jwtSecret}_refresh`;\n\n super({\n jwtFromRequest: ExtractJwt.fromBodyField(\"refreshToken\"),\n ignoreExpiration: false,\n secretOrKey: refreshSecret,\n passReqToCallback: true,\n });\n }\n\n /**\n * Validate the refresh token payload\n * Returns user with the refresh token attached for further validation\n */\n async validate(req: Request, payload: RefreshTokenPayload) {\n // Ensure this is a refresh token\n if (payload.type !== \"refresh\") {\n throw new UnauthorizedException(\"Invalid token type\");\n }\n\n const user = await this.userService.findById(payload.sub);\n if (!user) {\n throw new UnauthorizedException(\"User not found\");\n }\n\n if (!user.hashedRefreshToken) {\n throw new UnauthorizedException(\"Refresh token has been revoked\");\n }\n\n // Return user with refresh token for AuthService to validate\n const refreshToken = req.body?.refreshToken;\n return { ...user, refreshToken };\n }\n}\n"],"mappings":"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","names":["import_common","import_jwt","import_passport","import_common","import_common","import_common","import_passport","import_common","import_common","import_common","hash","import_common","import_passport","import_common","import_passport","import_passport_jwt"]}
|
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
import * as _nestjs_common from '@nestjs/common';
|
|
2
|
+
import { Type, DynamicModule, ExecutionContext } from '@nestjs/common';
|
|
3
|
+
import { JwtService } from '@nestjs/jwt';
|
|
4
|
+
import * as rxjs from 'rxjs';
|
|
5
|
+
import * as _nestjs_passport from '@nestjs/passport';
|
|
6
|
+
import { Reflector } from '@nestjs/core';
|
|
7
|
+
import * as passport_jwt from 'passport-jwt';
|
|
8
|
+
import { Strategy } from 'passport-jwt';
|
|
9
|
+
import { Request as Request$1 } from 'express';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* JWT payload structure
|
|
13
|
+
*/
|
|
14
|
+
interface JwtPayload {
|
|
15
|
+
/** User ID (subject) */
|
|
16
|
+
sub: string;
|
|
17
|
+
/** User email */
|
|
18
|
+
email: string;
|
|
19
|
+
/** Issued at timestamp */
|
|
20
|
+
iat?: number;
|
|
21
|
+
/** Expiration timestamp */
|
|
22
|
+
exp?: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Token response containing access and refresh tokens
|
|
26
|
+
*/
|
|
27
|
+
interface AuthTokens {
|
|
28
|
+
/** Short-lived access token */
|
|
29
|
+
accessToken: string;
|
|
30
|
+
/** Long-lived refresh token */
|
|
31
|
+
refreshToken: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Base user interface - minimal fields required by the auth system
|
|
35
|
+
* Consumers should extend this with their own user properties
|
|
36
|
+
*/
|
|
37
|
+
interface BaseUser {
|
|
38
|
+
/** Unique user identifier */
|
|
39
|
+
id: string;
|
|
40
|
+
/** User email address */
|
|
41
|
+
email: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Full auth user interface combining all auth-related fields
|
|
45
|
+
*/
|
|
46
|
+
interface AuthUser extends BaseUser {
|
|
47
|
+
passwordHash: string;
|
|
48
|
+
hashedRefreshToken: string | null;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Login credentials
|
|
52
|
+
*/
|
|
53
|
+
interface LoginCredentials {
|
|
54
|
+
email: string;
|
|
55
|
+
password: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Registration data
|
|
59
|
+
*/
|
|
60
|
+
interface RegisterData {
|
|
61
|
+
email: string;
|
|
62
|
+
password: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* User service interface that consumers must implement
|
|
67
|
+
* This is the contract between the auth library and your application's user management
|
|
68
|
+
*/
|
|
69
|
+
interface UserServiceInterface<TUser extends AuthUser = AuthUser> {
|
|
70
|
+
/**
|
|
71
|
+
* Find a user by their email address
|
|
72
|
+
* Used during login to validate credentials
|
|
73
|
+
*/
|
|
74
|
+
findByEmail(email: string): Promise<TUser | null>;
|
|
75
|
+
/**
|
|
76
|
+
* Find a user by their ID
|
|
77
|
+
* Used for token validation and user retrieval
|
|
78
|
+
*/
|
|
79
|
+
findById(id: string): Promise<TUser | null>;
|
|
80
|
+
/**
|
|
81
|
+
* Create a new user with hashed password
|
|
82
|
+
* Called during registration
|
|
83
|
+
*/
|
|
84
|
+
createUser(data: {
|
|
85
|
+
email: string;
|
|
86
|
+
passwordHash: string;
|
|
87
|
+
}): Promise<TUser>;
|
|
88
|
+
/**
|
|
89
|
+
* Update the user's hashed refresh token
|
|
90
|
+
* Called after login/refresh to store the new refresh token
|
|
91
|
+
* Pass null to clear the token (logout)
|
|
92
|
+
*/
|
|
93
|
+
updateRefreshToken(userId: string, hashedToken: string | null): Promise<void>;
|
|
94
|
+
/**
|
|
95
|
+
* Validate that the provided refresh token matches the stored one
|
|
96
|
+
* Should compare hashed values
|
|
97
|
+
*/
|
|
98
|
+
validateRefreshToken(userId: string, hashedToken: string): Promise<boolean>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Injection token for the user service
|
|
102
|
+
*/
|
|
103
|
+
declare const LENAN_USER_SERVICE: unique symbol;
|
|
104
|
+
/**
|
|
105
|
+
* Configuration options for the auth module
|
|
106
|
+
*/
|
|
107
|
+
interface AuthModuleOptions {
|
|
108
|
+
/** Secret key for signing JWT access tokens */
|
|
109
|
+
jwtSecret: string;
|
|
110
|
+
/** Access token expiration time (e.g., '15m', '1h') */
|
|
111
|
+
jwtAccessExpiry?: string;
|
|
112
|
+
/** Refresh token expiration time (e.g., '7d', '30d') */
|
|
113
|
+
jwtRefreshExpiry?: string;
|
|
114
|
+
/** Optional separate secret for refresh tokens (defaults to jwtSecret + '_refresh') */
|
|
115
|
+
jwtRefreshSecret?: string;
|
|
116
|
+
/** Whether to register the default AuthController (default: true) */
|
|
117
|
+
useController?: boolean;
|
|
118
|
+
/** Global route prefix for auth endpoints (default: 'auth') */
|
|
119
|
+
routePrefix?: string;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Async configuration options for the auth module
|
|
123
|
+
*/
|
|
124
|
+
interface AuthModuleAsyncOptions {
|
|
125
|
+
/**
|
|
126
|
+
* Imports required for the factory/useClass
|
|
127
|
+
*/
|
|
128
|
+
imports?: any[];
|
|
129
|
+
/**
|
|
130
|
+
* Factory function to create the options
|
|
131
|
+
*/
|
|
132
|
+
useFactory?: (...args: any[]) => Promise<AuthModuleOptions> | AuthModuleOptions;
|
|
133
|
+
/**
|
|
134
|
+
* Dependencies to inject into the factory
|
|
135
|
+
*/
|
|
136
|
+
inject?: any[];
|
|
137
|
+
/**
|
|
138
|
+
* Class that implements AuthOptionsFactory
|
|
139
|
+
*/
|
|
140
|
+
useClass?: new (...args: any[]) => AuthOptionsFactory;
|
|
141
|
+
/**
|
|
142
|
+
* Existing provider to use
|
|
143
|
+
*/
|
|
144
|
+
useExisting?: new (...args: any[]) => AuthOptionsFactory;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Factory interface for creating auth options
|
|
148
|
+
*/
|
|
149
|
+
interface AuthOptionsFactory {
|
|
150
|
+
createAuthOptions(): Promise<AuthModuleOptions> | AuthModuleOptions;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Injection token for auth module options
|
|
154
|
+
*/
|
|
155
|
+
declare const LENAN_AUTH_OPTIONS: unique symbol;
|
|
156
|
+
/**
|
|
157
|
+
* Request with user attached (after authentication)
|
|
158
|
+
*/
|
|
159
|
+
interface AuthenticatedRequest<TUser extends BaseUser = BaseUser> extends Request {
|
|
160
|
+
user: TUser;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* JWT payload for access tokens
|
|
164
|
+
*/
|
|
165
|
+
interface AccessTokenPayload {
|
|
166
|
+
sub: string;
|
|
167
|
+
email: string;
|
|
168
|
+
type: "access";
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* JWT payload for refresh tokens
|
|
172
|
+
*/
|
|
173
|
+
interface RefreshTokenPayload {
|
|
174
|
+
sub: string;
|
|
175
|
+
email: string;
|
|
176
|
+
type: "refresh";
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Lenan Auth Module for NestJS
|
|
181
|
+
*
|
|
182
|
+
* A flexible authentication module supporting JWT access/refresh tokens.
|
|
183
|
+
* Requires consumers to implement UserServiceInterface.
|
|
184
|
+
*
|
|
185
|
+
* @example
|
|
186
|
+
* ```typescript
|
|
187
|
+
* // Sync registration
|
|
188
|
+
* @Module({
|
|
189
|
+
* imports: [
|
|
190
|
+
* LenanAuthModule.register({
|
|
191
|
+
* jwtSecret: 'your-secret',
|
|
192
|
+
* jwtAccessExpiry: '15m',
|
|
193
|
+
* jwtRefreshExpiry: '7d',
|
|
194
|
+
* }, UserService),
|
|
195
|
+
* ],
|
|
196
|
+
* })
|
|
197
|
+
* export class AppModule {}
|
|
198
|
+
*
|
|
199
|
+
* // Async registration with ConfigService
|
|
200
|
+
* @Module({
|
|
201
|
+
* imports: [
|
|
202
|
+
* LenanAuthModule.registerAsync({
|
|
203
|
+
* imports: [ConfigModule],
|
|
204
|
+
* useFactory: (config: ConfigService) => ({
|
|
205
|
+
* jwtSecret: config.get('JWT_SECRET'),
|
|
206
|
+
* jwtAccessExpiry: config.get('JWT_ACCESS_EXPIRY', '15m'),
|
|
207
|
+
* jwtRefreshExpiry: config.get('JWT_REFRESH_EXPIRY', '7d'),
|
|
208
|
+
* }),
|
|
209
|
+
* inject: [ConfigService],
|
|
210
|
+
* }, UserService),
|
|
211
|
+
* ],
|
|
212
|
+
* })
|
|
213
|
+
* export class AppModule {}
|
|
214
|
+
* ```
|
|
215
|
+
*/
|
|
216
|
+
declare class LenanAuthModule {
|
|
217
|
+
/**
|
|
218
|
+
* Register the auth module with synchronous configuration
|
|
219
|
+
*
|
|
220
|
+
* @param options - Auth module configuration options
|
|
221
|
+
* @param userService - Your UserService class implementing UserServiceInterface
|
|
222
|
+
*/
|
|
223
|
+
static register(options: AuthModuleOptions, userService: Type<UserServiceInterface>): DynamicModule;
|
|
224
|
+
/**
|
|
225
|
+
* Register the auth module with async configuration
|
|
226
|
+
*
|
|
227
|
+
* @param asyncOptions - Async configuration options
|
|
228
|
+
* @param userService - Your UserService class implementing UserServiceInterface
|
|
229
|
+
*/
|
|
230
|
+
static registerAsync(asyncOptions: AuthModuleAsyncOptions, userService: Type<UserServiceInterface>): DynamicModule;
|
|
231
|
+
private static createProviders;
|
|
232
|
+
private static createAsyncProviders;
|
|
233
|
+
private static createAsyncOptionsProvider;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Login request DTO
|
|
238
|
+
*/
|
|
239
|
+
declare class LoginDto {
|
|
240
|
+
email: string;
|
|
241
|
+
password: string;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Registration request DTO
|
|
245
|
+
*/
|
|
246
|
+
declare class RegisterDto {
|
|
247
|
+
email: string;
|
|
248
|
+
password: string;
|
|
249
|
+
confirmPassword: string;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Refresh token request DTO
|
|
253
|
+
*/
|
|
254
|
+
declare class RefreshTokenDto {
|
|
255
|
+
refreshToken: string;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Token response DTO
|
|
259
|
+
*/
|
|
260
|
+
declare class TokensResponseDto {
|
|
261
|
+
accessToken: string;
|
|
262
|
+
refreshToken: string;
|
|
263
|
+
constructor(accessToken: string, refreshToken: string);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Message response DTO
|
|
267
|
+
*/
|
|
268
|
+
declare class MessageResponseDto {
|
|
269
|
+
message: string;
|
|
270
|
+
constructor(message: string);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Service for JWT token generation and verification
|
|
275
|
+
*/
|
|
276
|
+
declare class JwtTokenService {
|
|
277
|
+
private readonly jwtService;
|
|
278
|
+
private readonly accessExpiry;
|
|
279
|
+
private readonly refreshExpiry;
|
|
280
|
+
private readonly accessSecret;
|
|
281
|
+
private readonly refreshSecret;
|
|
282
|
+
constructor(jwtService: JwtService, options: AuthModuleOptions);
|
|
283
|
+
/**
|
|
284
|
+
* Generate access and refresh tokens for a user
|
|
285
|
+
*/
|
|
286
|
+
generateTokens(userId: string, email: string): Promise<AuthTokens>;
|
|
287
|
+
/**
|
|
288
|
+
* Generate an access token
|
|
289
|
+
*/
|
|
290
|
+
generateAccessToken(userId: string, email: string): Promise<string>;
|
|
291
|
+
/**
|
|
292
|
+
* Generate a refresh token
|
|
293
|
+
*/
|
|
294
|
+
generateRefreshToken(userId: string, email: string): Promise<string>;
|
|
295
|
+
/**
|
|
296
|
+
* Verify an access token and return its payload
|
|
297
|
+
*/
|
|
298
|
+
verifyAccessToken(token: string): Promise<AccessTokenPayload | null>;
|
|
299
|
+
/**
|
|
300
|
+
* Verify a refresh token and return its payload
|
|
301
|
+
*/
|
|
302
|
+
verifyRefreshToken(token: string): Promise<RefreshTokenPayload | null>;
|
|
303
|
+
/**
|
|
304
|
+
* Decode a token without verification (useful for debugging)
|
|
305
|
+
*/
|
|
306
|
+
decodeToken<T = any>(token: string): T | null;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Service for password hashing and comparison using bcrypt
|
|
311
|
+
*/
|
|
312
|
+
declare class PasswordService {
|
|
313
|
+
private readonly saltRounds;
|
|
314
|
+
/**
|
|
315
|
+
* Hash a plain text password
|
|
316
|
+
*/
|
|
317
|
+
hash(password: string): Promise<string>;
|
|
318
|
+
/**
|
|
319
|
+
* Compare a plain text password with a hash
|
|
320
|
+
*/
|
|
321
|
+
compare(password: string, hash: string): Promise<boolean>;
|
|
322
|
+
/**
|
|
323
|
+
* Hash a refresh token for storage
|
|
324
|
+
* Uses fewer rounds since refresh tokens are already random
|
|
325
|
+
*/
|
|
326
|
+
hashToken(token: string): Promise<string>;
|
|
327
|
+
/**
|
|
328
|
+
* Compare a refresh token with its hash
|
|
329
|
+
*/
|
|
330
|
+
compareToken(token: string, hash: string): Promise<boolean>;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Main authentication service
|
|
335
|
+
* Orchestrates user authentication, registration, and token management
|
|
336
|
+
*/
|
|
337
|
+
declare class AuthService {
|
|
338
|
+
private readonly userService;
|
|
339
|
+
private readonly passwordService;
|
|
340
|
+
private readonly jwtTokenService;
|
|
341
|
+
constructor(userService: UserServiceInterface, passwordService: PasswordService, jwtTokenService: JwtTokenService);
|
|
342
|
+
/**
|
|
343
|
+
* Register a new user
|
|
344
|
+
* @throws ConflictException if email already exists
|
|
345
|
+
*/
|
|
346
|
+
register(dto: RegisterDto): Promise<AuthTokens>;
|
|
347
|
+
/**
|
|
348
|
+
* Authenticate a user with email and password
|
|
349
|
+
* @throws UnauthorizedException if credentials are invalid
|
|
350
|
+
*/
|
|
351
|
+
login(dto: LoginDto): Promise<AuthTokens>;
|
|
352
|
+
/**
|
|
353
|
+
* Refresh tokens using a valid refresh token
|
|
354
|
+
* @throws UnauthorizedException if refresh token is invalid
|
|
355
|
+
*/
|
|
356
|
+
refreshTokens(userId: string, refreshToken: string): Promise<AuthTokens>;
|
|
357
|
+
/**
|
|
358
|
+
* Log out a user by clearing their refresh token
|
|
359
|
+
*/
|
|
360
|
+
logout(userId: string): Promise<void>;
|
|
361
|
+
/**
|
|
362
|
+
* Validate a user exists by ID
|
|
363
|
+
* Used by JWT strategy to validate token payloads
|
|
364
|
+
*/
|
|
365
|
+
validateUser(userId: string): Promise<AuthUser | null>;
|
|
366
|
+
/**
|
|
367
|
+
* Get current user by ID (without sensitive fields)
|
|
368
|
+
*/
|
|
369
|
+
getCurrentUser(userId: string): Promise<Omit<AuthUser, "passwordHash" | "hashedRefreshToken"> | null>;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
declare const JwtAuthGuard_base: _nestjs_passport.Type<_nestjs_passport.IAuthGuard>;
|
|
373
|
+
/**
|
|
374
|
+
* JWT Auth Guard for protecting routes
|
|
375
|
+
* Uses the 'lenan-jwt' strategy to validate access tokens
|
|
376
|
+
* Respects the @Public() decorator to skip authentication
|
|
377
|
+
*/
|
|
378
|
+
declare class JwtAuthGuard extends JwtAuthGuard_base {
|
|
379
|
+
private reflector;
|
|
380
|
+
constructor(reflector: Reflector);
|
|
381
|
+
canActivate(context: ExecutionContext): boolean | Promise<boolean> | rxjs.Observable<boolean>;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
declare const RefreshTokenGuard_base: _nestjs_passport.Type<_nestjs_passport.IAuthGuard>;
|
|
385
|
+
/**
|
|
386
|
+
* Refresh Token Guard for protecting the refresh endpoint
|
|
387
|
+
* Uses the 'lenan-jwt-refresh' strategy to validate refresh tokens
|
|
388
|
+
*/
|
|
389
|
+
declare class RefreshTokenGuard extends RefreshTokenGuard_base {
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
declare const JwtStrategy_base: new (...args: [opt: passport_jwt.StrategyOptionsWithRequest] | [opt: passport_jwt.StrategyOptionsWithoutRequest]) => Strategy & {
|
|
393
|
+
validate(...args: any[]): unknown;
|
|
394
|
+
};
|
|
395
|
+
/**
|
|
396
|
+
* JWT Strategy for validating access tokens
|
|
397
|
+
* Extracts token from Authorization header and validates against the user service
|
|
398
|
+
*/
|
|
399
|
+
declare class JwtStrategy extends JwtStrategy_base {
|
|
400
|
+
private readonly userService;
|
|
401
|
+
constructor(options: AuthModuleOptions, userService: UserServiceInterface);
|
|
402
|
+
/**
|
|
403
|
+
* Validate the JWT payload and return the user
|
|
404
|
+
* This is called by Passport after successfully verifying the token signature
|
|
405
|
+
*/
|
|
406
|
+
validate(payload: AccessTokenPayload): Promise<{
|
|
407
|
+
id: string;
|
|
408
|
+
email: string;
|
|
409
|
+
}>;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
declare const RefreshTokenStrategy_base: new (...args: [opt: passport_jwt.StrategyOptionsWithRequest] | [opt: passport_jwt.StrategyOptionsWithoutRequest]) => Strategy & {
|
|
413
|
+
validate(...args: any[]): unknown;
|
|
414
|
+
};
|
|
415
|
+
/**
|
|
416
|
+
* Refresh Token Strategy for validating refresh tokens
|
|
417
|
+
* Extracts token from request body and validates it
|
|
418
|
+
*/
|
|
419
|
+
declare class RefreshTokenStrategy extends RefreshTokenStrategy_base {
|
|
420
|
+
private readonly userService;
|
|
421
|
+
constructor(options: AuthModuleOptions, userService: UserServiceInterface);
|
|
422
|
+
/**
|
|
423
|
+
* Validate the refresh token payload
|
|
424
|
+
* Returns user with the refresh token attached for further validation
|
|
425
|
+
*/
|
|
426
|
+
validate(req: Request$1, payload: RefreshTokenPayload): Promise<{
|
|
427
|
+
refreshToken: any;
|
|
428
|
+
passwordHash: string;
|
|
429
|
+
hashedRefreshToken: string | null;
|
|
430
|
+
id: string;
|
|
431
|
+
email: string;
|
|
432
|
+
}>;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Metadata key for public routes
|
|
437
|
+
*/
|
|
438
|
+
declare const IS_PUBLIC_KEY = "isPublic";
|
|
439
|
+
/**
|
|
440
|
+
* Mark a route as public (no authentication required)
|
|
441
|
+
* Use this decorator on routes that should be accessible without a valid JWT
|
|
442
|
+
*
|
|
443
|
+
* @example
|
|
444
|
+
* ```typescript
|
|
445
|
+
* @Public()
|
|
446
|
+
* @Get('health')
|
|
447
|
+
* healthCheck() {
|
|
448
|
+
* return { status: 'ok' };
|
|
449
|
+
* }
|
|
450
|
+
* ```
|
|
451
|
+
*/
|
|
452
|
+
declare const Public: () => _nestjs_common.CustomDecorator<string>;
|
|
453
|
+
/**
|
|
454
|
+
* Extract the current authenticated user from the request
|
|
455
|
+
* Can optionally extract a specific property from the user object
|
|
456
|
+
*
|
|
457
|
+
* @example
|
|
458
|
+
* ```typescript
|
|
459
|
+
* // Get the entire user object
|
|
460
|
+
* @Get('profile')
|
|
461
|
+
* getProfile(@CurrentUser() user: User) {
|
|
462
|
+
* return user;
|
|
463
|
+
* }
|
|
464
|
+
*
|
|
465
|
+
* // Get a specific property
|
|
466
|
+
* @Get('my-id')
|
|
467
|
+
* getMyId(@CurrentUser('id') userId: string) {
|
|
468
|
+
* return { id: userId };
|
|
469
|
+
* }
|
|
470
|
+
* ```
|
|
471
|
+
*/
|
|
472
|
+
declare const CurrentUser: (...dataOrPipes: (string | _nestjs_common.PipeTransform<any, any> | _nestjs_common.Type<_nestjs_common.PipeTransform<any, any>> | undefined)[]) => ParameterDecorator;
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* Authentication controller providing standard auth endpoints
|
|
476
|
+
* This controller is optional - consumers can disable it and implement their own
|
|
477
|
+
*/
|
|
478
|
+
declare class AuthController {
|
|
479
|
+
private readonly authService;
|
|
480
|
+
constructor(authService: AuthService);
|
|
481
|
+
/**
|
|
482
|
+
* Register a new user
|
|
483
|
+
* POST /auth/register
|
|
484
|
+
*/
|
|
485
|
+
register(dto: RegisterDto): Promise<TokensResponseDto>;
|
|
486
|
+
/**
|
|
487
|
+
* Login with email and password
|
|
488
|
+
* POST /auth/login
|
|
489
|
+
*/
|
|
490
|
+
login(dto: LoginDto): Promise<TokensResponseDto>;
|
|
491
|
+
/**
|
|
492
|
+
* Refresh access token using refresh token
|
|
493
|
+
* POST /auth/refresh
|
|
494
|
+
*/
|
|
495
|
+
refresh(user: BaseUser & {
|
|
496
|
+
refreshToken: string;
|
|
497
|
+
}): Promise<TokensResponseDto>;
|
|
498
|
+
/**
|
|
499
|
+
* Logout (invalidate refresh token)
|
|
500
|
+
* POST /auth/logout
|
|
501
|
+
*/
|
|
502
|
+
logout(userId: string): Promise<MessageResponseDto>;
|
|
503
|
+
/**
|
|
504
|
+
* Get current authenticated user
|
|
505
|
+
* GET /auth/me
|
|
506
|
+
*/
|
|
507
|
+
me(user: BaseUser): Promise<BaseUser>;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export { type AccessTokenPayload, AuthController, type AuthModuleAsyncOptions, type AuthModuleOptions, type AuthOptionsFactory, AuthService, type AuthTokens, type AuthUser, type AuthenticatedRequest, type BaseUser, CurrentUser, IS_PUBLIC_KEY, JwtAuthGuard, type JwtPayload, JwtStrategy, JwtTokenService, LENAN_AUTH_OPTIONS, LENAN_USER_SERVICE, LenanAuthModule, type LoginCredentials, LoginDto, MessageResponseDto, PasswordService, Public, RefreshTokenDto, RefreshTokenGuard, type RefreshTokenPayload, RefreshTokenStrategy, type RegisterData, RegisterDto, TokensResponseDto, type UserServiceInterface };
|