@venizia/ignis-docs 0.0.4-1 → 0.0.4-2

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.
Files changed (38) hide show
  1. package/package.json +1 -1
  2. package/wiki/best-practices/api-usage-examples.md +1 -0
  3. package/wiki/best-practices/code-style-standards/advanced-patterns.md +259 -0
  4. package/wiki/best-practices/code-style-standards/constants-configuration.md +225 -0
  5. package/wiki/best-practices/code-style-standards/control-flow.md +245 -0
  6. package/wiki/best-practices/code-style-standards/documentation.md +221 -0
  7. package/wiki/best-practices/code-style-standards/function-patterns.md +142 -0
  8. package/wiki/best-practices/code-style-standards/index.md +110 -0
  9. package/wiki/best-practices/code-style-standards/naming-conventions.md +174 -0
  10. package/wiki/best-practices/code-style-standards/route-definitions.md +150 -0
  11. package/wiki/best-practices/code-style-standards/tooling.md +155 -0
  12. package/wiki/best-practices/code-style-standards/type-safety.md +165 -0
  13. package/wiki/best-practices/common-pitfalls.md +164 -3
  14. package/wiki/best-practices/contribution-workflow.md +1 -1
  15. package/wiki/best-practices/data-modeling.md +102 -2
  16. package/wiki/best-practices/error-handling.md +468 -0
  17. package/wiki/best-practices/index.md +204 -21
  18. package/wiki/best-practices/performance-optimization.md +180 -0
  19. package/wiki/best-practices/security-guidelines.md +249 -0
  20. package/wiki/best-practices/testing-strategies.md +620 -0
  21. package/wiki/changelogs/2026-01-05-range-queries-content-range.md +184 -0
  22. package/wiki/changelogs/2026-01-06-basic-authentication.md +103 -0
  23. package/wiki/changelogs/2026-01-07-controller-route-customization.md +209 -0
  24. package/wiki/changelogs/index.md +3 -0
  25. package/wiki/guides/core-concepts/components-guide.md +1 -1
  26. package/wiki/guides/core-concepts/persistent/models.md +10 -0
  27. package/wiki/guides/tutorials/complete-installation.md +1 -1
  28. package/wiki/guides/tutorials/testing.md +1 -1
  29. package/wiki/references/base/components.md +47 -29
  30. package/wiki/references/base/controllers.md +215 -18
  31. package/wiki/references/base/filter-system/fields-order-pagination.md +84 -0
  32. package/wiki/references/base/middlewares.md +33 -1
  33. package/wiki/references/base/models.md +40 -2
  34. package/wiki/references/base/repositories/index.md +2 -0
  35. package/wiki/references/components/authentication.md +261 -247
  36. package/wiki/references/helpers/index.md +1 -1
  37. package/wiki/references/src-details/core.md +1 -1
  38. package/wiki/best-practices/code-style-standards.md +0 -1193
@@ -1,6 +1,6 @@
1
1
  # Authentication Component
2
2
 
3
- JWT-based authentication and authorization system for Ignis applications.
3
+ JWT and Basic authentication system for Ignis applications with multi-strategy support.
4
4
 
5
5
  ## Quick Reference
6
6
 
@@ -9,7 +9,9 @@ JWT-based authentication and authorization system for Ignis applications.
9
9
  | **AuthenticateComponent** | Main component registering auth services and controllers |
10
10
  | **AuthenticationStrategyRegistry** | Singleton managing available auth strategies |
11
11
  | **JWTAuthenticationStrategy** | JWT verification using `JWTTokenService` |
12
- | **JWTTokenService** | Generate, verify, encrypt/decrypt JWT tokens (safely handles undefined/null) |
12
+ | **BasicAuthenticationStrategy** | Basic HTTP authentication using `BasicTokenService` |
13
+ | **JWTTokenService** | Generate, verify, encrypt/decrypt JWT tokens |
14
+ | **BasicTokenService** | Extract and verify Basic auth credentials |
13
15
  | **IAuthService** | Interface for custom auth implementation (sign-in, sign-up) |
