@nestjs-kitchen/authz 1.0.0 → 1.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 yikenman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -0,0 +1,166 @@
1
+ # @nestjs-kitchen/authz
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/%40nestjs-kitchen%2Fauthz)
4
+ ](https://www.npmjs.com/package/@nestjs-kitchen/authz)
5
+ ![NPM License](https://img.shields.io/npm/l/%40nestjs-kitchen%2Fauthz)
6
+ [![codecov](https://codecov.io/gh/yikenman/nestjs-kitchen/graph/badge.svg?token=43EG2T8LKS&flag=@nestjs-kitchen/authz)](https://codecov.io/gh/yikenman/nestjs-kitchen)
7
+
8
+ Simplest authentication & authorization module in NextJS.
9
+
10
+ ---
11
+
12
+
13
+ ## Description
14
+
15
+ **@nestjs-kitchen/authz** is an easy-to-use TypeScript library to apply JWT/Session authentication and authorization to your NestJS application within **4** steps.
16
+
17
+ ## Features
18
+
19
+ - JWT based authentication
20
+ - Session based authentication
21
+ - Customizable authorization
22
+ - Simplified setups and APIs
23
+ - Anonymous access support
24
+ - Simultaneous multiple strategy (JWT/Session) uses
25
+
26
+ ## Install
27
+
28
+ Once completed NestJS project setup, install this package and its dependencies:
29
+
30
+ ```bash
31
+ $ npm install --save @nestjs/passport passport @nestjs-kitchen/authz
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ 1. Create file `authz.provider.ts`:
37
+
38
+ ```typescript
39
+ // authz.provider.ts
40
+ import { Injectable } from '@nestjs/common';
41
+ import { AuthzProviderClass } from '@nestjs-kitchen/authz';
42
+
43
+ // The type representing the payload used for authentication.
44
+ interface Payload {
45
+ // ...
46
+ }
47
+
48
+ // The type representing the user entity involved in authentication and authorization.
49
+ export interface User {
50
+ // ...
51
+ }
52
+
53
+ @Injectable()
54
+ export class AuthzProvider extends AuthzProviderClass<Payload, User> {
55
+ authenticate(payload: Payload) {
56
+ // Return payload.
57
+ };
58
+
59
+ createPayload(user: User) {
60
+ // Return user entity.
61
+ };
62
+ }
63
+ ```
64
+
65
+ 2. Create file `authz.module.ts`:
66
+
67
+ ```typescript
68
+ // authz.module.ts
69
+ import { createJwtAuthzModule } from '@nestjs-kitchen/authz';
70
+ import { AuthzProvider } from './authz.provider.ts';
71
+
72
+ export const {
73
+ AuthzGuard,
74
+ AuthzService,
75
+ AuthzModule
76
+ } = createJwtAuthzModule(AuthzProvider);
77
+
78
+ // Fix typescript type hint error
79
+ export type AuthzService = InstanceType<typeof AuthzService>;
80
+ ```
81
+
82
+ 3. Use AuthzGuard in your business controller:
83
+
84
+ ```typescript
85
+ // business.controller.ts
86
+ import { Controller, Get, Query, UseGuards } from '@nestjs/common';
87
+ import { AuthzGuard, AuthzService } from './authz.module';
88
+
89
+ @UseGuards(AuthzGuard)
90
+ @Controller('apply-on-both')
91
+ export class BusinessController {
92
+ constructor(private readonly authzService: AuthzService) {}
93
+
94
+ // Escape from AuthzGuard
95
+ @AuthzGuard.NoVerify()
96
+ @Get('log-in')
97
+ async logIn() {
98
+ // get user from db or other api.
99
+ const user = // ...
100
+ // call AuthzService.login to create JWT.
101
+ const result = await this.authzService.logIn(user);
102
+ return result;
103
+ }
104
+
105
+ @Get('get-user')
106
+ async getUser() {
107
+ // AuthzService.getUser can get current request user across services.
108
+ const user = await this.authzService.getUser();
109
+ return user;
110
+ }
111
+ }
112
+ ```
113
+
114
+ 4. Import AuthzModule
115
+
116
+ ```typescript
117
+ // business.module.ts
118
+ import { Module } from '@nestjs/common';
119
+ import { ExtractJwt } from '@nestjs-kitchen/authz';
120
+ import { AuthzModule } from './authz.module';
121
+ import { BusinessController } from './business.controller';
122
+
123
+ @Module({
124
+ imports: [
125
+ // Import and configure JWT strategy
126
+ AuthzModule.register({
127
+ jwt: {
128
+ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
129
+ secret: '1234567890',
130
+ algorithm: 'HS256'
131
+ },
132
+ // Apply strategy to specific controllers.
133
+ routes: [BusinessController]
134
+ })
135
+ ],
136
+ controllers: [BusinessController]
137
+ })
138
+ export class BusinessModule {}
139
+ ```
140
+
141
+ ## Errors
142
+
143
+ The following errors may be thrown during authentication and authorization:
144
+
145
+ - AuthzError: The base error type.
146
+ - AuthzVerificationError: Thrown when authentication fails.
147
+ - AuthzAnonymousError: Thrown when authentication returns empty.
148
+
149
+ ### Error handling
150
+
151
+ See [Catch everything](https://docs.nestjs.com/exception-filters#catch-everything) for handling custom error types.
152
+
153
+ ## Examples
154
+
155
+ Find more scenarios:
156
+
157
+ - [Authenticate with JWT](./docs/authenticate-with-jwt.md)
158
+ - [Authenticate & authorize with JWT](./docs/authenticate-&-authorize-with-jwt.md)
159
+ - [Authenticate with Session](./docs/authenticate-with-session.md)
160
+ - [Authenticate & authorize with Session](./docs/authenticate-&-authorize-with-session.md)
161
+ - [Use JWT with refresh token](./docs/use-jwt-with-refresh-token.md)
162
+ - [Use JWT and refresh token via session](./docs/use-jwt-and-refresh-token-via-session.md)
163
+
164
+ ## License
165
+
166
+ MIT License
@@ -1,7 +1,46 @@
1
+ /**
2
+ * Abstract base class for implementing custom authorization logic.
3
+ *
4
+ * @template Payload - The type representing the payload used for authentication.
5
+ * @template User - The type representing the user entity involved in authentication and authorization.
6
+ */
1
7
  declare abstract class AuthzProviderClass<Payload, User> {
8
+ /**
9
+ * Creates a payload from the given user.
10
+ *
11
+ * This method is intended to transform a user entity into a payload, which can be used
12
+ * for token generation or other authentication mechanisms.
13
+ *
14
+ * @param {User} user - The user entity to create the payload for.
15
+ * @returns {Payload | Promise<Payload>} A payload derived from the user entity,
16
+ * or a promise resolving to the payload.
17
+ */
2
18
  abstract createPayload(user: User): Payload | Promise<Payload>;
19
+ /**
20
+ * Authenticates a given payload to retrieve a user.
21
+ *
22
+ * This method is used to validate a payload and map it back to a user entity,
23
+ * typically as part of a token-based authentication workflow.
24
+ *
25
+ * @param {Payload} payload - The payload to authenticate.
26
+ * @returns {User | Promise<User>} The authenticated user, or a promise resolving to the user.
27
+ */
3
28
  abstract authenticate(payload: Payload): User | Promise<User>;
4
- authorize(_uesr: User, _metaData?: unknown): boolean | Promise<boolean>;
29
+ /**
30
+ * (**Optional**: Implement this method only if authorization is required.)
31
+ *
32
+ * Authorizes a user based on the provided metadata.
33
+ *
34
+ * This method checks if the given user is authorized to perform a specific action based on
35
+ * the provided metadata. If implemented, this method enables the authorization check; otherwise,
36
+ * only authentication will be performed.
37
+ *
38
+ * @param {User} _user - The user entity that needs to be authorized.
39
+ * @param {unknown} [_metaData] - Optional metadata that can influence the authorization decision.
40
+ * @returns {boolean | Promise<boolean>} `true` if the user is authorized, `false` otherwise,
41
+ * or a promise that resolves to the authorization result.
42
+ */
43
+ authorize(_user: User, _metaData?: unknown): boolean | Promise<boolean>;
5
44
  }
6
45
 
7
46
  export { AuthzProviderClass };
@@ -22,7 +22,21 @@ __export(authz_provider_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(authz_provider_exports);
24
24
  const _AuthzProviderClass = class _AuthzProviderClass {
25
- authorize(_uesr, _metaData) {
25
+ /**
26
+ * (**Optional**: Implement this method only if authorization is required.)
27
+ *
28
+ * Authorizes a user based on the provided metadata.
29
+ *
30
+ * This method checks if the given user is authorized to perform a specific action based on
31
+ * the provided metadata. If implemented, this method enables the authorization check; otherwise,
32
+ * only authentication will be performed.
33
+ *
34
+ * @param {User} _user - The user entity that needs to be authorized.
35
+ * @param {unknown} [_metaData] - Optional metadata that can influence the authorization decision.
36
+ * @returns {boolean | Promise<boolean>} `true` if the user is authorized, `false` otherwise,
37
+ * or a promise that resolves to the authorization result.
38
+ */
39
+ authorize(_user, _metaData) {
26
40
  return true;
27
41
  }
28
42
  };
package/dist/errors.d.ts CHANGED
@@ -1,10 +1,19 @@
1
+ /**
2
+ * Internal error type.
3
+ */
1
4
  declare class AuthzError extends Error {
2
5
  cause?: unknown;
3
6
  constructor(message?: string, cause?: unknown);
4
7
  }
8
+ /**
9
+ * Internal error type for verification error.
10
+ */
5
11
  declare class AuthzVerificationError extends AuthzError {
6
12
  constructor(message?: string, cause?: unknown);
7
13
  }
14
+ /**
15
+ * Internal error type for anonymous error.
16
+ */
8
17
  declare class AuthzAnonymousError extends AuthzError {
9
18
  constructor(message?: string, cause?: unknown);
10
19
  }
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export { AuthzProviderClass } from './authz.provider.js';
2
2
  export { User } from './user.decorator.js';
3
- export { AuthzError, AuthzVerificationError } from './errors.js';
3
+ export { AuthzAnonymousError, AuthzError, AuthzVerificationError } from './errors.js';
4
4
  export { ExtractJwt, JwtFromRequestFunction } from './jwt/extract-jwt.js';
5
5
  export { createJwtAuthzModule } from './jwt/jwt-authz.module.js';
6
6
  export { cereateSessionAuthzModule } from './session/session-authz.module.js';
package/dist/index.js CHANGED
@@ -17,6 +17,7 @@ var __copyProps = (to, from, except, desc) => {
17
17
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
18
  var src_exports = {};
19
19
  __export(src_exports, {
20
+ AuthzAnonymousError: () => import_errors.AuthzAnonymousError,
20
21
  AuthzError: () => import_errors.AuthzError,
21
22
  AuthzProviderClass: () => import_authz.AuthzProviderClass,
22
23
  AuthzVerificationError: () => import_errors.AuthzVerificationError,
@@ -33,6 +34,7 @@ var import_jwt = require("./jwt");
33
34
  var import_session = require("./session");
34
35
  // Annotate the CommonJS export names for ESM import in node:
35
36
  0 && (module.exports = {
37
+ AuthzAnonymousError,
36
38
  AuthzError,
37
39
  AuthzProviderClass,
38
40
  AuthzVerificationError,
@@ -7,6 +7,11 @@ declare const parseAuthHeader: (hdrValue: unknown) => {
7
7
  interface JwtFromRequestFunction<T = any> {
8
8
  (req: T): string | null;
9
9
  }
10
+ /**
11
+ * Utility factory function for creating extractor functions that retrieve JWT from HTTP requests.
12
+ *
13
+ * Same as `passportjs` [jwt extractors](https://www.passportjs.org/packages/passport-jwt/#included-extractors)
14
+ */
10
15
  declare const ExtractJwt: {
11
16
  /**
12
17
  * Creates an extractor function to retrieve a token from the request header.
@@ -103,24 +103,21 @@ const createJwtAuthzGuard = /* @__PURE__ */ __name(([JWT_STRATEGY, AUTHZ_PROVIDE
103
103
  context.getClass(),
104
104
  context.getHandler()
105
105
  ]));
106
+ if (paramsList.length && Boolean(paramsList[paramsList.length - 1].options?.public)) {
107
+ store.guardResult = true;
108
+ return true;
109
+ }
106
110
  const contextParamsList = (0, import_utils.getContextAuthzMetaParamsList)(paramsList, {
107
111
  defaultOverride: this.jwtAuthzOptions.defaultOverride,
108
112
  skipFalsyMetadata: this.jwtAuthzOptions.skipFalsyMetadata
109
113
  });
110
- if (!contextParamsList.length) {
111
- return true;
112
- }
113
114
  const req = context.switchToHttp().getRequest();
114
115
  store.allowAnonymous = (0, import_utils.getAllowAnonymous)(contextParamsList, {
115
116
  defaultAllowAnonymous: this.jwtAuthzOptions.defaultAllowAnonymous
116
117
  });
117
118
  await super.canActivate(context);
118
- if (typeof this.authzProvider.authorize !== "function") {
119
- store.guardResult = true;
120
- return true;
121
- }
122
119
  const user = (0, import_utils.getPassportProperty)(req);
123
- if (!user && store.allowAnonymous) {
120
+ if (store.allowAnonymous && !user) {
124
121
  return true;
125
122
  }
126
123
  for (const ele of contextParamsList) {
@@ -9,13 +9,39 @@ import '../authz.provider.js';
9
9
  import 'cookie';
10
10
 
11
11
  type JwtOptions = Omit<VerifyOptions, 'algorithms' | 'audience' | 'issuer'> & SignOptions & {
12
+ /**
13
+ * Function that accepts a request as the only parameter and returns either the JWT as a string or null.
14
+ *
15
+ * Same as `passport-jwt` [jwtFromRequest option](https://www.passportjs.org/packages/passport-jwt/#configure-strategy).
16
+ */
12
17
  jwtFromRequest: JwtFromRequestFunction | JwtFromRequestFunction[];
18
+ /**
19
+ * Secret string used for HMAC algorithms.
20
+ */
13
21
  secret?: Secret;
22
+ /**
23
+ * PEM-encoded private key used for RSA and ECDSA algorithms.
24
+ */
14
25
  privateKey?: PrivateKey;
26
+ /**
27
+ * PEM-encoded public key corresponding to the `privateKey` used for RSA and ECDSA algorithms.
28
+ */
15
29
  publicKey?: PublicKey;
16
30
  };
17
31
  type JwtAuthzModuleOptions = Partial<AuthzModuleBaseOptions> & {
32
+ /**
33
+ * JWT sign & verify options.
34
+ *
35
+ * This combines `jsonwebtoken` [sign options](https://www.npmjs.com/package/jsonwebtoken#jwtsignpayload-secretorprivatekey-options-callback)
36
+ * and [verify options](https://www.npmjs.com/package/jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback).
37
+ */
18
38
  jwt: JwtOptions;
39
+ /**
40
+ * Refresh token sign & verify options.
41
+ *
42
+ * This combines `jsonwebtoken` [sign options](https://www.npmjs.com/package/jsonwebtoken#jwtsignpayload-secretorprivatekey-options-callback)
43
+ * and [verify options](https://www.npmjs.com/package/jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback).
44
+ */
19
45
  refresh?: JwtOptions;
20
46
  };
21
47
  declare const normalizedJwtAuthzModuleOptions: (options: JwtAuthzModuleOptions) => {
@@ -2,7 +2,7 @@ import './extract-jwt.js';
2
2
  import * as _nestjs_core from '@nestjs/core';
3
3
  import { JwtAuthzOptions, JwtAuthzModuleOptions, JwtOptions } from './jwt-authz.interface.js';
4
4
  import { AuthzProviderClass } from '../authz.provider.js';
5
- import { AbstractConstructor, RoutesOptions, AuthzDecoParams, MethodParameters, ApplyDecorators, CookieOptionsWithSecret, AuthzModuleRoutesOptions, AuthzModuleBaseOptions } from '../utils/types.js';
5
+ import { AbstractConstructor, RoutesOptions, AuthzDecoParams, MethodParameters, ApplyDecorators, CookieOptionsWithSecret, DeepReadonly, AuthzModuleRoutesOptions, AuthzModuleBaseOptions } from '../utils/types.js';
6
6
  import { AsyncLocalStorage } from 'node:async_hooks';
7
7
  import * as _nestjs_common from '@nestjs/common';
8
8
  import { MiddlewareConsumer, DynamicModule, Type } from '@nestjs/common';
@@ -24,16 +24,84 @@ declare const OPTIONS_TYPE: Partial<AuthzModuleBaseOptions> & {
24
24
  } & Partial<{
25
25
  authzProvider?: Type<AuthzProviderClass<unknown, unknown>>;
26
26
  } & AuthzModuleRoutesOptions>;
27
+ /**
28
+ * Creates a JWT module along with its associated guard and service,
29
+ * with types inferred from the provided implementation of `AuthzProviderClass`.
30
+ *
31
+ * @param authzProvider - The implementation class of `AuthzProviderClass`
32
+ * @returns \{AuthzModule, AuthzGuard, AuthzService}
33
+ */
27
34
  declare const createJwtAuthzModule: <P, U, T extends AuthzProviderClass<P, U>>(authzProvider: AbstractConstructor<T, P, U>) => {
35
+ /**
36
+ * A dynamic module used to configure JWT based authentication and authorization features for the application.
37
+ *
38
+ * This module can be configured using 2 static methods:
39
+ *
40
+ * - `register`
41
+ * - `registerAsync`
42
+ *
43
+ * ### Usage
44
+ *
45
+ * ```typescript
46
+ * ⁣@Module({
47
+ * imports: [
48
+ * // Import and configure JWT strategy
49
+ * AuthzModule.register({
50
+ * jwt: {
51
+ * jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
52
+ * secret: '1234567890',
53
+ * algorithm: 'HS256'
54
+ * },
55
+ * // Enable refresh token handling
56
+ * refresh: {
57
+ * jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
58
+ * secret: '0987654321',
59
+ * algorithm: 'HS256'
60
+ * },
61
+ * // Apply strategy to specific controllers.
62
+ * routes: [BusinessController]
63
+ * })
64
+ * ],
65
+ * controllers: [BusinessController]
66
+ * })
67
+ * export class BusinessModule {}
68
+ * ```
69
+ */
28
70
  AuthzModule: {
29
71
  new (routesOpt: RoutesOptions): {
30
72
  [x: string]: any;
31
73
  readonly routesOpt: RoutesOptions;
32
74
  configure(consumer: MiddlewareConsumer): void;
33
75
  };
76
+ /**
77
+ * Configures authz module.
78
+ */
34
79
  register(options: Omit<typeof OPTIONS_TYPE, "authzProvider">): DynamicModule;
80
+ /**
81
+ * Configures authz module asynchronously.
82
+ */
35
83
  registerAsync(options: Omit<typeof ASYNC_OPTIONS_TYPE, "authzProvider">): DynamicModule;
36
84
  };
85
+ /**
86
+ * A custom guard that applies authentication to controllers.
87
+ *
88
+ * This guard also provides 4 utility decorators to apply and modify authorization:
89
+ *
90
+ * - `@AuthzGuard.Verify`: Used to verify the user's authorization for specific meta data.
91
+ * - `@AuthzGuard.NoVerify`: Used to `skip` authentication & authorization checks for specific routes.
92
+ * - `@AuthzGuard.Apply`: A simplified version of `@UseGuards(AuthzGuard)` and `@AuthzGuard.Verify`, combining both for convenience.
93
+ * - `@AuthzGuard.Refresh`: Used to ensure that only using refresh token for authentication on specific routes, for refreshing JWT tokens.
94
+ *
95
+ * ### Usage:
96
+ *
97
+ * ```typescript
98
+ * ⁣@UseGuards(AuthzGuard)
99
+ * ⁣@Controller(/⁣/ ...)
100
+ * export class BusinessController {
101
+ * // ...
102
+ * }
103
+ * ```
104
+ */
37
105
  AuthzGuard: Type<Omit<{
38
106
  readonly reflector: _nestjs_core.Reflector;
39
107
  readonly authzProvider: AuthzProviderClass<unknown, unknown>;
@@ -50,14 +118,81 @@ declare const createJwtAuthzModule: <P, U, T extends AuthzProviderClass<P, U>>(a
50
118
  } = any>(request: TRequest): Promise<void>;
51
119
  getRequest(context: _nestjs_common.ExecutionContext): any;
52
120
  }, "als" | "jwtAuthzOptions" | "reflector" | "authzProvider">> & {
121
+ /**
122
+ * Verifies the user's authorization for specific meta data.
123
+ *
124
+ * ### Usage
125
+ *
126
+ * ```typescript
127
+ * ⁣@UseGuards(AuthzGuard)
128
+ * ⁣@Controller(/⁣/ ...)
129
+ * export class BusinessController {
130
+ * ⁣@AuthzGuard.Verify(/⁣/ mata datas used to authorize user)
131
+ * ⁣@Get()
132
+ * async method() {
133
+ * // ...
134
+ * }
135
+ * }
136
+ * ```
137
+ */
53
138
  Verify: (...args: AuthzDecoParams<MethodParameters<T, "authorize">[1]>) => ApplyDecorators;
139
+ /**
140
+ * Skips authentication & authorization checks for specific routes.
141
+ *
142
+ * ### Usage
143
+ *
144
+ * ```typescript
145
+ * ⁣@UseGuards(AuthzGuard)
146
+ * ⁣@Controller(/⁣/ ...)
147
+ * export class BusinessController {
148
+ * ⁣@AuthzGuard.NoVerify()
149
+ * ⁣@Get()
150
+ * async publicMethod() {
151
+ * // ...
152
+ * }
153
+ * }
154
+ * ```
155
+ */
54
156
  NoVerify: () => MethodDecorator & ClassDecorator;
55
157
  /**
56
- * take highest priority
158
+ * Ensures that only the refresh token is used for authentication on specific routes, for refreshing JWT tokens.
159
+ *
160
+ * ### Usage
161
+ *
162
+ * ```typescript
163
+ * ⁣@UseGuards(AuthzGuard)
164
+ * ⁣@Controller(/⁣/ ...)
165
+ * export class BusinessController {
166
+ * ⁣@AuthzGuard.Refresh()
167
+ * ⁣@Get()
168
+ * async refreshToken() {
169
+ * // ...
170
+ * }
171
+ * }
172
+ * ```
57
173
  */
58
174
  Refresh: () => MethodDecorator & ClassDecorator;
175
+ /**
176
+ * A simplified version of `@UseGuards(AuthzGuard)` and `@AuthzGuard.Verify()`, combining both for convenience
177
+ *
178
+ * ### Usage
179
+ *
180
+ * ```typescript
181
+ * ⁣@Controller(/⁣/ ...)
182
+ * export class BusinessController {
183
+ * ⁣@AuthzGuard.Apply(/⁣/ mata datas used to authorize user)
184
+ * ⁣@Get()
185
+ * async refreshToken() {
186
+ * // ...
187
+ * }
188
+ * }
189
+ * ```
190
+ */
59
191
  Apply: (...rest: Parameters<(...args: AuthzDecoParams<MethodParameters<T, "authorize">[1]>) => ApplyDecorators>) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
60
192
  };
193
+ /**
194
+ * A custom servcie to provide methods to handle authentication and authorization.
195
+ */
61
196
  AuthzService: Type<Omit<{
62
197
  readonly authzProvider: AuthzProviderClass<P, U>;
63
198
  readonly jwtAuthzOptions: JwtAuthzOptions;
@@ -73,7 +208,7 @@ declare const createJwtAuthzModule: <P, U, T extends AuthzProviderClass<P, U>>(a
73
208
  token: string;
74
209
  } | undefined>;
75
210
  setCookie(name: string, value: string, options?: CookieOptionsWithSecret | undefined): void;
76
- getUser(): U | undefined;
211
+ getUser(): DeepReadonly<U> | undefined;
77
212
  }, "als" | "jwtAuthzOptions" | "authzProvider">>;
78
213
  };
79
214
 
@@ -185,6 +185,9 @@ const createJwtAuthzModule = /* @__PURE__ */ __name((authzProvider) => {
185
185
  __publicField(this, "routesOpt");
186
186
  this.routesOpt = routesOpt;
187
187
  }
188
+ /**
189
+ * Configures authz module.
190
+ */
188
191
  static register(options) {
189
192
  const jwtAuthzOptions = (0, import_jwt_authz2.normalizedJwtAuthzModuleOptions)(options);
190
193
  return (0, import_utils.mergeDynamicModuleConfigs)(super.register({
@@ -199,6 +202,9 @@ const createJwtAuthzModule = /* @__PURE__ */ __name((authzProvider) => {
199
202
  ]
200
203
  });
201
204
  }
205
+ /**
206
+ * Configures authz module asynchronously.
207
+ */
202
208
  static registerAsync(options) {
203
209
  return (0, import_utils.mergeDynamicModuleConfigs)(super.registerAsync({
204
210
  ...options,
@@ -233,8 +239,66 @@ const createJwtAuthzModule = /* @__PURE__ */ __name((authzProvider) => {
233
239
  ])
234
240
  ], JwtAuthzModule);
235
241
  return {
242
+ /**
243
+ * A dynamic module used to configure JWT based authentication and authorization features for the application.
244
+ *
245
+ * This module can be configured using 2 static methods:
246
+ *
247
+ * - `register`
248
+ * - `registerAsync`
249
+ *
250
+ * ### Usage
251
+ *
252
+ * ```typescript
253
+ * ⁣@Module({
254
+ * imports: [
255
+ * // Import and configure JWT strategy
256
+ * AuthzModule.register({
257
+ * jwt: {
258
+ * jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
259
+ * secret: '1234567890',
260
+ * algorithm: 'HS256'
261
+ * },
262
+ * // Enable refresh token handling
263
+ * refresh: {
264
+ * jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
265
+ * secret: '0987654321',
266
+ * algorithm: 'HS256'
267
+ * },
268
+ * // Apply strategy to specific controllers.
269
+ * routes: [BusinessController]
270
+ * })
271
+ * ],
272
+ * controllers: [BusinessController]
273
+ * })
274
+ * export class BusinessModule {}
275
+ * ```
276
+ */
236
277
  AuthzModule: JwtAuthzModule,
278
+ /**
279
+ * A custom guard that applies authentication to controllers.
280
+ *
281
+ * This guard also provides 4 utility decorators to apply and modify authorization:
282
+ *
283
+ * - `@AuthzGuard.Verify`: Used to verify the user's authorization for specific meta data.
284
+ * - `@AuthzGuard.NoVerify`: Used to `skip` authentication & authorization checks for specific routes.
285
+ * - `@AuthzGuard.Apply`: A simplified version of `@UseGuards(AuthzGuard)` and `@AuthzGuard.Verify`, combining both for convenience.
286
+ * - `@AuthzGuard.Refresh`: Used to ensure that only using refresh token for authentication on specific routes, for refreshing JWT tokens.
287
+ *
288
+ * ### Usage:
289
+ *
290
+ * ```typescript
291
+ * ⁣@UseGuards(AuthzGuard)
292
+ * ⁣@Controller(/⁣/ ...)
293
+ * export class BusinessController {
294
+ * // ...
295
+ * }
296
+ * ```
297
+ */
237
298
  AuthzGuard: JwtAuthzGuard,
299
+ /**
300
+ * A custom servcie to provide methods to handle authentication and authorization.
301
+ */
238
302
  AuthzService: JwtAuthzService
239
303
  };
240
304
  }, "createJwtAuthzModule");
@@ -1,6 +1,6 @@
1
1
  import * as _nestjs_common from '@nestjs/common';
2
2
  import { AuthzProviderClass } from '../authz.provider.js';
3
- import { CookieOptionsWithSecret } from '../utils/types.js';
3
+ import { CookieOptionsWithSecret, DeepReadonly } from '../utils/types.js';
4
4
  import { AsyncLocalStorage } from 'node:async_hooks';
5
5
  import { JwtAlsType } from './jwt-authz-als.middleware.js';
6
6
  import { JwtAuthzOptions } from './jwt-authz.interface.js';
@@ -16,6 +16,14 @@ declare const createJwtAuthzService: <P = unknown, U = unknown>([AUTHZ_PROVIDER,
16
16
  readonly authzProvider: AuthzProviderClass<P, U>;
17
17
  readonly jwtAuthzOptions: JwtAuthzOptions;
18
18
  readonly als: AsyncLocalStorage<JwtAlsType<U>>;
19
+ /**
20
+ * Creates a JWT token with a payload generated by AuthzProviderClass.createPayload(). Optionally, includes a refresh token if configured.
21
+ *
22
+ * @param user - User entity
23
+ * @returns
24
+ * - `token` : The generated JWT access token.
25
+ * - `refresh` (optional): The generated refresh token, if enabled.
26
+ */
19
27
  logIn(user: U): Promise<{
20
28
  token: string;
21
29
  refresh: string;
@@ -23,11 +31,24 @@ declare const createJwtAuthzService: <P = unknown, U = unknown>([AUTHZ_PROVIDER,
23
31
  token: string;
24
32
  refresh?: undefined;
25
33
  }>;
34
+ /**
35
+ * Refreshes the JWT token for the provided user. If no user is provided, it attempts to retrieve the
36
+ * current user and generate a new token.
37
+ *
38
+ * @param [user] - User entity
39
+ * @returns
40
+ */
26
41
  refresh(user?: U): Promise<{
27
42
  token: string;
28
43
  } | undefined>;
44
+ /**
45
+ * Sets a secure HTTP cookie with the given name, value, and optional cookie options.
46
+ */
29
47
  setCookie(name: string, value: string, options?: CookieOptionsWithSecret | undefined): void;
30
- getUser(): U | undefined;
48
+ /**
49
+ * Retrieves the current user associated with the request, if available.
50
+ */
51
+ getUser(): DeepReadonly<U> | undefined;
31
52
  }, "als" | "jwtAuthzOptions" | "authzProvider">>;
32
53
 
33
54
  export { createJwtAuthzService };
@@ -77,6 +77,14 @@ const createJwtAuthzService = /* @__PURE__ */ __name(([AUTHZ_PROVIDER, JWT_AUTHZ
77
77
  throw new import_errors.AuthzError(`InternalError: Missing Refresh sign options.`);
78
78
  }
79
79
  }
80
+ /**
81
+ * Creates a JWT token with a payload generated by AuthzProviderClass.createPayload(). Optionally, includes a refresh token if configured.
82
+ *
83
+ * @param user - User entity
84
+ * @returns
85
+ * - `token` : The generated JWT access token.
86
+ * - `refresh` (optional): The generated refresh token, if enabled.
87
+ */
80
88
  async logIn(user) {
81
89
  const payload = await this.authzProvider.createPayload(user);
82
90
  const token = import_jsonwebtoken.default.sign(payload, this.jwtAuthzOptions.jwt.secretOrPrivateKey, this.jwtAuthzOptions.jwt.sign);
@@ -93,6 +101,13 @@ const createJwtAuthzService = /* @__PURE__ */ __name(([AUTHZ_PROVIDER, JWT_AUTHZ
93
101
  token
94
102
  };
95
103
  }
104
+ /**
105
+ * Refreshes the JWT token for the provided user. If no user is provided, it attempts to retrieve the
106
+ * current user and generate a new token.
107
+ *
108
+ * @param [user] - User entity
109
+ * @returns
110
+ */
96
111
  async refresh(user) {
97
112
  if (!this.jwtAuthzOptions.refresh) {
98
113
  console.warn(`'refresh' method can only be called when configured in module options.`);
@@ -115,10 +130,16 @@ const createJwtAuthzService = /* @__PURE__ */ __name(([AUTHZ_PROVIDER, JWT_AUTHZ
115
130
  token
116
131
  };
117
132
  }
133
+ /**
134
+ * Sets a secure HTTP cookie with the given name, value, and optional cookie options.
135
+ */
118
136
  setCookie(...rest) {
119
137
  const store = (0, import_utils.getAlsStore)(this.als);
120
138
  store.setCookie(...rest);
121
139
  }
140
+ /**
141
+ * Retrieves the current user associated with the request, if available.
142
+ */
122
143
  getUser() {
123
144
  const store = (0, import_utils.getAlsStore)(this.als);
124
145
  const user = store.user;
@@ -17,24 +17,12 @@ declare const createJwtStrategy: ([JWT_STRATEGY, AUTHZ_PROVIDER, ALS_PROVIDER]:
17
17
  readonly als: AsyncLocalStorage<JwtAlsType<unknown>>;
18
18
  validate(req: Request): Promise<{}>;
19
19
  authenticate(req: Request, options?: any): any;
20
- success(user: any, info?: any): void;
21
- fail(challenge: any, status: number): void;
22
- fail(status: number): void;
23
- redirect(url: string, status?: number): void;
24
- pass(): void;
25
- error(err: Error): void;
26
20
  }, "als" | "authzProvider">>;
27
21
  declare const createRefreshStrategy: ([JWT_REFRESH_STRATEGY, AUTHZ_PROVIDER, ALS_PROVIDER]: [string, any, any]) => _nestjs_common.Type<Omit<{
28
22
  readonly authzProvider: AuthzProviderClass<unknown, unknown>;
29
23
  readonly als: AsyncLocalStorage<JwtAlsType<unknown>>;
30
24
  validate(req: Request): Promise<{}>;
31
25
  authenticate(req: Request, options?: any): any;
32
- success(user: any, info?: any): void;
33
- fail(challenge: any, status: number): void;
34
- fail(status: number): void;
35
- redirect(url: string, status?: number): void;
36
- pass(): void;
37
- error(err: Error): void;
38
26
  }, "als" | "authzProvider">>;
39
27
 
40
28
  export { createJwtStrategy, createRefreshStrategy };
@@ -94,24 +94,21 @@ const createSessionAuthzGuard = /* @__PURE__ */ __name(([SESSION_STRATEGY, AUTHZ
94
94
  context.getClass(),
95
95
  context.getHandler()
96
96
  ]));
97
+ if (paramsList.length && Boolean(paramsList[paramsList.length - 1].options?.public)) {
98
+ store.guardResult = true;
99
+ return true;
100
+ }
97
101
  const contextParamsList = (0, import_utils.getContextAuthzMetaParamsList)(paramsList, {
98
102
  defaultOverride: this.sessionAuthzOptions.defaultOverride,
99
103
  skipFalsyMetadata: this.sessionAuthzOptions.skipFalsyMetadata
100
104
  });
101
- if (!contextParamsList.length) {
102
- return true;
103
- }
104
105
  const req = context.switchToHttp().getRequest();
105
106
  store.allowAnonymous = (0, import_utils.getAllowAnonymous)(contextParamsList, {
106
107
  defaultAllowAnonymous: this.sessionAuthzOptions.defaultAllowAnonymous
107
108
  });
108
109
  await super.canActivate(context);
109
- if (typeof this.authzProvider.authorize !== "function") {
110
- store.guardResult = true;
111
- return true;
112
- }
113
110
  const user = (0, import_utils.getPassportProperty)(req);
114
- if (!user && store.allowAnonymous) {
111
+ if (store.allowAnonymous && !user) {
115
112
  return true;
116
113
  }
117
114
  for (const ele of contextParamsList) {
@@ -6,7 +6,17 @@ import 'express';
6
6
  import '../authz.provider.js';
7
7
 
8
8
  type SessionAuthzModuleOptions = Partial<AuthzModuleBaseOptions> & {
9
+ /**
10
+ * Session options.
11
+ *
12
+ * Same as `express-session` [session options](https://www.npmjs.com/package/express-session#options).
13
+ */
9
14
  session: SessionOptions & {
15
+ /**
16
+ * Option to keep session information after regenerating.
17
+ *
18
+ * Same as `passportjs` [keepSessionInfo](https://github.com/jaredhanson/passport/blob/217018dbc46dcd4118dd6f2c60c8d97010c587f8/CHANGELOG.md#L18).
19
+ */
10
20
  keepSessionInfo?: boolean;
11
21
  };
12
22
  };
@@ -1,6 +1,6 @@
1
1
  import * as _nestjs_core from '@nestjs/core';
2
2
  import { AuthzProviderClass } from '../authz.provider.js';
3
- import { AbstractConstructor, RoutesOptions, AuthzDecoParams, MethodParameters, ApplyDecorators, CookieOptionsWithSecret, AuthzModuleRoutesOptions, AuthzModuleBaseOptions } from '../utils/types.js';
3
+ import { AbstractConstructor, RoutesOptions, AuthzDecoParams, MethodParameters, ApplyDecorators, CookieOptionsWithSecret, DeepReadonly, AuthzModuleRoutesOptions, AuthzModuleBaseOptions } from '../utils/types.js';
4
4
  import { AsyncLocalStorage } from 'node:async_hooks';
5
5
  import * as _nestjs_common from '@nestjs/common';
6
6
  import { MiddlewareConsumer, DynamicModule, Type } from '@nestjs/common';
@@ -21,7 +21,42 @@ declare const OPTIONS_TYPE: Partial<AuthzModuleBaseOptions> & {
21
21
  } & Partial<{
22
22
  authzProvider?: Type<AuthzProviderClass<unknown, unknown>>;
23
23
  } & AuthzModuleRoutesOptions>;
24
+ /**
25
+ * Creates a session module along with its associated guard and service,
26
+ * with types inferred from the provided implementation of `AuthzProviderClass`.
27
+ *
28
+ * @param authzProvider - The implementation class of `AuthzProviderClass`
29
+ * @returns \{AuthzModule, AuthzGuard, AuthzService}
30
+ */
24
31
  declare const cereateSessionAuthzModule: <P, U, T extends AuthzProviderClass<P, U>>(authzProvider: AbstractConstructor<T, P, U>) => {
32
+ /**
33
+ * A dynamic module used to configure session based authentication and authorization features for the application.
34
+ *
35
+ * This module can be configured using 2 static methods:
36
+ *
37
+ * - `register`
38
+ * - `registerAsync`
39
+ *
40
+ * ### Usage
41
+ *
42
+ * ```typescript
43
+ * ⁣@Module({
44
+ * imports: [
45
+ * // Import and configure session strategy
46
+ * AuthzModule.register({
47
+ * session: {
48
+ * name: 'custom-session-id-name',
49
+ * secret: '1234567890'
50
+ * },
51
+ * // Define routes that use AuthzGuard
52
+ * routes: [BusinessController]
53
+ * })
54
+ * ],
55
+ * controllers: [BusinessController]
56
+ * })
57
+ * export class BusinessModule {}
58
+ * ```
59
+ */
25
60
  AuthzModule: {
26
61
  new (routesOpt: RoutesOptions, sessionAuthzOptions: SessionAuthzOptions): {
27
62
  [x: string]: any;
@@ -30,14 +65,37 @@ declare const cereateSessionAuthzModule: <P, U, T extends AuthzProviderClass<P,
30
65
  configure(consumer: MiddlewareConsumer): void;
31
66
  };
32
67
  /**
33
- * Note: DO NOT register the same route in multiple session authz modules, or import the same session authz module in the same module multiple times, express-session middleware will not work properly.
68
+ * Configures authz module.
69
+ *
70
+ * Note: DO NOT register the same routes in multiple session authz modules, or import the same session authz module in the same module multiple times, express-session middleware will not work properly.
34
71
  */
35
72
  register(options: Omit<typeof OPTIONS_TYPE, "authzProvider">): DynamicModule;
36
73
  /**
37
- * Note: DO NOT register the same route in multiple session authz modules, express-session middleware will not work properly.
74
+ * Configures authz module asynchronously.
75
+ *
76
+ * Note: DO NOT register the same routes in multiple session authz modules, express-session middleware will not work properly.
38
77
  */
39
78
  registerAsync(options: typeof ASYNC_OPTIONS_TYPE): DynamicModule;
40
79
  };
80
+ /**
81
+ * A custom guard that applies authentication to controllers.
82
+ *
83
+ * This guard also provides 3 utility decorators to apply and modify authorization:
84
+ *
85
+ * - `@AuthzGuard.Verify`: Used to verify the user's authorization for specific meta data.
86
+ * - `@AuthzGuard.NoVerify`: Used to `skip` authentication & authorization checks for specific routes.
87
+ * - `@AuthzGuard.Apply`: A simplified version of `@UseGuards(AuthzGuard)` and `@AuthzGuard.Verify`, combining both for convenience.
88
+ *
89
+ * ### Usage:
90
+ *
91
+ * ```typescript
92
+ * ⁣@UseGuards(AuthzGuard)
93
+ * ⁣@Controller(/⁣/ ...)
94
+ * export class BusinessController {
95
+ * // ...
96
+ * }
97
+ * ```
98
+ */
41
99
  AuthzGuard: Type<Omit<{
42
100
  readonly reflector: _nestjs_core.Reflector;
43
101
  readonly authzProvider: AuthzProviderClass<unknown, unknown>;
@@ -54,17 +112,70 @@ declare const cereateSessionAuthzModule: <P, U, T extends AuthzProviderClass<P,
54
112
  } = any>(request: TRequest): Promise<void>;
55
113
  getRequest(context: _nestjs_common.ExecutionContext): any;
56
114
  }, "als" | "reflector" | "authzProvider" | "sessionAuthzOptions">> & {
115
+ /**
116
+ * Verifies the user's authorization for specific meta data.
117
+ *
118
+ * ### Usage
119
+ *
120
+ * ```typescript
121
+ * ⁣@UseGuards(AuthzGuard)
122
+ * ⁣@Controller(/⁣/ ...)
123
+ * export class BusinessController {
124
+ * ⁣@AuthzGuard.Verify(/⁣/ mata datas used to authorize user)
125
+ * ⁣@Get()
126
+ * async method() {
127
+ * // ...
128
+ * }
129
+ * }
130
+ * ```
131
+ */
57
132
  Verify: (...args: AuthzDecoParams<MethodParameters<T, "authorize">[1]>) => ApplyDecorators;
133
+ /**
134
+ * Skips authentication & authorization checks for specific routes.
135
+ *
136
+ * ### Usage
137
+ *
138
+ * ```typescript
139
+ * ⁣@UseGuards(AuthzGuard)
140
+ * ⁣@Controller(/⁣/ ...)
141
+ * export class BusinessController {
142
+ * ⁣@AuthzGuard.NoVerify()
143
+ * ⁣@Get()
144
+ * async publicMethod() {
145
+ * // ...
146
+ * }
147
+ * }
148
+ * ```
149
+ */
58
150
  NoVerify: () => MethodDecorator & ClassDecorator;
151
+ /**
152
+ * A simplified version of `@UseGuards(AuthzGuard)` and `@AuthzGuard.Verify()`, combining both for convenience
153
+ *
154
+ * ### Usage
155
+ *
156
+ * ```typescript
157
+ * ⁣@Controller(/⁣/ ...)
158
+ * export class BusinessController {
159
+ * ⁣@AuthzGuard.Apply(/⁣/ mata datas used to authorize user)
160
+ * ⁣@Get()
161
+ * async refreshToken() {
162
+ * // ...
163
+ * }
164
+ * }
165
+ * ```
166
+ */
59
167
  Apply: (...rest: Parameters<(...args: AuthzDecoParams<MethodParameters<T, "authorize">[1]>) => ApplyDecorators>) => <TFunction extends Function, Y>(target: TFunction | object, propertyKey?: string | symbol, descriptor?: TypedPropertyDescriptor<Y>) => void;
60
168
  };
169
+ /**
170
+ * A custom servcie to provide methods to handle authentication and authorization.
171
+ */
61
172
  AuthzService: Type<Omit<{
62
173
  readonly authzProvider: AuthzProviderClass<P, U>;
63
174
  readonly als: AsyncLocalStorage<SessionAlsType<P, U>>;
64
175
  logIn(user: U): Promise<void>;
65
176
  logOut(): Promise<void>;
66
177
  setCookie(name: string, value: string, options?: CookieOptionsWithSecret | undefined): void;
67
- getUser(): U | undefined;
178
+ getUser(): DeepReadonly<U> | undefined;
68
179
  }, "als" | "authzProvider">>;
69
180
  };
70
181
 
@@ -180,7 +180,9 @@ const cereateSessionAuthzModule = /* @__PURE__ */ __name((authzProvider) => {
180
180
  this.routesOpt = routesOpt, this.sessionAuthzOptions = sessionAuthzOptions;
181
181
  }
182
182
  /**
183
- * Note: DO NOT register the same route in multiple session authz modules, or import the same session authz module in the same module multiple times, express-session middleware will not work properly.
183
+ * Configures authz module.
184
+ *
185
+ * Note: DO NOT register the same routes in multiple session authz modules, or import the same session authz module in the same module multiple times, express-session middleware will not work properly.
184
186
  */
185
187
  static register(options) {
186
188
  const sessionAuthzOptions = (0, import_session_authz2.normalizedSessionAuthzModuleOptions)(options);
@@ -197,7 +199,9 @@ const cereateSessionAuthzModule = /* @__PURE__ */ __name((authzProvider) => {
197
199
  });
198
200
  }
199
201
  /**
200
- * Note: DO NOT register the same route in multiple session authz modules, express-session middleware will not work properly.
202
+ * Configures authz module asynchronously.
203
+ *
204
+ * Note: DO NOT register the same routes in multiple session authz modules, express-session middleware will not work properly.
201
205
  */
202
206
  static registerAsync(options) {
203
207
  return (0, import_utils.mergeDynamicModuleConfigs)(super.registerAsync({
@@ -234,8 +238,58 @@ const cereateSessionAuthzModule = /* @__PURE__ */ __name((authzProvider) => {
234
238
  ])
235
239
  ], SessionAuthzModule);
236
240
  return {
241
+ /**
242
+ * A dynamic module used to configure session based authentication and authorization features for the application.
243
+ *
244
+ * This module can be configured using 2 static methods:
245
+ *
246
+ * - `register`
247
+ * - `registerAsync`
248
+ *
249
+ * ### Usage
250
+ *
251
+ * ```typescript
252
+ * ⁣@Module({
253
+ * imports: [
254
+ * // Import and configure session strategy
255
+ * AuthzModule.register({
256
+ * session: {
257
+ * name: 'custom-session-id-name',
258
+ * secret: '1234567890'
259
+ * },
260
+ * // Define routes that use AuthzGuard
261
+ * routes: [BusinessController]
262
+ * })
263
+ * ],
264
+ * controllers: [BusinessController]
265
+ * })
266
+ * export class BusinessModule {}
267
+ * ```
268
+ */
237
269
  AuthzModule: SessionAuthzModule,
270
+ /**
271
+ * A custom guard that applies authentication to controllers.
272
+ *
273
+ * This guard also provides 3 utility decorators to apply and modify authorization:
274
+ *
275
+ * - `@AuthzGuard.Verify`: Used to verify the user's authorization for specific meta data.
276
+ * - `@AuthzGuard.NoVerify`: Used to `skip` authentication & authorization checks for specific routes.
277
+ * - `@AuthzGuard.Apply`: A simplified version of `@UseGuards(AuthzGuard)` and `@AuthzGuard.Verify`, combining both for convenience.
278
+ *
279
+ * ### Usage:
280
+ *
281
+ * ```typescript
282
+ * ⁣@UseGuards(AuthzGuard)
283
+ * ⁣@Controller(/⁣/ ...)
284
+ * export class BusinessController {
285
+ * // ...
286
+ * }
287
+ * ```
288
+ */
238
289
  AuthzGuard: SessionAuthzGuard,
290
+ /**
291
+ * A custom servcie to provide methods to handle authentication and authorization.
292
+ */
239
293
  AuthzService: SessionAuthzService
240
294
  };
241
295
  }, "cereateSessionAuthzModule");
@@ -1,6 +1,6 @@
1
1
  import * as _nestjs_common from '@nestjs/common';
2
2
  import { AuthzProviderClass } from '../authz.provider.js';
3
- import { CookieOptionsWithSecret } from '../utils/types.js';
3
+ import { CookieOptionsWithSecret, DeepReadonly } from '../utils/types.js';
4
4
  import { AsyncLocalStorage } from 'node:async_hooks';
5
5
  import { SessionAlsType } from './session-authz-als.middleware.js';
6
6
  import '@nestjs/common/interfaces';
@@ -11,10 +11,24 @@ import 'express-session';
11
11
  declare const createSessionAuthzService: <P = unknown, U = unknown>([AUTHZ_PROVIDER, ALS_PROVIDER]: [any, any]) => _nestjs_common.Type<Omit<{
12
12
  readonly authzProvider: AuthzProviderClass<P, U>;
13
13
  readonly als: AsyncLocalStorage<SessionAlsType<P, U>>;
14
+ /**
15
+ * Creates a session id with a payload generated by AuthzProviderClass.createPayload().
16
+ *
17
+ * @param user - User entity
18
+ */
14
19
  logIn(user: U): Promise<void>;
20
+ /**
21
+ * Clears current user session.
22
+ */
15
23
  logOut(): Promise<void>;
24
+ /**
25
+ * Sets a secure HTTP cookie with the given name, value, and optional cookie options.
26
+ */
16
27
  setCookie(name: string, value: string, options?: CookieOptionsWithSecret | undefined): void;
17
- getUser(): U | undefined;
28
+ /**
29
+ * Retrieves the current user associated with the request, if available.
30
+ */
31
+ getUser(): DeepReadonly<U> | undefined;
18
32
  }, "als" | "authzProvider">>;
19
33
 
20
34
  export { createSessionAuthzService };
@@ -57,19 +57,33 @@ const createSessionAuthzService = /* @__PURE__ */ __name(([AUTHZ_PROVIDER, ALS_P
57
57
  throw new import_errors.AuthzError(`InternalError: Method 'createPayload' from abstract class 'AuthzProvider' must be implemented.`);
58
58
  }
59
59
  }
60
+ /**
61
+ * Creates a session id with a payload generated by AuthzProviderClass.createPayload().
62
+ *
63
+ * @param user - User entity
64
+ */
60
65
  async logIn(user) {
61
66
  const store = (0, import_utils.getAlsStore)(this.als);
62
67
  const payload = await this.authzProvider.createPayload(user);
63
68
  return store.logIn(payload);
64
69
  }
70
+ /**
71
+ * Clears current user session.
72
+ */
65
73
  async logOut() {
66
74
  const store = (0, import_utils.getAlsStore)(this.als);
67
75
  return store.logOut();
68
76
  }
77
+ /**
78
+ * Sets a secure HTTP cookie with the given name, value, and optional cookie options.
79
+ */
69
80
  setCookie(...rest) {
70
81
  const store = (0, import_utils.getAlsStore)(this.als);
71
82
  store.setCookie(...rest);
72
83
  }
84
+ /**
85
+ * Retrieves the current user associated with the request, if available.
86
+ */
73
87
  getUser() {
74
88
  const store = (0, import_utils.getAlsStore)(this.als);
75
89
  const user = store.user;
@@ -13,12 +13,6 @@ declare const createSessionAuthzStrategy: ([SESSION_STRATEGY, AUTHZ_PROVIDER, AL
13
13
  readonly als: AsyncLocalStorage<SessionAlsType<unknown, unknown>>;
14
14
  validate(req: Request): Promise<{}>;
15
15
  authenticate(req: Request, options?: any): any;
16
- success(user: any, info?: any): void;
17
- fail(challenge: any, status: number): void;
18
- fail(status: number): void;
19
- redirect(url: string, status?: number): void;
20
- pass(): void;
21
- error(err: Error): void;
22
16
  }, "als" | "authzProvider">>;
23
17
 
24
18
  export { createSessionAuthzStrategy };
@@ -1,6 +1,22 @@
1
1
  import { ExecutionContext } from '@nestjs/common';
2
2
 
3
3
  declare const userDecoratorFactory: (_data: unknown, ctx: ExecutionContext) => unknown;
4
+ /**
5
+ * Retrieves the current user associated with the request, if available.
6
+ *
7
+ * ### Usage
8
+ *
9
+ * ```typescript
10
+ * ⁣@UseGuards(AuthzGuard)
11
+ * ⁣@Controller(/⁣/ ...)
12
+ * export class BusinessController {
13
+ * ⁣@Get()
14
+ * async method(@User() user: User) {
15
+ * // ...
16
+ * }
17
+ * }
18
+ * ```
19
+ */
4
20
  declare const User: (...dataOrPipes: unknown[]) => ParameterDecorator;
5
21
 
6
22
  export { User, userDecoratorFactory };
@@ -8,7 +8,7 @@ export { getContextAuthzMetaParamsList } from './get-context-authz-meta-params-l
8
8
  export { getPassportProperty } from './get-passport-property.js';
9
9
  export { mergeDynamicModuleConfigs } from './merge-dynamic-module-configs.js';
10
10
  export { decodeMsgpackrString, encodeMsgpackrString } from './msgpackrs.js';
11
- export { AbstractConstructor, ApplyDecorators, AuthzDecoBaseOptions, AuthzDecoOptions, AuthzDecoParams, AuthzMetaParams, AuthzModuleBaseOptions, AuthzModuleRoutesOptions, CookieOptionsWithSecret, IncludesUndefined, IsEqual, IsNull, IsUnknown, MethodParameters, OmitClassInstance, RoutesOptions, SetRequired, SingleOrArray } from './types.js';
11
+ export { AbstractConstructor, ApplyDecorators, AuthzDecoBaseOptions, AuthzDecoOptions, AuthzDecoParams, AuthzMetaParams, AuthzModuleBaseOptions, AuthzModuleRoutesOptions, CookieOptionsWithSecret, DeepReadonly, IncludesUndefined, IsEqual, IsNull, IsUnknown, MethodParameters, OmitClassInstance, RoutesOptions, SetRequired, SingleOrArray } from './types.js';
12
12
  import 'express';
13
13
  import '../authz.provider.js';
14
14
  import 'node:async_hooks';
@@ -10,6 +10,9 @@ type SetRequired<T, K extends keyof T> = T & {
10
10
  type IsEqual<A, B> = (<G>() => G extends A ? 1 : 2) extends <G>() => G extends B ? 1 : 2 ? true : false;
11
11
  type IsNull<T> = [T] extends [null] ? true : false;
12
12
  type IsUnknown<T> = unknown extends T ? IsNull<T> extends false ? true : false : false;
13
+ type DeepReadonly<T> = {
14
+ readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
15
+ };
13
16
  type CookieOptionsWithSecret = CookieOptions & {
14
17
  /**
15
18
  * a string or array used to sign cookies.
@@ -17,7 +20,13 @@ type CookieOptionsWithSecret = CookieOptions & {
17
20
  secret?: string | string[];
18
21
  };
19
22
  interface AuthzDecoBaseOptions {
23
+ /**
24
+ * When set, overrides the previous metadatas during the authorization, instead of inheriting.
25
+ */
20
26
  override?: boolean;
27
+ /**
28
+ * When set, authorization & authentication will be bypassed if authentication returns empty.
29
+ */
21
30
  allowAnonymous?: boolean;
22
31
  }
23
32
  interface AuthzDecoOptions extends AuthzDecoBaseOptions {
@@ -33,17 +42,49 @@ type IncludesUndefined<T> = undefined extends T ? true : false;
33
42
  type AbstractConstructor<T, T1, T2> = new (...args: any[]) => T & AuthzProviderClass<T1, T2>;
34
43
  type MethodParameters<T, Method extends keyof T> = T[Method] extends (...args: infer P) => any ? P : never;
35
44
  interface AuthzModuleBaseOptions {
45
+ /**
46
+ * Property name for registering authenticated user on the HTTP request object.
47
+ *
48
+ * @default 'user'
49
+ */
36
50
  passportProperty: string;
51
+ /**
52
+ * When set, the current metadata will override previous metadatas during the authorization by default, instead of inheriting.
53
+ *
54
+ * @default false
55
+ */
37
56
  defaultOverride: boolean;
57
+ /**
58
+ * When set, empty metadata will be `ignored` by default during the authorization.
59
+ *
60
+ * @default false
61
+ */
38
62
  skipFalsyMetadata: boolean;
63
+ /**
64
+ * When set, authorization & authentication will be bypassed by default if authentication returns empty.
65
+ *
66
+ * @default false
67
+ */
39
68
  defaultAllowAnonymous: boolean;
40
69
  }
41
70
  type AuthzModuleRoutesOptions = {
71
+ /**
72
+ * When enabled, becomes a global module and will apply strategy to all routes in the application.
73
+ *
74
+ * Note: This option conflicts with the `routes` option.
75
+ *
76
+ * @default false
77
+ */
42
78
  global?: boolean;
43
79
  /**
44
- * Note: DO NOT register the same controller in different modules, their middlewares will not work properly. This is an Nest.js design. Pleases use string instead if requires.
80
+ * Applies strategy to the specified controllers/routes.
81
+ *
82
+ * Note: This option conflicts with the `global` option.
45
83
  */
46
84
  routes?: SingleOrArray<string | Type | RouteInfo>;
85
+ /**
86
+ * Whitelists the specified controllers/routes listed in `routes` options.
87
+ */
47
88
  excludes?: SingleOrArray<string | RouteInfo>;
48
89
  };
49
90
  type RoutesOptions = {
@@ -53,4 +94,4 @@ type RoutesOptions = {
53
94
  };
54
95
  type ApplyDecorators = ReturnType<typeof applyDecorators>;
55
96
 
56
- export type { AbstractConstructor, ApplyDecorators, AuthzDecoBaseOptions, AuthzDecoOptions, AuthzDecoParams, AuthzMetaParams, AuthzModuleBaseOptions, AuthzModuleRoutesOptions, CookieOptionsWithSecret, IncludesUndefined, IsEqual, IsNull, IsUnknown, MethodParameters, OmitClassInstance, RoutesOptions, SetRequired, SingleOrArray };
97
+ export type { AbstractConstructor, ApplyDecorators, AuthzDecoBaseOptions, AuthzDecoOptions, AuthzDecoParams, AuthzMetaParams, AuthzModuleBaseOptions, AuthzModuleRoutesOptions, CookieOptionsWithSecret, DeepReadonly, IncludesUndefined, IsEqual, IsNull, IsUnknown, MethodParameters, OmitClassInstance, RoutesOptions, SetRequired, SingleOrArray };
package/package.json CHANGED
@@ -1,8 +1,11 @@
1
1
  {
2
2
  "name": "@nestjs-kitchen/authz",
3
3
  "private": false,
4
- "description": "Nest TypeScript starter repository",
5
- "version": "1.0.0",
4
+ "description": "Simplest authentication & authorization module in NextJS",
5
+ "version": "1.1.0",
6
+ "homepage": "https://github.com/yikenman/nestjs-kitchen",
7
+ "repository": "https://github.com/yikenman/nestjs-kitchen",
8
+ "author": "yikenman",
6
9
  "license": "MIT",
7
10
  "exports": {
8
11
  ".": {
@@ -47,6 +50,9 @@
47
50
  "tsup": "^8.3.5",
48
51
  "typescript": "^5.7.2"
49
52
  },
53
+ "engines": {
54
+ "node": ">=20.13.0"
55
+ },
50
56
  "peerDependencies": {
51
57
  "@nestjs/common": "^10.4.12",
52
58
  "@nestjs/core": "^10.4.12",