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