14
16
  | **defineAuthController** | Factory function for creating custom auth controllers |
15
17
 
@@ -17,31 +19,60 @@ JWT-based authentication and authorization system for Ignis applications.
17
19
 
18
20
  | Variable | Purpose | Required |
19
21
  |----------|---------|----------|
20
- | `APP_ENV_APPLICATION_SECRET` | Encrypt JWT payload | Yes |
21
- | `APP_ENV_JWT_SECRET` | Sign and verify JWT signature | Yes |
22
+ | `APP_ENV_APPLICATION_SECRET` | Encrypt JWT payload | Required for JWT |
23
+ | `APP_ENV_JWT_SECRET` | Sign and verify JWT signature | Required for JWT |
22
24
  | `APP_ENV_JWT_EXPIRES_IN` | Token expiration (seconds) | Optional |
23
25
 
24
- ### Authentication Options Configuration
26
+ ### Binding Keys
27
+
28
+ The authentication component uses **separate binding keys** for each configuration type:
29
+
30
+ | Binding Key | Type | Description |
31
+ |-------------|------|-------------|
32
+ | `AuthenticateBindingKeys.REST_OPTIONS` | `TAuthenticationRestOptions` | REST controller configuration |
33
+ | `AuthenticateBindingKeys.JWT_OPTIONS` | `IJWTTokenServiceOptions` | JWT token configuration |
34
+ | `AuthenticateBindingKeys.BASIC_OPTIONS` | `IBasicTokenServiceOptions` | Basic auth configuration |
35
+
36
+ ### REST Options Configuration
25
37
 
26
38
  | Option | Type | Description |
27
39
  |--------|------|-------------|
28
- | `restOptions.useAuthController` | `boolean` | Enable/disable built-in auth controller (default: `false`) |
29
- | `restOptions.controllerOpts` | `TDefineAuthControllerOpts` | Configuration for built-in auth controller (required if `useAuthController` is `true`) |
30
- | `restOptions.controllerOpts.restPath` | `string` | Base path for auth endpoints (default: `/auth`) |
31
- | `restOptions.controllerOpts.serviceKey` | `string` | Dependency injection key for auth service (default: `services.AuthenticationService`) |
32
- | `restOptions.controllerOpts.requireAuthenticatedSignUp` | `boolean` | Whether sign-up requires authentication (default: `false`) |
33
- | `restOptions.controllerOpts.payload` | `object` | Custom Zod schemas for request/response payloads |
34
- | `alwaysAllowPaths` | `string[]` | Array of paths that bypass authentication |
35
- | `tokenOptions` | `IJWTTokenServiceOptions` | JWT token configuration |
40
+ | `useAuthController` | `boolean` | Enable/disable built-in auth controller (default: `false`) |
41
+ | `controllerOpts` | `TDefineAuthControllerOpts` | Configuration for built-in auth controller (required if `useAuthController` is `true`) |
42
+ | `controllerOpts.restPath` | `string` | Base path for auth endpoints (default: `/auth`) |
43
+ | `controllerOpts.serviceKey` | `string` | Dependency injection key for auth service |
44
+ | `controllerOpts.requireAuthenticatedSignUp` | `boolean` | Whether sign-up requires authentication (default: `false`) |
45
+ | `controllerOpts.payload` | `object` | Custom Zod schemas for request/response payloads |
46
+
47
+ ::: warning IMPORTANT
48
+ At least one of `JWT_OPTIONS` or `BASIC_OPTIONS` must be bound. If neither is configured, the component will throw an error.
49
+ :::
50
+
51
+ ### Route Configuration Options
52
+
53
+ | Option | Type | Description |
54
+ |--------|------|-------------|
55
+ | `authStrategies` | `TAuthStrategy[]` | Array of strategy names to use (e.g., `['jwt']`, `['jwt', 'basic']`) |
56
+ | `authMode` | `'any' \| 'all'` | How to handle multiple strategies (default: `'any'`) |
57
+ | `skipAuth` | `boolean` | Skip authentication for this route (default: `false`) |
58
+
59
+ ### Auth Modes
60
+
61
+ | Mode | Behavior |
62
+ |------|----------|
63
+ | `'any'` | First successful strategy wins (fallback mode) |
64
+ | `'all'` | All strategies must pass (MFA mode) |
36
65
 
