@venizia/ignis-docs 0.0.6-2 → 0.0.6-3
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/dist/mcp-server/index.js +1 -0
- package/dist/mcp-server/index.js.map +1 -1
- package/dist/mcp-server/tools/base.tool.d.ts +4 -8
- package/dist/mcp-server/tools/base.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/base.tool.js +1 -1
- package/dist/mcp-server/tools/base.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts +8 -2
- package/dist/mcp-server/tools/docs/get-document-content.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.js +1 -1
- package/dist/mcp-server/tools/docs/get-document-content.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/get-document-metadata.tool.d.ts +13 -2
- package/dist/mcp-server/tools/docs/get-document-metadata.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/docs/get-document-metadata.tool.js +1 -1
- package/dist/mcp-server/tools/docs/get-document-metadata.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/get-package-overview.tool.d.ts +16 -2
- package/dist/mcp-server/tools/docs/get-package-overview.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/docs/get-package-overview.tool.js +1 -1
- package/dist/mcp-server/tools/docs/get-package-overview.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/list-categories.tool.d.ts +5 -2
- package/dist/mcp-server/tools/docs/list-categories.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/docs/list-categories.tool.js +1 -1
- package/dist/mcp-server/tools/docs/list-categories.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/list-documents.tool.d.ts +11 -2
- package/dist/mcp-server/tools/docs/list-documents.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/docs/list-documents.tool.js +1 -1
- package/dist/mcp-server/tools/docs/list-documents.tool.js.map +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.d.ts +13 -2
- package/dist/mcp-server/tools/docs/search-documents.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.js +1 -1
- package/dist/mcp-server/tools/docs/search-documents.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +9 -2
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.d.ts +16 -2
- package/dist/mcp-server/tools/github/search-code.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/search-code.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts +19 -2
- package/dist/mcp-server/tools/github/verify-dependencies.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js.map +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.d.ts +8 -2
- package/dist/mcp-server/tools/github/view-source-file.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js.map +1 -1
- package/package.json +68 -54
- package/wiki/guides/reference/mcp-docs-server.md +0 -134
- package/wiki/references/base/controllers.md +11 -8
- package/wiki/references/components/authentication/usage.md +3 -3
- package/wiki/references/components/authorization/api.md +1213 -0
- package/wiki/references/components/authorization/errors.md +387 -0
- package/wiki/references/components/authorization/index.md +712 -0
- package/wiki/references/components/authorization/usage.md +696 -0
- package/wiki/references/components/index.md +2 -0
- package/wiki/references/helpers/index.md +1 -0
- package/wiki/references/helpers/kafka/index.md +305 -0
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
# Authorization -- Error Reference
|
|
2
|
+
|
|
3
|
+
> Complete error messages and troubleshooting for the authorization module. See [Setup & Configuration](./) for initial setup.
|
|
4
|
+
|
|
5
|
+
## Error Flow Diagram
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
flowchart TD
|
|
9
|
+
Req([Request arrives]) --> S1{"Step 1: SKIP?"}
|
|
10
|
+
S1 -->|Yes| OK1([No error - skip])
|
|
11
|
+
S1 -->|No| S2{"Step 2: User?"}
|
|
12
|
+
S2 -->|No| E401[/"401: No authenticated user found"/]
|
|
13
|
+
S2 -->|Yes| S3{"Step 3: Role shortcuts"}
|
|
14
|
+
S3 -->|Match| OK2([No error - bypass])
|
|
15
|
+
S3 -->|No match| S4{"Step 4: Voters"}
|
|
16
|
+
S4 -->|DENY| E403a[/"403: Authorization denied by voter"/]
|
|
17
|
+
S4 -->|ALLOW/ABSTAIN| S5{"Step 5: Resolve enforcer"}
|
|
18
|
+
|
|
19
|
+
S5 -->|Registry empty| E500a[/"500: No items registered"/]
|
|
20
|
+
S5 -->|Name not found| E500b[/"500: Descriptor not found"/]
|
|
21
|
+
S5 -->|DI fails| E500c[/"500: Failed to resolve"/]
|
|
22
|
+
S5 -->|OK| S6{"Step 6: Build rules"}
|
|
23
|
+
|
|
24
|
+
S6 -->|No principalType| E400a[/"400: principalType required"/]
|
|
25
|
+
S6 -->|Not initialized| E500d[/"500: Enforcer not initialized"/]
|
|
26
|
+
S6 -->|No FilteredAdapter| E500e[/"500: Adapter does not support loadFilteredPolicy"/]
|
|
27
|
+
S6 -->|Bad cache driver| E500f[/"500: Invalid cached.driver"/]
|
|
28
|
+
S6 -->|Empty Redis key| E400b[/"400: Invalid cachedKey"/]
|
|
29
|
+
S6 -->|OK| S7{"Step 7: Evaluate"}
|
|
30
|
+
|
|
31
|
+
S7 -->|No action/resource| E500g[/"500: request.action and resource required"/]
|
|
32
|
+
S7 -->|ALLOW| OK3([Authorized])
|
|
33
|
+
S7 -->|DENY| E403b[/"403: Authorization denied"/]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Complete Error Reference
|
|
37
|
+
|
|
38
|
+
All error messages from the authorization module, organized by source:
|
|
39
|
+
|
|
40
|
+
### Component Errors (AuthorizeComponent)
|
|
41
|
+
|
|
42
|
+
| Error Message | Status | Method |
|
|
43
|
+
|---------------|--------|--------|
|
|
44
|
+
| `[AuthorizeComponent] No authorize options found. Bind options to AuthorizeBindingKeys.OPTIONS before registering the component.` | 500 | `binding` |
|
|
45
|
+
|
|
46
|
+
### Authorization Provider Errors
|
|
47
|
+
|
|
48
|
+
| Error Message | Status | Step |
|
|
49
|
+
|---------------|--------|------|
|
|
50
|
+
| `Authorization failed: No authenticated user found` | 401 | Step 2 -- User check |
|
|
51
|
+
| `Authorization failed: user.principalType is required for enforcer-based authorization` | 400 | Step 6 -- Build rules |
|
|
52
|
+
| <code v-pre>Authorization denied by voter | action: {{action}} | resource: {{resource}}</code> | 403 | Step 4 -- Voter DENY |
|
|
53
|
+
| <code v-pre>Authorization denied | action: {{action}} | resource: {{resource}}</code> | 403 | Step 7 -- Enforcer denied |
|
|
54
|
+
|
|
55
|
+
### Enforcer Registry Errors (AuthorizationEnforcerRegistry)
|
|
56
|
+
|
|
57
|
+
| Error Message | Status | Method |
|
|
58
|
+
|---------------|--------|--------|
|
|
59
|
+
| <code v-pre>[getKey] Invalid name | name: {{name}}</code> | 500 | `getKey` |
|
|
60
|
+
| `[AuthorizationEnforcerRegistry] No items registered` | 500 | `getDefaultName` |
|
|
61
|
+
| <code v-pre>[AuthorizationEnforcerRegistry] Duplicate enforcer name(s): {{names}}</code> | 500 | `register` |
|
|
62
|
+
| <code v-pre>[AuthorizationEnforcerRegistry] Enforcer already registered: {{name}}</code> | 500 | `register` |
|
|
63
|
+
| <code v-pre>[AuthorizationEnforcerRegistry] Descriptor not found: {{name}}</code> | 500 | `resolveDescriptor` |
|
|
64
|
+
| <code v-pre>[AuthorizationEnforcerRegistry] Failed to resolve: {{name}}</code> | 500 | `resolveDescriptor` |
|
|
65
|
+
|
|
66
|
+
### Casbin Enforcer Errors (CasbinAuthorizationEnforcer)
|
|
67
|
+
|
|
68
|
+
| Error Message | Status | Method |
|
|
69
|
+
|---------------|--------|--------|
|
|
70
|
+
| `[CasbinAuthorizationEnforcer] "casbin" is not installed` | 500 | `configure` |
|
|
71
|
+
| `[CasbinAuthorizationEnforcer] options.model is required.` | 500 | `configure` |
|
|
72
|
+
| `[CasbinAuthorizationEnforcer] Enforcer not initialized. Call configure() first.` | 500 | `evaluate`, `buildRules` |
|
|
73
|
+
| `[CasbinAuthorizationEnforcer] Adapter does not support loadFilteredPolicy.` | 500 | `buildRules` |
|
|
74
|
+
| `[CasbinAuthorizationEnforcer] request.action and request.resource are required.` | 500 | `evaluate` |
|
|
75
|
+
| <code v-pre>[CasbinAuthorizationEnforcer] cached.options.expiresIn must be >= 10000 (ms) | Received: {{value}}</code> | 500 | `configure` (via `validateExpiresIn`) |
|
|
76
|
+
| <code v-pre>[buildRules] Invalid cached.driver | Valids: [in-memory, redis]</code> | 500 | `buildRules` |
|
|
77
|
+
| <code v-pre>[resolveCasbinEnforcer] Invalid cached.driver | Valids: [in-memory, redis]</code> | 500 | `configure` (via `resolveCasbinEnforcer`) |
|
|
78
|
+
| <code v-pre>[resolveModel] Invalid model.driver | Valids: [file, text]</code> | 500 | `configure` (via `resolveModel`) |
|
|
79
|
+
|
|
80
|
+
### Policy Loading Errors (CasbinAuthorizationEnforcer internals)
|
|
81
|
+
|
|
82
|
+
| Error Message | Status | Method |
|
|
83
|
+
|---------------|--------|--------|
|
|
84
|
+
| `[loadPoliciesWithRedisCache] Invalid cachedKey to start validate user authorization!` | 400 | `loadPoliciesWithRedisCache` |
|
|
85
|
+
| `[loadPoliciesFromAdapter] Invalid state of enforcer` | 500 | `loadPoliciesFromAdapter` |
|
|
86
|
+
| `[extractPolicyLines] Invalid state of enforcer` | 500 | `extractPolicyLines` |
|
|
87
|
+
| `[loadPolicyLinesIntoModel] Enforcer not initialized. Call configure() first.` | 500 | `loadPolicyLinesIntoModel` |
|
|
88
|
+
|
|
89
|
+
## Troubleshooting
|
|
90
|
+
|
|
91
|
+
### "[AuthorizeComponent] No authorize options found"
|
|
92
|
+
|
|
93
|
+
**Cause:** `AuthorizeComponent` was registered but `IAuthorizeOptions` was not bound to the container.
|
|
94
|
+
|
|
95
|
+
**Fix:** Bind options **before** registering the component:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// 1. Bind options first
|
|
99
|
+
this.bind<IAuthorizeOptions>({ key: AuthorizeBindingKeys.OPTIONS }).toValue({
|
|
100
|
+
defaultDecision: 'deny',
|
|
101
|
+
alwaysAllowRoles: ['999_super-admin'],
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// 2. Then register the component
|
|
105
|
+
this.component(AuthorizeComponent);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### "Authorization failed: No authenticated user found"
|
|
109
|
+
|
|
110
|
+
**Cause:** The authorization middleware runs after authentication, but no user was found on the context (`Authentication.CURRENT_USER` is undefined). This happens when:
|
|
111
|
+
- The route has `authorize` but no `authenticate` config
|
|
112
|
+
- Authentication middleware failed silently
|
|
113
|
+
- Authentication was skipped but authorization was not
|
|
114
|
+
|
|
115
|
+
**Fix:** Ensure routes with `authorize` also have `authenticate`:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
this.defineRoute({
|
|
119
|
+
configs: {
|
|
120
|
+
path: '/',
|
|
121
|
+
method: 'get',
|
|
122
|
+
authenticate: { strategies: [Authentication.STRATEGY_JWT] }, // Must be present
|
|
123
|
+
authorize: { action: AuthorizationActions.READ, resource: 'Article' },
|
|
124
|
+
// ...
|
|
125
|
+
},
|
|
126
|
+
handler: async (context) => { ... },
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### "Authorization failed: user.principalType is required"
|
|
131
|
+
|
|
132
|
+
**Cause:** The authenticated user object does not have a `principalType` field. This is required for enforcer-based authorization because the enforcer uses `principalType` to construct the casbin subject (e.g., `user_123`, `service_456`).
|
|
133
|
+
|
|
134
|
+
**Fix:** Ensure your authentication service sets `principalType` on the user object:
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
// In your JWT token service or authentication service:
|
|
138
|
+
return {
|
|
139
|
+
userId: '123',
|
|
140
|
+
principalType: 'user', // Required for authorization
|
|
141
|
+
roles: [...],
|
|
142
|
+
};
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
> [!NOTE]
|
|
146
|
+
> `principalType` is accessed via the `IAuthUser` index signature (`[extra: string | symbol]: any`), not a dedicated field. It must be set as a property on the returned user object.
|
|
147
|
+
|
|
148
|
+
### "Authorization denied by voter | action: ... | resource: ..."
|
|
149
|
+
|
|
150
|
+
**Cause:** A voter function explicitly returned `AuthorizationDecisions.DENY` for the request.
|
|
151
|
+
|
|
152
|
+
**Fix:** Check the voter logic. Review which voter denied the request by examining the action and resource in the error message. Common causes:
|
|
153
|
+
- Voter checking ownership and user is not the owner
|
|
154
|
+
- Voter checking time window and request is outside allowed hours
|
|
155
|
+
- Voter checking resource state (e.g., locked, archived)
|
|
156
|
+
|
|
157
|
+
### "Authorization denied | action: ... | resource: ..."
|
|
158
|
+
|
|
159
|
+
**Cause:** The enforcer's `evaluate()` returned `DENY` or `ABSTAIN` (which fell back to `defaultDecision`) for the requested action/resource. This means:
|
|
160
|
+
- No matching policies were found for the user
|
|
161
|
+
- Matching policies exist but deny the action
|
|
162
|
+
- The casbin model does not cover the requested action/resource combination
|
|
163
|
+
|
|
164
|
+
**Fix:** Debug by checking:
|
|
165
|
+
|
|
166
|
+
1. **Policies are loaded correctly** -- verify your adapter is returning the right policy definitions for the user
|
|
167
|
+
2. **Subject format matches** -- the `normalizePayloadFn` must produce subjects matching your policy definitions (e.g., `user_123` must match what's in the database)
|
|
168
|
+
3. **Casbin model covers the request** -- your `.conf` file must define matchers for the action/resource/domain pattern you're using
|
|
169
|
+
4. **Set defaultDecision explicitly:**
|
|
170
|
+
```typescript
|
|
171
|
+
this.bind<IAuthorizeOptions>({ key: AuthorizeBindingKeys.OPTIONS }).toValue({
|
|
172
|
+
defaultDecision: 'deny', // Explicit is better
|
|
173
|
+
// ...
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### "[AuthorizationEnforcerRegistry] Duplicate enforcer name(s): ..."
|
|
178
|
+
|
|
179
|
+
**Cause:** Two or more enforcers in the same `register()` call have the same name.
|
|
180
|
+
|
|
181
|
+
**Fix:** Ensure each enforcer has a unique name:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
AuthorizationEnforcerRegistry.getInstance().register({
|
|
185
|
+
container: this,
|
|
186
|
+
enforcers: [
|
|
187
|
+
{ enforcer: CasbinEnforcer, name: 'casbin', type: 'casbin', ... },
|
|
188
|
+
{ enforcer: CustomEnforcer, name: 'custom', type: 'custom', ... }, // Different name
|
|
189
|
+
],
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### "[AuthorizationEnforcerRegistry] Enforcer already registered: ..."
|
|
194
|
+
|
|
195
|
+
**Cause:** An enforcer with this name was already registered in a previous `register()` call. The registry does not allow overwriting.
|
|
196
|
+
|
|
197
|
+
**Fix:** Ensure you only register each enforcer name once. If you need to re-register, call `registry.reset()` first (typically only in tests).
|
|
198
|
+
|
|
199
|
+
### "[AuthorizationEnforcerRegistry] No items registered"
|
|
200
|
+
|
|
201
|
+
**Cause:** Tried to get the default enforcer name but no enforcers are registered. This usually means `AuthorizationEnforcerRegistry.register()` was never called.
|
|
202
|
+
|
|
203
|
+
**Fix:** Register enforcers after registering the component:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
// 1. Bind options and register component
|
|
207
|
+
this.bind<IAuthorizeOptions>({ key: AuthorizeBindingKeys.OPTIONS }).toValue({ ... });
|
|
208
|
+
this.component(AuthorizeComponent);
|
|
209
|
+
|
|
210
|
+
// 2. Register enforcers
|
|
211
|
+
AuthorizationEnforcerRegistry.getInstance().register({
|
|
212
|
+
container: this,
|
|
213
|
+
enforcers: [{ enforcer: CasbinAuthorizationEnforcer, name: 'casbin', type: 'casbin', options: { ... } }],
|
|
214
|
+
});
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### "[AuthorizationEnforcerRegistry] Descriptor not found: ..."
|
|
218
|
+
|
|
219
|
+
**Cause:** Tried to resolve an enforcer by a name that was never registered. This happens when `enforcerName` is specified in the `authorize()` call but doesn't match any registered enforcer.
|
|
220
|
+
|
|
221
|
+
**Fix:** Ensure the enforcer name matches what was registered. The default enforcer name is the first one registered.
|
|
222
|
+
|
|
223
|
+
### "[AuthorizationEnforcerRegistry] Failed to resolve: ..."
|
|
224
|
+
|
|
225
|
+
**Cause:** The enforcer class was registered in the descriptor Map but DI container resolution returned `null`. This typically means the enforcer class has unsatisfied dependencies.
|
|
226
|
+
|
|
227
|
+
**Fix:** Check that all `@inject` dependencies in your enforcer's constructor are bound in the same container.
|
|
228
|
+
|
|
229
|
+
### "[CasbinAuthorizationEnforcer] casbin is not installed"
|
|
230
|
+
|
|
231
|
+
**Cause:** The Casbin enforcer dynamically imports `casbin` at configure time, but the package is not installed.
|
|
232
|
+
|
|
233
|
+
**Fix:** Install casbin as a dependency:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
bun add casbin
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### "[CasbinAuthorizationEnforcer] options.model is required"
|
|
240
|
+
|
|
241
|
+
**Cause:** The Casbin enforcer's options do not include a `model` field. The model defines the casbin RBAC/ABAC rules structure.
|
|
242
|
+
|
|
243
|
+
**Fix:** Provide `model` in the enforcer options:
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
AuthorizationEnforcerRegistry.getInstance().register({
|
|
247
|
+
container: this,
|
|
248
|
+
enforcers: [{
|
|
249
|
+
enforcer: CasbinAuthorizationEnforcer,
|
|
250
|
+
name: 'casbin',
|
|
251
|
+
type: 'casbin',
|
|
252
|
+
options: {
|
|
253
|
+
model: {
|
|
254
|
+
driver: 'file',
|
|
255
|
+
definition: path.resolve(__dirname, './security/model.conf'),
|
|
256
|
+
},
|
|
257
|
+
cached: { use: false },
|
|
258
|
+
},
|
|
259
|
+
}],
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### "[CasbinAuthorizationEnforcer] Adapter does not support loadFilteredPolicy"
|
|
264
|
+
|
|
265
|
+
**Cause:** The adapter provided to the Casbin enforcer does not implement the `loadFilteredPolicy` method from casbin's `FilteredAdapter` interface. The authorization system always uses filtered policy loading.
|
|
266
|
+
|
|
267
|
+
**Fix:** Use an adapter that implements `FilteredAdapter`, such as `DrizzleCasbinAdapter` or a custom adapter extending `BaseFilteredAdapter`:
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
import { DrizzleCasbinAdapter } from '@venizia/ignis';
|
|
271
|
+
|
|
272
|
+
const adapter = new DrizzleCasbinAdapter({
|
|
273
|
+
dataSource,
|
|
274
|
+
entities: { ... },
|
|
275
|
+
});
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### "[CasbinAuthorizationEnforcer] cached.options.expiresIn must be >= 10000"
|
|
279
|
+
|
|
280
|
+
**Cause:** The `expiresIn` value for the cache TTL is too small. Minimum is 10,000 ms (10 seconds), enforced by the `MIN_EXPIRES_IN` constant.
|
|
281
|
+
|
|
282
|
+
**Fix:** Increase the expiration time:
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
cached: {
|
|
286
|
+
use: true,
|
|
287
|
+
driver: 'redis',
|
|
288
|
+
options: {
|
|
289
|
+
connection: redisHelper,
|
|
290
|
+
expiresIn: 5 * 60 * 1000, // 5 minutes (minimum: 10,000 ms)
|
|
291
|
+
keyFn: ({ user }) => `authz:policies:${user.userId}`,
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### "[CasbinAuthorizationEnforcer] Enforcer not initialized"
|
|
297
|
+
|
|
298
|
+
**Cause:** The Casbin enforcer's `evaluate()`, `buildRules()`, or internal methods were called before `configure()`. This should not happen when using `resolveEnforcer()` (which auto-configures), but can occur if the enforcer is resolved manually via the DI container.
|
|
299
|
+
|
|
300
|
+
**Fix:** Always resolve enforcers through the registry's `resolveEnforcer()` method, which handles configure-once automatically:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const enforcer = await AuthorizationEnforcerRegistry.getInstance().resolveEnforcer({ name: 'casbin' });
|
|
304
|
+
// configure() is called automatically on first resolve
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### "[loadPoliciesWithRedisCache] Invalid cachedKey"
|
|
308
|
+
|
|
309
|
+
**Cause:** The `keyFn` in Redis cache options returned a falsy value (empty string, null, undefined). The cache key is required to store/retrieve policies from Redis.
|
|
310
|
+
|
|
311
|
+
**Fix:** Ensure your `keyFn` always returns a non-empty string:
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
keyFn: ({ user }) => {
|
|
315
|
+
if (!user.userId) {
|
|
316
|
+
throw new Error('User ID is required for cache key');
|
|
317
|
+
}
|
|
318
|
+
return `authz:policies:${user.userId}`;
|
|
319
|
+
},
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### "[loadPoliciesFromAdapter] Invalid state of enforcer"
|
|
323
|
+
|
|
324
|
+
**Cause:** `loadPoliciesFromAdapter()` was called but the internal casbin enforcer is null. This is an internal state error.
|
|
325
|
+
|
|
326
|
+
**Fix:** This should not occur in normal usage. If it does, ensure `configure()` completed successfully before any policy loading operations.
|
|
327
|
+
|
|
328
|
+
### "[extractPolicyLines] Invalid state of enforcer"
|
|
329
|
+
|
|
330
|
+
**Cause:** `extractPolicyLines()` was called but the internal casbin enforcer is null. This method is called during Redis cache miss flow.
|
|
331
|
+
|
|
332
|
+
**Fix:** Same as above -- ensure `configure()` completed before policy operations.
|
|
333
|
+
|
|
334
|
+
### "[loadPolicyLinesIntoModel] Enforcer not initialized"
|
|
335
|
+
|
|
336
|
+
**Cause:** `loadPolicyLinesIntoModel()` was called but the internal casbin enforcer is null. This method is called during Redis cache hit flow to load cached lines.
|
|
337
|
+
|
|
338
|
+
**Fix:** Same as above -- ensure `configure()` completed before policy operations.
|
|
339
|
+
|
|
340
|
+
### Invalid driver errors
|
|
341
|
+
|
|
342
|
+
**Messages:**
|
|
343
|
+
- `[buildRules] Invalid cached.driver | Valids: [in-memory, redis]`
|
|
344
|
+
- `[resolveCasbinEnforcer] Invalid cached.driver | Valids: [in-memory, redis]`
|
|
345
|
+
- `[resolveModel] Invalid model.driver | Valids: [file, text]`
|
|
346
|
+
|
|
347
|
+
**Cause:** An unsupported driver string was passed in the options.
|
|
348
|
+
|
|
349
|
+
**Fix:** Use one of the valid values:
|
|
350
|
+
- Cache drivers: `CasbinEnforcerCachedDrivers.IN_MEMORY` (`'in-memory'`) or `CasbinEnforcerCachedDrivers.REDIS` (`'redis'`)
|
|
351
|
+
- Model drivers: `CasbinEnforcerModelDrivers.FILE` (`'file'`) or `CasbinEnforcerModelDrivers.TEXT` (`'text'`)
|
|
352
|
+
|
|
353
|
+
## Common Patterns
|
|
354
|
+
|
|
355
|
+
### Authorization Is Not Running
|
|
356
|
+
|
|
357
|
+
Check middleware injection order:
|
|
358
|
+
1. Verify `authorize` is set on the route config (not just `authenticate`)
|
|
359
|
+
2. Verify `authenticate` is not set to `{ skip: true }` (which also skips authorization in CRUD factory)
|
|
360
|
+
3. Verify the component is registered and enforcers are registered via the registry
|
|
361
|
+
|
|
362
|
+
### Rules Are Built On Every Request
|
|
363
|
+
|
|
364
|
+
Check that rules are being cached correctly. The middleware caches on `Authorization.RULES`:
|
|
365
|
+
- Cached per-request (each new request starts fresh)
|
|
366
|
+
- Multiple authorization specs on the same route share the cache
|
|
367
|
+
- If rules are `undefined` or `null`, they will be rebuilt
|
|
368
|
+
|
|
369
|
+
### Casbin Policies Not Loading
|
|
370
|
+
|
|
371
|
+
1. **Check adapter entities** -- ensure `tableName` and `principalType` match your database schema
|
|
372
|
+
2. **Check variant column** -- policy rows must have `variant = 'policy'` (`CasbinRuleVariants.POLICY`), role assignments must have `variant = 'group'` (`CasbinRuleVariants.GROUP`)
|
|
373
|
+
3. **Check subject/target types** -- the SQL queries filter by `subject_type` and `target_type`
|
|
374
|
+
4. **Check the model file** -- ensure your `.conf` file matches the policy format (e.g., domain-aware vs simple)
|
|
375
|
+
|
|
376
|
+
### Redis Cache Not Working
|
|
377
|
+
|
|
378
|
+
1. **Check Redis connection** -- verify `DefaultRedisHelper` is properly connected
|
|
379
|
+
2. **Check keyFn** -- ensure it returns a unique, non-empty key per user
|
|
380
|
+
3. **Check expiresIn** -- must be >= 10,000 ms (`MIN_EXPIRES_IN`)
|
|
381
|
+
4. **Verify cache hit** -- check logs for `"Loaded CACHED Policies"` vs `"Loaded ADAPTER + CACHED Policies"`
|
|
382
|
+
|
|
383
|
+
## See Also
|
|
384
|
+
|
|
385
|
+
- [Setup & Configuration](./) -- Binding keys, options interfaces, and initial setup
|
|
386
|
+
- [Usage & Examples](./usage) -- Securing routes, voters, patterns, and CRUD integration
|
|
387
|
+
- [API Reference](./api) -- Architecture, enforcer internals, provider, registry, and adapters
|