37
66
  ## Architecture Components
38
67
 
39
68
  - **`AuthenticateComponent`**: Registers all necessary services and optionally the authentication controller
40
69
  - **`AuthenticationStrategyRegistry`**: Singleton managing authentication strategies
41
70
  - **`JWTAuthenticationStrategy`**: JWT strategy implementation using `JWTTokenService`
42
- - **`JWTTokenService`**: Generates, verifies, encrypts/decrypts JWT payloads (handles undefined/null values safely)
71
+ - **`BasicAuthenticationStrategy`**: Basic HTTP auth strategy using `BasicTokenService`
72
+ - **`JWTTokenService`**: Generates, verifies, encrypts/decrypts JWT payloads
73
+ - **`BasicTokenService`**: Extracts and verifies Basic auth credentials
43
74
  - **`defineAuthController`**: Factory function to create customizable authentication controller
44
- - **Protected Routes**: Use `authStrategies` in route configs to secure endpoints
75
+ - **Protected Routes**: Use `authStrategies` and `authMode` in route configs to secure endpoints
45
76
 
46
77
  ## Implementation Details
47
78
 
@@ -60,7 +91,7 @@ Configure the authentication feature using environment variables:
60
91
  - `APP_ENV_JWT_EXPIRES_IN`: The JWT expiration time in seconds.
61
92
 
62
93
  ::: danger SECURITY NOTE
63
- Both `APP_ENV_APPLICATION_SECRET` and `APP_ENV_JWT_SECRET` are **mandatory**. For security purposes, you must set these to strong, unique secret values. The application will fail to start if these environment variables are missing or left empty.
94
+ Both `APP_ENV_APPLICATION_SECRET` and `APP_ENV_JWT_SECRET` are **mandatory** when using JWT authentication. For security purposes, you must set these to strong, unique secret values.
64
95
  :::
65
96
 
66
97
  **Example `.env` file:**
@@ -75,157 +106,209 @@ APP_ENV_JWT_EXPIRES_IN=86400
75
106
 
76
107
  #### 1. Registering the Authentication Component
77
108
 
78
- In `src/application.ts`, register the `AuthenticateComponent` and the `JWTAuthenticationStrategy`. You also need to provide an `AuthenticationService`.
109
+ In `src/application.ts`, register the `AuthenticateComponent` and authentication strategies.
79
110
 
80
- **Basic Setup (without built-in auth controller):**
111
+ **JWT Only Setup:**
81
112
 
82
113
  ```typescript
83
114
  // src/application.ts
84
115
  import {
85
116
  AuthenticateComponent,
117
+ AuthenticateBindingKeys,
86
118
  Authentication,
87
119
  AuthenticationStrategyRegistry,
120
+ IJWTTokenServiceOptions,
88
121
  JWTAuthenticationStrategy,
89
122
  BaseApplication,
90
123
  ValueOrPromise,
91
124
  } from '@venizia/ignis';
92
- import { AuthenticationService } from './services'; // Your custom auth service
125
+ import { AuthenticationService } from './services';
93
126
 
94
127
  export class Application extends BaseApplication {
95
- // ...
96
-
97
128
  registerAuth() {
98
129
  this.service(AuthenticationService);
99
- this.component(AuthenticateComponent, {
100
- restOptions: {
101
- useAuthController: false, // Default: controller not registered
102
- },
103
- alwaysAllowPaths: [],
104
- tokenOptions: {
105
- applicationSecret: process.env.APP_ENV_APPLICATION_SECRET,
106
- jwtSecret: process.env.APP_ENV_JWT_SECRET,
107
- getTokenExpiresFn: () => Number(process.env.APP_ENV_JWT_EXPIRES_IN || 86400),
108
- },
130
+
131
+ // Bind JWT options
132
+ this.bind<IJWTTokenServiceOptions>({ key: AuthenticateBindingKeys.JWT_OPTIONS }).toValue({
133
+ applicationSecret: process.env.APP_ENV_APPLICATION_SECRET,
134
+ jwtSecret: process.env.APP_ENV_JWT_SECRET,
135
+ getTokenExpiresFn: () => Number(process.env.APP_ENV_JWT_EXPIRES_IN || 86400),
109
136
  });
137
+
138
+ this.component(AuthenticateComponent);
110
139
  AuthenticationStrategyRegistry.getInstance().register({
111
140
  container: this,
112
- name: Authentication.STRATEGY_JWT,
113
- strategy: JWTAuthenticationStrategy,
141
+ strategies: [
142
+ { name: Authentication.STRATEGY_JWT, strategy: JWTAuthenticationStrategy },
143
+ ],
114
144
  });
115
145
  }
116
146
 
117
147
  preConfigure(): ValueOrPromise<void> {
118
- // ...
119
148
  this.registerAuth();
120
- // ...
121
149
  }
122
150
  }
123
151
  ```
124
152
 
125
- **Advanced Setup (with built-in auth controller):**
153
+ **Basic Auth Only Setup:**
126
154
 
127
155
  ```typescript
128
156
  import {
129
157
  AuthenticateComponent,
158
+ AuthenticateBindingKeys,
130
159
  Authentication,
131
160
  AuthenticationStrategyRegistry,
132
- JWTAuthenticationStrategy,
161
+ BasicAuthenticationStrategy,
162
+ IBasicTokenServiceOptions,
133
163
  BaseApplication,
134
- ValueOrPromise,
135
164
  } from '@venizia/ignis';
136
- import { z } from '@hono/zod-openapi';
137
- import { AuthenticationService } from './services';
138
165
 
139
166
  export class Application extends BaseApplication {
140
- // ...
167
+ registerAuth() {
168
+ // Bind Basic auth options
169
+ this.bind<IBasicTokenServiceOptions>({ key: AuthenticateBindingKeys.BASIC_OPTIONS }).toValue({
170
+ verifyCredentials: async (opts) => {
171
+ const { credentials, context } = opts;
172
+ // Your verification logic here
173
+ const user = await this.userRepo.findByUsername(credentials.username);
174
+ if (user && await bcrypt.compare(credentials.password, user.passwordHash)) {
175
+ return { userId: user.id, roles: user.roles };
176
+ }
177
+ return null;
178
+ },
179
+ });
180
+
181
+ this.component(AuthenticateComponent);
182
+ AuthenticationStrategyRegistry.getInstance().register({
183
+ container: this,
184
+ strategies: [
185
+ { name: Authentication.STRATEGY_BASIC, strategy: BasicAuthenticationStrategy },
186
+ ],
187
+ });
188
+ }
189
+ }
190
+ ```
191
+
192
+ **Combined JWT + Basic Auth Setup (with fallback):**
193
+
194
+ ```typescript
195
+ import {
196
+ AuthenticateComponent,
197
+ AuthenticateBindingKeys,
198
+ Authentication,
199
+ AuthenticationStrategyRegistry,
200
+ BasicAuthenticationStrategy,
201
+ JWTAuthenticationStrategy,
202
+ IJWTTokenServiceOptions,
203
+ IBasicTokenServiceOptions,
204
+ TAuthenticationRestOptions,
205
+ BaseApplication,
206
+ } from '@venizia/ignis';
141
207
 
208
+ export class Application extends BaseApplication {
142
209
  registerAuth() {
143
210
  this.service(AuthenticationService);
144
- this.component(AuthenticateComponent, {
145
- restOptions: {
146
- useAuthController: true, // Enable built-in auth controller
147
- controllerOpts: {
148
- restPath: '/auth', // Base path for auth endpoints
149
- serviceKey: 'services.AuthenticationService', // Default service key
150
- requireAuthenticatedSignUp: false, // Whether sign-up requires authentication
151
- payload: {
152
- signIn: {
153
- request: {
154
- schema: z.object({
155
- identifier: z.object({
156
- type: z.string(),
157
- value: z.string(),
158
- }),
159
- credential: z.object({
160
- type: z.string(),
161
- value: z.string(),
162
- }),
163
- })
164
- },
165
- response: {
166
- schema: z.object({
167
- token: z.string(),
168
- })
169
- },
170
- },
171
- signUp: {
172
- request: {
173
- schema: z.object({
174
- username: z.string(),
175
- email: z.string().email(),
176
- password: z.string().min(8),
177
- })
178
- },
179
- response: {
180
- schema: z.object({
181
- token: z.string(),
182
- userId: z.string(),
183
- })
184
- },
185
- },
186
- changePassword: {
187
- request: {
188
- schema: z.object({
189
- oldPassword: z.string(),
190
- newPassword: z.string().min(8),
191
- })
192
- },
193
- response: {
194
- schema: z.object({
195
- success: z.boolean(),
196
- })
197
- },
198
- },
211
+
212
+ // Bind REST options (for auth controller)
213
+ this.bind<TAuthenticationRestOptions>({ key: AuthenticateBindingKeys.REST_OPTIONS }).toValue({
214
+ useAuthController: true,
215
+ controllerOpts: {
216
+ restPath: '/auth',
217
+ payload: {
218
+ signIn: {
219
+ request: { schema: SignInRequestSchema },
220
+ response: { schema: SignInResponseSchema },
221
+ },
222
+ signUp: {
223
+ request: { schema: SignUpRequestSchema },
224
+ response: { schema: SignUpResponseSchema },
199
225
  },
200
226
  },
201
227
  },
202
- alwaysAllowPaths: [],
203
- tokenOptions: {
204
- applicationSecret: process.env.APP_ENV_APPLICATION_SECRET,
205
- jwtSecret: process.env.APP_ENV_JWT_SECRET,
206
- getTokenExpiresFn: () => Number(process.env.APP_ENV_JWT_EXPIRES_IN || 86400),
228
+ });
229
+
230
+ // Bind JWT options
231
+ this.bind<IJWTTokenServiceOptions>({ key: AuthenticateBindingKeys.JWT_OPTIONS }).toValue({
232
+ applicationSecret: process.env.APP_ENV_APPLICATION_SECRET,
233
+ jwtSecret: process.env.APP_ENV_JWT_SECRET,
234
+ getTokenExpiresFn: () => Number(process.env.APP_ENV_JWT_EXPIRES_IN || 86400),
235
+ });
236
+
237
+ // Bind Basic auth options
238
+ this.bind<IBasicTokenServiceOptions>({ key: AuthenticateBindingKeys.BASIC_OPTIONS }).toValue({
239
+ verifyCredentials: async (opts) => {
240
+ const authenticateService = this.get<AuthenticationService>({
241
+ key: BindingKeys.build({
242
+ namespace: BindingNamespaces.SERVICE,
243
+ key: AuthenticationService.name,
244
+ }),
245
+ });
246
+ return authenticateService.signIn(opts.context, {
247
+ identifier: { scheme: 'username', value: opts.credentials.username },
248
+ credential: { scheme: 'basic', value: opts.credentials.password },
249
+ });
207
250
  },
208
251
  });
252
+
253
+ this.component(AuthenticateComponent);
254
+
255
+ // Register multiple strategies at once
209
256
  AuthenticationStrategyRegistry.getInstance().register({
210
257
  container: this,
211
- name: Authentication.STRATEGY_JWT,
212
- strategy: JWTAuthenticationStrategy,
258
+ strategies: [
259
+ { name: Authentication.STRATEGY_JWT, strategy: JWTAuthenticationStrategy },
260
+ { name: Authentication.STRATEGY_BASIC, strategy: BasicAuthenticationStrategy },
261
+ ],
213
262
  });
214
263
  }
215
-
216
- preConfigure(): ValueOrPromise<void> {
217
- // ...
218
- this.registerAuth();
219
- // ...
220
- }
221
264
  }
222
265
  ```
223
266
 
224
- #### 2. Implementing an AuthenticationService
267
+ #### 2. Basic Authentication Verification Function
268
+
269
+ The `verifyCredentials` function receives an options object with credentials and context:
270
+
271
+ ```typescript
272
+ type TBasicAuthVerifyFn = (opts: {
273
+ credentials: { username: string; password: string };
274
+ context: Context;
275
+ }) => Promise<IAuthUser | null>;
276
+ ```
277
+
278
+ Example implementation:
279
+
280
+ ```typescript
281
+ basicOptions: {
282
+ verifyCredentials: async (opts) => {
283
+ const { credentials, context } = opts;
284
+
285
+ // Look up user by username
286
+ const user = await userRepo.findByUsername(credentials.username);
287
+
288
+ if (!user) {
289
+ return null; // User not found
290
+ }
291
+
292
+ // Verify password
293
+ const isValid = await bcrypt.compare(credentials.password, user.passwordHash);
294
+
295
+ if (!isValid) {
296
+ return null; // Invalid password
297
+ }
298
+
299
+ // Return user info (must include userId)
300
+ return {
301
+ userId: user.id,
302
+ roles: user.roles,
303
+ // ... any additional fields
304
+ };
305
+ },
306
+ }
307
+ ```
225
308
 
226
- The `AuthenticateComponent` depends on a service that implements the `IAuthService` interface. You need to provide your own implementation for this service, which will contain your application's specific logic for user authentication.
309
+ #### 3. Implementing an AuthenticationService
227
310
 
228
- Here is a minimal example of what this service might look like:
311
+ The `AuthenticateComponent` depends on a service that implements the `IAuthService` interface.
229
312
 
230
313
  ```typescript
231
314
  // src/services/authentication.service.ts
@@ -251,21 +334,16 @@ export class AuthenticationService extends BaseService implements IAuthService {
251
334
  async signIn(context: Context, opts: TSignInRequest): Promise<{ token: string }> {
252
335
  const { identifier, credential } = opts;
253
336
 
254
- // --- Your custom logic here ---
255
- // 1. Find the user by identifier (e.g., username or email).
256
- // 2. Verify the credential (e.g., check the password).
257
- // 3. If valid, create a JWT payload.
258
- const user = { id: 'user-id-from-db', roles: [] }; // Dummy user
337
+ // Your custom logic here
338
+ const user = await this.userRepo.findByIdentifier(identifier);
259
339
 
260
- if (identifier.value !== 'test_username' || credential.value !== 'test_password') {
340
+ if (!user || !await this.verifyCredential(credential, user)) {
261
341
  throw getError({ message: 'Invalid credentials' });
262
342
  }
263
- // --- End of custom logic ---
264
343
 
265
344
  const payload: IJWTTokenPayload = {
266
345
  userId: user.id,
267
346
  roles: user.roles,
268
- // Add any other data you want in the token
269
347
  };
270
348
 
271
349
  const token = await this._jwtTokenService.generate({ payload });
@@ -274,174 +352,110 @@ export class AuthenticationService extends BaseService implements IAuthService {
274
352
 
275
353
  async signUp(context: Context, opts: any): Promise<any> {
276
354
  // Implement your sign-up logic
277
- throw getError({ message: 'Method not implemented.' });
278
355
  }
279
356
 
280
357
  async changePassword(context: Context, opts: any): Promise<any> {
281
358
  // Implement your change password logic
282
- throw getError({ message: 'Method not implemented.' });
283
359
  }
284
360
  }
285
361
  ```
286
362
 
287
- This service is then registered in `application.ts` as shown in the previous step. It injects the `JWTTokenService` (provided by the `AuthenticateComponent`) to generate a token upon successful sign-in.
363
+ #### 4. Securing Routes
288
364
 
289
- #### 3. Custom Authentication Controller (Optional)
365
+ Use `authStrategies` and `authMode` in route configurations:
290
366
 
291
- If you need more control over the authentication endpoints, you can create a custom controller using the `defineAuthController` factory function.
367
+ **Single Strategy:**
292
368
 
293
369
  ```typescript
294
- // src/controllers/custom-auth.controller.ts
295
- import { defineAuthController } from '@venizia/ignis';
296
- import { z } from '@hono/zod-openapi';
297
-
298
- export const CustomAuthController = defineAuthController({
299
- restPath: '/api/auth',
300
- serviceKey: 'services.AuthenticationService',
301
- requireAuthenticatedSignUp: true, // Require authentication for sign-up
302
- payload: {
303
- signIn: {
304
- request: {
305
- schema: z.object({
306
- email: z.string().email(),
307
- password: z.string(),
308
- }),
309
- },
310
- response: {
311
- schema: z.object({
312
- token: z.string(),
313
- expiresIn: z.number(),
314
- }),
315
- },
316
- },
317
- signUp: {
318
- request: {
319
- schema: z.object({
320
- email: z.string().email(),
321
- password: z.string().min(8),
322
- firstName: z.string(),
323
- lastName: z.string(),
324
- }),
325
- },
326
- response: {
327
- schema: z.object({
328
- token: z.string(),
329
- userId: z.string(),
330
- }),
331
- },
332
- },
333
- changePassword: {
334
- request: {
335
- schema: z.object({
336
- currentPassword: z.string(),
337
- newPassword: z.string().min(8),
338
- }),
339
- },
340
- response: {
341
- schema: z.object({
342
- success: z.boolean(),
343
- message: z.string().optional(),
344
- }),
345
- },
346
- },
347
- },
348
- });
370
+ const SECURE_ROUTE_CONFIG = {
371
+ path: '/secure-data',
372
+ method: HTTP.Methods.GET,
373
+ authStrategies: [Authentication.STRATEGY_JWT],
374
+ responses: jsonResponse({
375
+ description: 'Protected data',
376
+ schema: z.object({ message: z.string() }),
377
+ }),
378
+ } as const;
349
379
  ```
350
380
 
351
- Then register it in your application:
381
+ **Multiple Strategies with Fallback (any mode):**
352
382
 
353
383
  ```typescript
354
- // src/application.ts
355
- import { CustomAuthController } from './controllers/custom-auth.controller';
356
-
357
- export class Application extends BaseApplication {
358
- registerAuth() {
359
- this.service(AuthenticationService);
360
- this.component(AuthenticateComponent, {
361
- restOptions: { useAuthController: false }, // Disable built-in controller
362
- // ... other options
363
- });
364
-
365
- // Register your custom controller
366
- this.controller(CustomAuthController);
367
-
368
- AuthenticationStrategyRegistry.getInstance().register({
369
- container: this,
370
- name: Authentication.STRATEGY_JWT,
371
- strategy: JWTAuthenticationStrategy,
372
- });
373
- }
374
- }
384
+ const FALLBACK_AUTH_CONFIG = {
385
+ path: '/api/data',
386
+ method: HTTP.Methods.GET,
387
+ authStrategies: [Authentication.STRATEGY_JWT, Authentication.STRATEGY_BASIC],
388
+ authMode: 'any', // First successful strategy wins (default)
389
+ responses: jsonResponse({
390
+ description: 'Data accessible via JWT or Basic auth',
391
+ schema: z.object({ data: z.any() }),
392
+ }),
393
+ } as const;
375
394
  ```
376
395
 
377
- #### 4. Securing Routes
378
-
379
- In your controllers, use decorator-based routing (`@get`, `@post`, etc.) with the `authStrategies` property in the `configs` object to protect endpoints. This will automatically run the necessary authentication middlewares and attach the authenticated user to the Hono `Context`, which can then be accessed type-safely using `TRouteContext`.
396
+ **Multiple Strategies with MFA (all mode):**
380
397
 
381
398
  ```typescript
382
- // src/controllers/test.controller.ts
383
- import {
384
- Authentication,
385
- BaseController,
386
- controller,
387
- get, // Or @api, @post, etc.
388
- HTTP,
389
- jsonResponse,
390
- IJWTTokenPayload,
391
- TRouteContext, // Import TRouteContext for type safety
392
- } from '@venizia/ignis';
393
- import { z } from '@hono/zod-openapi';
394
-
395
- const SECURE_ROUTE_CONFIG = {
396
- path: '/secure-data',
397
- method: HTTP.Methods.GET,
398
- authStrategies: [Authentication.STRATEGY_JWT],
399
+ const MFA_CONFIG = {
400
+ path: '/admin/sensitive',
401
+ method: HTTP.Methods.POST,
402
+ authStrategies: [Authentication.STRATEGY_JWT, Authentication.STRATEGY_MFA],
403
+ authMode: 'all', // All strategies must pass
399
404
  responses: jsonResponse({
400
- description: 'Test message content',
401
- schema: z.object({ message: z.string() }),
405
+ description: 'Requires both JWT and MFA',
406
+ schema: z.object({ success: z.boolean() }),
402
407
  }),
403
408
  } as const;
409
+ ```
404
410
 
405
- @controller({ path: '/test' })
406
- export class TestController extends BaseController {
407
- constructor() {
408
- super({
409
- scope: TestController.name,
410
- path: '/test',
411
- });
412
- }
411
+ **Skipping Authentication:**
413
412
 
414
- @get({ configs: SECURE_ROUTE_CONFIG })
415
- secureData(c: TRouteContext<typeof SECURE_ROUTE_CONFIG>) {
416
- // 'c' is fully typed here, including c.get and c.json return type
417
- const user = c.get(Authentication.CURRENT_USER) as IJWTTokenPayload | undefined;
418
- return c.json(
419
- { message: `Hello, ${user?.userId || 'guest'} from protected data` },
420
- HTTP.ResultCodes.RS_2.Ok,
421
- );
422
- }
423
- }
413
+ ```typescript
414
+ const PUBLIC_ROUTE_CONFIG = {
415
+ path: '/public',
416
+ method: HTTP.Methods.GET,
417
+ skipAuth: true, // Bypass authentication even if controller has default auth
418
+ responses: jsonResponse({
419
+ description: 'Public endpoint',
420
+ schema: z.object({ message: z.string() }),
421
+ }),
422
+ } as const;
424
423
  ```
425
424
 
426
425
  #### 5. Accessing the Current User in Context
427
426
 
428
- After a route has been processed, the authenticated user's payload is available directly on the Hono `Context` object, using the `Authentication.CURRENT_USER` key.
427
+ After authentication, the user payload is available on the Hono `Context`:
429
428
 
430
429
  ```typescript
431
430
  import { Context } from 'hono';
432
431
  import { Authentication, IJWTTokenPayload } from '@venizia/ignis';
433
432
 
434
- // Inside a route handler or a custom middleware
433
+ // Inside a route handler
435
434
  const user = c.get(Authentication.CURRENT_USER) as IJWTTokenPayload | undefined;
436
435
 
437
436
  if (user) {
438
437
  console.log('Authenticated user ID:', user.userId);
439
- // You can also access roles, email, etc. from the user object
440
- } else {
441
- console.log('User is not authenticated or not found in context.');
438
+ console.log('User roles:', user.roles);
442
439
  }
443
440
  ```
444
441
 
442
+ #### 6. Dynamic Skip Authentication
443
+
444
+ Use `Authentication.SKIP_AUTHENTICATION` to dynamically skip auth in middleware:
445
+
446
+ ```typescript
447
+ import { Authentication } from '@venizia/ignis';
448
+ import { createMiddleware } from 'hono/factory';
449
+
450
+ const conditionalAuthMiddleware = createMiddleware(async (c, next) => {
451
+ // Skip auth for certain conditions
452
+ if (c.req.header('X-API-Key') === 'valid-api-key') {
453
+ c.set(Authentication.SKIP_AUTHENTICATION, true);
454
+ }
455
+ return next();
456
+ });
457
+ ```
458
+
445
459
  ## See Also
446
460
 
447
461
  - **Related Concepts:**
@@ -33,4 +33,4 @@ Reusable classes and functions providing common functionality - designed for eas
33
33
  - [Components](/references/components/) - Framework components
34
34
 
35
35
  - **Best Practices:**
36
- - [Code Style Standards](/best-practices/code-style-standards) - Helper usage patterns
36
+ - [Code Style Standards](/best-practices/code-style-standards/) - Helper usage patterns