ldap-rest 0.1.4 → 0.1.6

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 (51) hide show
  1. package/README.md +31 -21
  2. package/docs/README.md +23 -486
  3. package/docs/{DEVELOPER_GUIDE.md → client-development/README.md} +24 -24
  4. package/docs/client-development/api/README.md +75 -0
  5. package/docs/client-development/browser/README.md +65 -0
  6. package/docs/{plugins/DEVELOPMENT.md → plugin-development/README.md} +4 -9
  7. package/docs/plugin-development/hooks.md +18 -0
  8. package/docs/usage/README.md +89 -0
  9. package/docs/usage/configuration.md +375 -0
  10. package/docs/usage/plugins/README.md +87 -0
  11. package/docs/usage/plugins/auth/README.md +65 -0
  12. package/docs/usage/plugins/auth/crowdsec.md +95 -0
  13. package/docs/usage/plugins/auth/hmac.md +293 -0
  14. package/docs/usage/plugins/auth/llng.md +99 -0
  15. package/docs/usage/plugins/auth/oidc.md +167 -0
  16. package/docs/usage/plugins/auth/rate-limit.md +62 -0
  17. package/docs/usage/plugins/auth/token.md +136 -0
  18. package/docs/usage/plugins/auth/totp.md +213 -0
  19. package/docs/usage/plugins/auth/trusted-proxy.md +127 -0
  20. package/docs/usage/plugins/integrations/README.md +42 -0
  21. package/docs/usage/plugins/ldap/README.md +79 -0
  22. package/docs/usage/troubleshooting.md +105 -0
  23. package/package.json +9 -1
  24. package/docs/authentication.md +0 -1194
  25. /package/docs/{OPENAPI.md → client-development/api/openapi.md} +0 -0
  26. /package/docs/{api/REFERENCE.md → client-development/api/reference.md} +0 -0
  27. /package/docs/{api/REST_API.md → client-development/api/rest-api.md} +0 -0
  28. /package/docs/{browser/LIBRARIES.md → client-development/browser/libraries.md} +0 -0
  29. /package/docs/{examples/EXAMPLES.md → client-development/examples/README.md} +0 -0
  30. /package/docs/{examples → client-development/examples/ldif}/twake-mailbox-type-nomenclature.ldif +0 -0
  31. /package/docs/{examples → client-development/examples/ldif}/twake-mailbox-type-schema-amendment.ldif +0 -0
  32. /package/docs/{schemas/SCHEMAS.md → client-development/schemas/README.md} +0 -0
  33. /package/docs/{PLUGIN_DEPENDENCIES.md → plugin-development/dependencies.md} +0 -0
  34. /package/docs/{testing-with-embedded-ldap.md → plugin-development/testing.md} +0 -0
  35. /package/docs/{presenterm.md → presentations/en.md} +0 -0
  36. /package/docs/{presenterm-fr.md → presentations/fr.md} +0 -0
  37. /package/docs/{authzLinid1.md → usage/plugins/auth/authz-linid1.md} +0 -0
  38. /package/docs/{authzPerBranch.md → usage/plugins/auth/authz-per-branch.md} +0 -0
  39. /package/docs/{twakeAppAccountsApi.md → usage/plugins/integrations/app-accounts.md} +0 -0
  40. /package/docs/{twakeCalendarResources.md → usage/plugins/integrations/calendar-resources.md} +0 -0
  41. /package/docs/{twakeJames.md → usage/plugins/integrations/james-mail.md} +0 -0
  42. /package/docs/{jamesTeamMailboxes.md → usage/plugins/integrations/james-mailboxes.md} +0 -0
  43. /package/docs/{ldapBulkImport.md → usage/plugins/ldap/bulk-import.md} +0 -0
  44. /package/docs/{ldapExternalUsersInGroups.md → usage/plugins/ldap/external-users.md} +0 -0
  45. /package/docs/{ldapFlatGeneric.md → usage/plugins/ldap/flat-generic.md} +0 -0
  46. /package/docs/{ldapGroups.md → usage/plugins/ldap/groups.md} +0 -0
  47. /package/docs/{onChange.md → usage/plugins/ldap/on-change.md} +0 -0
  48. /package/docs/{ldapOrganizations.md → usage/plugins/ldap/organizations.md} +0 -0
  49. /package/docs/{ldapTrash.md → usage/plugins/ldap/trash.md} +0 -0
  50. /package/docs/{static.md → usage/plugins/utilities/static.md} +0 -0
  51. /package/docs/{weblogs.md → usage/plugins/utilities/weblogs.md} +0 -0
@@ -1,1194 +0,0 @@
1
- # Authentication Plugins
2
-
3
- LDAP-Rest provides multiple authentication plugins to secure API access. These plugins can be used individually or combined depending on your infrastructure requirements.
4
-
5
- ## Available Authentication Methods
6
-
7
- 1. **Token Authentication** (`core/auth/token`) - Simple bearer token authentication
8
- 2. **TOTP Authentication** (`core/auth/totp`) - Time-based One-Time Password authentication
9
- 3. **HMAC Authentication** (`core/auth/hmac`) - HMAC-SHA256 request signing for backend services
10
- 4. **LemonLDAP::NG** (`core/auth/llng`) - Integration with LemonLDAP::NG SSO
11
- 5. **OpenID Connect** (`core/auth/openidconnect`) - OAuth 2.0 / OpenID Connect authentication
12
- 6. **Authorization Per Branch** (`core/auth/authzPerBranch`) - Branch-level access control (see [authzPerBranch.md](authzPerBranch.md))
13
-
14
- ## Security Plugins
15
-
16
- 1. **Trusted Proxy** (`core/auth/trustedProxy`) - Validate X-Forwarded-For headers from reverse proxies
17
- 2. **Rate Limiting** (`core/auth/rateLimit`) - Prevent brute force attacks
18
- 3. **CrowdSec** (`core/auth/crowdsec`) - IP reputation and blocking
19
-
20
- ## Trusted Proxy
21
-
22
- When running behind a reverse proxy (nginx, Apache, HAProxy, etc.), client IP addresses are typically passed via `X-Forwarded-For` headers. The `trustedProxy` plugin validates these headers to prevent IP spoofing attacks.
23
-
24
- ### Configuration
25
-
26
- ```bash
27
- --plugin core/auth/trustedProxy \
28
- --trusted-proxy "127.0.0.1" \
29
- --trusted-proxy "10.0.0.0/8" \
30
- --trusted-proxy "192.168.0.0/16"
31
- ```
32
-
33
- **Environment Variables:**
34
-
35
- ```bash
36
- # Comma-separated list of trusted proxy IPs or CIDR ranges
37
- DM_TRUSTED_PROXIES="127.0.0.1,10.0.0.0/8,192.168.0.0/16,::1"
38
-
39
- # Optional: Header name for authenticated user from proxy (default: Auth-User)
40
- DM_TRUSTED_PROXY_AUTH_HEADER="Auth-User"
41
- ```
42
-
43
- ### How It Works
44
-
45
- 1. **Request arrives** from reverse proxy
46
- 2. **Plugin checks** if `req.socket.remoteAddress` matches a trusted proxy
47
- 3. **If trusted:**
48
- - `X-Forwarded-For` header is preserved
49
- - `Auth-User` header (or custom header) is extracted for logging
50
- - Request is marked as `req.trustedProxy = true`
51
- 4. **If untrusted:**
52
- - `X-Forwarded-For` header is **removed** to prevent IP spoofing
53
- - Request is marked as `req.trustedProxy = false`
54
- 5. **Other plugins** (rate limiting, CrowdSec, weblogs) see sanitized headers
55
-
56
- ### Supported Formats
57
-
58
- - **IPv4 addresses:** `192.168.1.1`
59
- - **IPv6 addresses:** `::1`, `fe80::1`
60
- - **CIDR ranges:** `10.0.0.0/8`, `192.168.0.0/16`, `2001:db8::/32`
61
- - **IPv4-mapped IPv6:** Automatically handled (e.g., `::ffff:127.0.0.1` matches `127.0.0.1`)
62
-
63
- ### Auth-User Header
64
-
65
- When requests come from a trusted proxy, the plugin can extract an authenticated username from a header set by the proxy. This is useful for:
66
-
67
- - Logging who made the request (even if LDAP-Rest doesn't handle authentication)
68
- - Passing identity from an upstream authentication system
69
-
70
- ```bash
71
- # Custom header name (default: Auth-User)
72
- DM_TRUSTED_PROXY_AUTH_HEADER="X-Remote-User"
73
- ```
74
-
75
- The extracted username is:
76
- - Available as `req.proxyAuthUser` for other plugins
77
- - Used by the `weblogs` plugin to log the user field
78
-
79
- ### Example: nginx Configuration
80
-
81
- ```nginx
82
- upstream ldap_rest {
83
- server 127.0.0.1:8081;
84
- }
85
-
86
- server {
87
- listen 443 ssl;
88
- server_name api.example.com;
89
-
90
- location / {
91
- proxy_pass http://ldap_rest;
92
- proxy_set_header Host $host;
93
- proxy_set_header X-Real-IP $remote_addr;
94
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
95
- proxy_set_header X-Forwarded-Proto $scheme;
96
-
97
- # Optional: Pass authenticated user from nginx auth
98
- proxy_set_header Auth-User $remote_user;
99
- }
100
- }
101
- ```
102
-
103
- LDAP-Rest configuration:
104
-
105
- ```bash
106
- DM_TRUSTED_PROXIES="127.0.0.1"
107
- ```
108
-
109
- ### Example: HAProxy Configuration
110
-
111
- ```haproxy
112
- frontend https
113
- bind *:443 ssl crt /etc/ssl/cert.pem
114
- default_backend ldap_rest
115
-
116
- backend ldap_rest
117
- option forwardfor
118
- http-request set-header X-Forwarded-Proto https
119
- server ldap_rest 127.0.0.1:8081
120
- ```
121
-
122
- ### Use Cases
123
-
124
- - **Reverse Proxy Deployments:** Ensure correct client IP for rate limiting and logging
125
- - **Load Balancers:** Trust headers from known load balancer IPs
126
- - **CDN Integration:** Trust headers from CDN edge servers
127
- - **Kubernetes:** Trust headers from ingress controllers
128
- - **Security:** Prevent attackers from spoofing `X-Forwarded-For` to bypass rate limits
129
-
130
- ### Security Considerations
131
-
132
- - **Only trust known proxies:** Never use `0.0.0.0/0` or trust all IPs
133
- - **Use specific IPs/ranges:** Limit to your actual proxy infrastructure
134
- - **HTTPS between proxy and LDAP-Rest:** Prevent header injection attacks
135
- - **Monitor logs:** Watch for warnings about removed X-Forwarded-For headers
136
-
137
- ### Plugin Load Order
138
-
139
- The `trustedProxy` plugin is automatically loaded **first** (via `priority.json`) to ensure all other plugins see sanitized headers:
140
-
141
- 1. `core/auth/trustedProxy` - Sanitizes X-Forwarded-For headers
142
- 2. `core/weblogs` - Logs requests with correct client IP
143
- 3. `core/auth/crowdsec` - Checks IP reputation
144
- 4. `core/auth/rateLimit` - Rate limits by IP
145
- 5. Authentication plugins...
146
-
147
- ## Token Authentication
148
-
149
- Simple stateless authentication using bearer tokens.
150
-
151
- ### Configuration
152
-
153
- #### Basic Configuration
154
-
155
- ```bash
156
- --plugin core/auth/token \
157
- --auth-token "secret-token-1" \
158
- --auth-token "secret-token-2" \
159
- --auth-token "secret-token-3"
160
- ```
161
-
162
- **Environment Variable:**
163
-
164
- ```bash
165
- DM_AUTH_TOKENS="token1,token2,token3"
166
- ```
167
-
168
- #### Named Tokens (Recommended)
169
-
170
- Associate a descriptive name with each token for better logging and audit trails:
171
-
172
- ```bash
173
- --plugin core/auth/token \
174
- --auth-token "9f8e7d6c5b4a:web-application" \
175
- --auth-token "1a2b3c4d5e6f:monitoring-service" \
176
- --auth-token "f1e2d3c4b5a6:backup-scripts"
177
- ```
178
-
179
- **Environment Variable:**
180
-
181
- ```bash
182
- DM_AUTH_TOKENS="9f8e7d6c5b4a:web-application,1a2b3c4d5e6f:monitoring-service,f1e2d3c4b5a6:backup-scripts"
183
- ```
184
-
185
- **Syntax:** `token:name`
186
-
187
- - Token value comes first (the secret)
188
- - Colon `:` separator
189
- - Name comes second (descriptive identifier)
190
-
191
- ### Usage
192
-
193
- Include the token in the `Authorization` header:
194
-
195
- ```bash
196
- curl -H "Authorization: Bearer 9f8e7d6c5b4a" \
197
- http://localhost:8081/api/v1/ldap/users
198
- ```
199
-
200
- ### How It Works
201
-
202
- 1. Extracts token from `Authorization: Bearer <token>` header
203
- 2. Validates token against configured list
204
- 3. Sets `req.user` to the token's name (e.g., `"web-application"`) or `"token {index}"` for unnamed tokens
205
- 4. Returns 401 Unauthorized if token is missing or invalid
206
-
207
- **Named tokens in logs:**
208
-
209
- ```
210
- INFO: Request from user: web-application
211
- INFO: Request from user: monitoring-service
212
- ```
213
-
214
- **Unnamed tokens in logs (backward compatible):**
215
-
216
- ```
217
- INFO: Request from user: token 0
218
- INFO: Request from user: token 1
219
- ```
220
-
221
- ### Use Cases
222
-
223
- - **Development/Testing**: Quick authentication without complex setup
224
- - **Service-to-Service**: API access for backend services
225
- - **CI/CD Pipelines**: Automated scripts and deployments
226
- - **Simple Deployments**: Small teams without SSO infrastructure
227
-
228
- ### Security Considerations
229
-
230
- - Tokens are static and shared (not user-specific)
231
- - Use HTTPS in production to protect tokens in transit
232
- - Rotate tokens regularly
233
- - Limit token count to necessary services only
234
- - Consider combining with IP whitelisting
235
-
236
- ### Example: Multiple Services with Named Tokens
237
-
238
- ```bash
239
- # API server configuration with named tokens
240
- npx ldap-rest \
241
- --plugin core/auth/token \
242
- --auth-token "a1b2c3d4e5f6:production-web-app" \
243
- --auth-token "f6e5d4c3b2a1:prometheus-monitoring" \
244
- --auth-token "1234567890ab:nightly-backup" \
245
- --ldap-url ldap://localhost:389 \
246
- ...
247
- ```
248
-
249
- ```bash
250
- # Web application (logs will show: user: production-web-app)
251
- curl -H "Authorization: Bearer a1b2c3d4e5f6" \
252
- http://api/v1/ldap/users
253
-
254
- # Monitoring system (logs will show: user: prometheus-monitoring)
255
- curl -H "Authorization: Bearer f6e5d4c3b2a1" \
256
- http://api/v1/ldap/groups
257
-
258
- # Backup script (logs will show: user: nightly-backup)
259
- curl -H "Authorization: Bearer 1234567890ab" \
260
- http://api/v1/ldap/organizations/top
261
- ```
262
-
263
- ### Example: Mixed Named and Unnamed Tokens
264
-
265
- You can mix named and unnamed tokens for backward compatibility:
266
-
267
- ```bash
268
- --auth-token "abc123:production-api" \
269
- --auth-token "def456" # Unnamed, will be "token 1" in logs \
270
- --auth-token "ghi789:staging-app"
271
- ```
272
-
273
- ## TOTP Authentication
274
-
275
- Time-based One-Time Password (TOTP) authentication using dynamic codes compatible with authenticator apps.
276
-
277
- ### Configuration
278
-
279
- #### Basic Configuration
280
-
281
- ```bash
282
- --plugin core/auth/totp \
283
- --auth-totp "JBSWY3DPEHPK3PXP:admin:6" \
284
- --auth-totp "HXDMVJECJJWSRB3H:service:8"
285
- ```
286
-
287
- **Environment Variable:**
288
-
289
- ```bash
290
- DM_AUTH_TOTP="JBSWY3DPEHPK3PXP:admin:6,HXDMVJECJJWSRB3H:service:8"
291
- ```
292
-
293
- **Syntax:** `secret:name[:digits]`
294
-
295
- - **secret**: Base32-encoded secret (e.g., generated by authenticator apps)
296
- - **name**: Descriptive user/service name
297
- - **digits**: Number of digits in TOTP code (optional, 6-10, default: 6)
298
-
299
- #### Advanced Configuration
300
-
301
- ```bash
302
- --auth-totp-window 1 # Time window tolerance (±30s with step=30)
303
- --auth-totp-step 30 # Time step in seconds (default: 30)
304
- ```
305
-
306
- **Environment Variables:**
307
-
308
- ```bash
309
- DM_AUTH_TOTP_WINDOW=1 # Default: 1
310
- DM_AUTH_TOTP_STEP=30 # Default: 30
311
- ```
312
-
313
- - **window**: Number of time steps to check before/after current time (compensates for clock drift)
314
- - **step**: Time interval in seconds for code generation (typically 30)
315
-
316
- ### Generating Secrets
317
-
318
- Use an authenticator app or generate Base32 secrets:
319
-
320
- ```bash
321
- # Using Node.js crypto (example)
322
- node -e "console.log(require('crypto').randomBytes(20).toString('base32'))"
323
- ```
324
-
325
- ### Usage
326
-
327
- #### HTTP Requests
328
-
329
- Include the current TOTP code in the `Authorization` header:
330
-
331
- ```bash
332
- # Get current TOTP code from your authenticator app
333
- curl -H "Authorization: Bearer 123456" \
334
- http://localhost:8081/api/v1/ldap/users
335
- ```
336
-
337
- #### Browser Client
338
-
339
- The TOTP client library is available as an npm module export:
340
-
341
- ```bash
342
- npm install ldap-rest
343
- ```
344
-
345
- ```typescript
346
- import {
347
- TotpAuthClient,
348
- generateTotp,
349
- getRemainingSeconds,
350
- isValidBase32,
351
- } from 'ldap-rest/browser-shared-utils-totp';
352
-
353
- const client = new TotpAuthClient({
354
- secret: 'JBSWY3DPEHPK3PXP',
355
- digits: 6,
356
- step: 30,
357
- });
358
-
359
- // Automatic authentication with current TOTP code
360
- const response = await client.get('/api/v1/ldap/users');
361
- const users = await response.json();
362
-
363
- // Or get current code manually
364
- const code = await client.getCode();
365
- console.log(`Current TOTP code: ${code}`);
366
- ```
367
-
368
- **Live Demo:** See [examples/web/totp-client.html](../../examples/web/totp-client.html) for an interactive demonstration.
369
-
370
- ### How It Works
371
-
372
- 1. Extracts TOTP code from `Authorization: Bearer <code>` header
373
- 2. Generates expected TOTP codes for current time window
374
- 3. Validates code against all configured users' secrets
375
- 4. Supports multiple time windows (±window × step seconds) for clock drift tolerance
376
- 5. Sets `req.user` to the user's name on successful validation
377
- 6. Returns 401 Unauthorized if code is missing, invalid, or expired
378
-
379
- ### Multi-User Example
380
-
381
- ```bash
382
- # Configure multiple users with different code lengths
383
- --plugin core/auth/totp \
384
- --auth-totp "JBSWY3DPEHPK3PXP:admin:6" \
385
- --auth-totp "HXDMVJECJJWSRB3H:api-service:8" \
386
- --auth-totp "IXDMVJECJJWSRB2A:monitoring:10"
387
- ```
388
-
389
- **In logs:**
390
-
391
- ```
392
- INFO: TOTP authentication successful for user: admin
393
- INFO: TOTP authentication successful for user: api-service
394
- ```
395
-
396
- ### Use Cases
397
-
398
- - **Enhanced Security**: Dynamic codes that expire every 30 seconds
399
- - **No Shared Secrets**: Each user/service has unique TOTP secret
400
- - **Compatible**: Works with Google Authenticator, Authy, 1Password, etc.
401
- - **API Access**: Suitable for automated scripts with TOTP generation
402
- - **Multi-Factor**: Can be combined with other authentication methods
403
-
404
- ### Security Considerations
405
-
406
- - **Secret Storage**: Store Base32 secrets securely (encrypted configuration, environment variables)
407
- - **HTTPS Required**: Always use HTTPS to protect TOTP codes in transit
408
- - **Clock Synchronization**: Ensure server and client clocks are synchronized (NTP recommended)
409
- - **Window Size**: Larger windows are more tolerant but slightly less secure
410
- - **Secret Rotation**: Rotate TOTP secrets periodically for better security
411
- - **Rate Limiting**: Consider adding rate limiting to prevent brute force attacks
412
-
413
- ### Browser Client Features
414
-
415
- The TOTP browser library provides these functions and classes:
416
-
417
- ```typescript
418
- import {
419
- generateTotp,
420
- getRemainingSeconds,
421
- isValidBase32,
422
- TotpAuthClient
423
- } from 'ldap-rest/browser-shared-utils-totp';
424
-
425
- // Generate TOTP code
426
- const code = await generateTotp({
427
- secret: 'JBSWY3DPEHPK3PXP',
428
- digits: 6,
429
- step: 30
430
- });
431
-
432
- // Check validity time
433
- const remaining = getRemainingSeconds(30);
434
- console.log(`Code expires in ${remaining} seconds`);
435
-
436
- // Validate secret format
437
- if (isValidBase32('JBSWY3DPEHPK3PXP')) {
438
- console.log('Valid Base32 secret');
439
- }
440
-
441
- // HTTP client with automatic TOTP authentication
442
- const client = new TotpAuthClient({
443
- secret: 'JBSWY3DPEHPK3PXP',
444
- digits: 6,
445
- step: 30
446
- });
447
-
448
- // All HTTP methods automatically include TOTP in Authorization header
449
- await client.post('/api/v1/ldap/users', { uid: 'user1', ... });
450
- await client.put('/api/v1/ldap/users/user1', { mail: 'new@example.com' });
451
- await client.delete('/api/v1/ldap/users/user1');
452
- ```
453
-
454
- **Module Export:** `ldap-rest/browser-shared-utils-totp`
455
-
456
- **Live Demo:** Run the server and open [http://localhost:8081/static/examples/web/totp-client.html](http://localhost:8081/static/examples/web/totp-client.html)
457
-
458
- ### Troubleshooting
459
-
460
- **Problem:** 401 Unauthorized despite correct code
461
-
462
- **Solutions:**
463
-
464
- 1. Verify secret is correctly configured (Base32 format)
465
- 2. Check system clock synchronization (use NTP)
466
- 3. Increase `--auth-totp-window` if experiencing timing issues
467
- 4. Ensure code is used immediately (codes expire every 30s)
468
- 5. Verify `Authorization: Bearer {code}` format
469
-
470
- **Problem:** Codes don't match authenticator app
471
-
472
- **Solutions:**
473
-
474
- 1. Verify secret matches exactly (case-sensitive Base32)
475
- 2. Check `--auth-totp-step` matches app configuration (usually 30)
476
- 3. Ensure both server and device clocks are synchronized
477
- 4. Confirm correct number of digits configured
478
-
479
- **Problem:** Invalid Base32 secret warning
480
-
481
- **Solutions:**
482
-
483
- 1. Secret must contain only A-Z and 2-7 characters
484
- 2. Use proper Base32 encoding (not Base64)
485
- 3. Remove padding `=` characters if present (optional)
486
-
487
- ## HMAC Authentication
488
-
489
- HMAC-SHA256 request signing authentication for backend services (Registration Service, admin panel backend, cloudery, etc.).
490
-
491
- ### Configuration
492
-
493
- #### Basic Configuration
494
-
495
- ```bash
496
- --plugin core/auth/hmac \
497
- --auth-hmac "registration-service:secret-key-minimum-32-chars:Registration Service" \
498
- --auth-hmac "cloudery:another-secret-key-long-enough:Cloudery Backend"
499
- ```
500
-
501
- **Environment Variable:**
502
-
503
- ```bash
504
- DM_AUTH_HMAC="registration-service:secret-key-minimum-32-chars:Registration Service,cloudery:another-secret-key-long-enough:Cloudery Backend"
505
- ```
506
-
507
- **Syntax:** `service-id:secret:name`
508
-
509
- - **service-id**: Service identifier (e.g., `registration-service`, `cloudery`)
510
- - **secret**: Shared secret for HMAC (minimum 32 characters recommended)
511
- - **name**: Descriptive service name (can contain colons)
512
-
513
- #### Advanced Configuration
514
-
515
- ```bash
516
- --auth-hmac-window 120000 # Time window in milliseconds (default: 120000 = 2 minutes)
517
- ```
518
-
519
- **Environment Variable:**
520
-
521
- ```bash
522
- DM_AUTH_HMAC_WINDOW=120000 # Default: 120000ms (2 minutes)
523
- ```
524
-
525
- - **window**: Maximum time difference (in milliseconds) between server and client timestamp
526
- - Prevents replay attacks by rejecting requests with timestamps outside the window
527
-
528
- ### How It Works
529
-
530
- #### Request Signing Process
531
-
532
- 1. **Client calculates signature:**
533
-
534
- ```
535
- signature = HMAC-SHA256(
536
- secret,
537
- "METHOD|PATH|timestamp|body-hash"
538
- )
539
- ```
540
-
541
- Where:
542
- - `METHOD`: HTTP method (GET, POST, PATCH, DELETE, PUT, etc.)
543
- - `PATH`: Request path with query string (e.g., `/api/v1/ldap/users?filter=active`)
544
- - `timestamp`: Unix timestamp in milliseconds (e.g., `1698765432000`)
545
- - `body-hash`: SHA256(request_body) for POST/PATCH/PUT, empty string for GET/DELETE/HEAD
546
-
547
- 2. **Client sends Authorization header:**
548
-
549
- ```
550
- Authorization: HMAC-SHA256 service-id:timestamp:signature
551
- ```
552
-
553
- 3. **Server validates:**
554
- - Extracts `service-id`, `timestamp`, and `signature` from header
555
- - Verifies timestamp is within configured window (prevents replay attacks)
556
- - Retrieves service secret using `service-id`
557
- - Recalculates signature using same method
558
- - Compares signatures using constant-time comparison (prevents timing attacks)
559
- - Rejects if mismatch or timestamp expired
560
-
561
- 4. **On success:**
562
- - Sets `req.user` to service name
563
- - Allows request to proceed
564
-
565
- ### Usage
566
-
567
- #### Manual Request Example
568
-
569
- ```bash
570
- # Example: GET request
571
- SERVICE_ID="registration-service"
572
- SECRET="secret-key-minimum-32-chars"
573
- METHOD="GET"
574
- PATH="/api/v1/ldap/users"
575
- TIMESTAMP=$(date +%s000) # Unix timestamp in milliseconds
576
-
577
- # Calculate body hash (empty for GET)
578
- BODY_HASH=""
579
-
580
- # Create signing string
581
- SIGNING_STRING="${METHOD}|${PATH}|${TIMESTAMP}|${BODY_HASH}"
582
-
583
- # Calculate HMAC-SHA256 signature
584
- SIGNATURE=$(echo -n "$SIGNING_STRING" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)
585
-
586
- # Make request
587
- curl -H "Authorization: HMAC-SHA256 ${SERVICE_ID}:${TIMESTAMP}:${SIGNATURE}" \
588
- http://localhost:8081${PATH}
589
- ```
590
-
591
- #### POST Request with Body
592
-
593
- ```bash
594
- SERVICE_ID="registration-service"
595
- SECRET="secret-key-minimum-32-chars"
596
- METHOD="POST"
597
- PATH="/api/v1/ldap/users"
598
- TIMESTAMP=$(date +%s000)
599
- BODY='{"uid":"user1","mail":"user1@example.com"}'
600
-
601
- # Calculate body hash
602
- BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 | cut -d' ' -f2)
603
-
604
- # Create signing string
605
- SIGNING_STRING="${METHOD}|${PATH}|${TIMESTAMP}|${BODY_HASH}"
606
-
607
- # Calculate signature
608
- SIGNATURE=$(echo -n "$SIGNING_STRING" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)
609
-
610
- # Make request
611
- curl -X POST \
612
- -H "Authorization: HMAC-SHA256 ${SERVICE_ID}:${TIMESTAMP}:${SIGNATURE}" \
613
- -H "Content-Type: application/json" \
614
- -d "$BODY" \
615
- http://localhost:8081${PATH}
616
- ```
617
-
618
- #### Browser Client
619
-
620
- The HMAC client library is available as an npm module export:
621
-
622
- ```bash
623
- npm install ldap-rest
624
- ```
625
-
626
- ```typescript
627
- import { HmacAuthClient } from 'ldap-rest/browser-shared-utils-hmac';
628
-
629
- const client = new HmacAuthClient({
630
- serviceId: 'registration-service',
631
- secret: 'secret-key-minimum-32-chars',
632
- });
633
-
634
- // Automatic authentication with HMAC signature
635
- const response = await client.get('/api/v1/ldap/users');
636
- const users = await response.json();
637
-
638
- // POST with automatic body hashing and signing
639
- await client.post('/api/v1/ldap/users', {
640
- uid: 'user1',
641
- mail: 'user1@example.com',
642
- });
643
-
644
- // Other methods: put, patch, delete
645
- await client.put('/api/v1/ldap/users/user1', { mail: 'new@example.com' });
646
- await client.delete('/api/v1/ldap/users/user1');
647
- ```
648
-
649
- **Manual signature generation:**
650
-
651
- ```typescript
652
- import { generateHmacSignature } from 'ldap-rest/browser-shared-utils-hmac';
653
-
654
- const signature = await generateHmacSignature(
655
- 'secret-key-minimum-32-chars',
656
- 'GET',
657
- '/api/v1/ldap/users',
658
- Date.now(),
659
- undefined // no body for GET
660
- );
661
-
662
- const authHeader = `HMAC-SHA256 registration-service:${Date.now()}:${signature}`;
663
- ```
664
-
665
- ### Use Cases
666
-
667
- - **Backend Services**: Service-to-service authentication (Registration Service, admin panels, etc.)
668
- - **Microservices**: Secure inter-service communication
669
- - **Webhooks**: Verify request authenticity and integrity
670
- - **API Gateways**: Backend service authentication
671
- - **Cloudery Integration**: Secure communication with cloudery backend
672
- - **Automated Services**: CI/CD, monitoring, backup services
673
-
674
- ### Security Considerations
675
-
676
- - **Secret Strength**: Use secrets of at least 32 characters (64+ recommended)
677
- - **Secret Storage**: Store secrets securely (encrypted configuration, environment variables, secret managers)
678
- - **HTTPS Required**: Always use HTTPS to protect signatures in transit
679
- - **Time Synchronization**: Ensure server and client clocks are synchronized (NTP recommended)
680
- - **Replay Protection**: Time window prevents replay attacks (adjust `auth-hmac-window` as needed)
681
- - **Constant-Time Comparison**: Signature validation uses `timingSafeEqual` to prevent timing attacks
682
- - **Secret Rotation**: Rotate secrets periodically for enhanced security
683
- - **Body Integrity**: Body hash ensures request payload hasn't been tampered with
684
- - **Path Integrity**: Full path (including query parameters) is signed
685
-
686
- ### Security Features
687
-
688
- 1. **Replay Attack Prevention**: Timestamp validation with configurable window
689
- 2. **Timing Attack Protection**: Constant-time signature comparison
690
- 3. **Request Integrity**: Body hash ensures payload integrity
691
- 4. **Path Integrity**: Query parameters included in signature
692
- 5. **Multi-Service Support**: Isolated secrets per service
693
- 6. **Clock Drift Tolerance**: Configurable time window (default 2 minutes)
694
-
695
- ### Advantages Over Other Methods
696
-
697
- | Feature | HMAC | Token | TOTP |
698
- | ------------------------- | ------------------ | -------------- | ------------------- |
699
- | **Request Integrity** | ✅ Yes (body hash) | ❌ No | ❌ No |
700
- | **Replay Protection** | ✅ Yes (timestamp) | ❌ No | ✅ Yes (time-based) |
701
- | **Signature Per Request** | ✅ Yes | ❌ No (static) | ✅ Yes (30s codes) |
702
- | **Body Tampering Detect** | ✅ Yes | ❌ No | ❌ No |
703
- | **Path/Query Protection** | ✅ Yes | ❌ No | ❌ No |
704
- | **Setup Complexity** | Medium | Simple | Simple |
705
- | **Best For** | Backend services | Simple APIs | MFA, user auth |
706
-
707
- ### Comparison with Standards
708
-
709
- This implementation is similar to:
710
-
711
- - **AWS Signature V4**: Similar approach but simpler (AWS is more complex with canonicalization)
712
- - **HTTP Message Signatures (RFC 9421)**: IETF standard for HTTP signatures
713
- - **HMAC-Based Authentication**: Industry-standard pattern for service authentication
714
-
715
- Our approach provides a good balance between security and simplicity:
716
-
717
- - ✅ Simpler than AWS Signature V4 (easier to implement)
718
- - ✅ More secure than static tokens (request-specific signatures)
719
- - ✅ Better integrity than TOTP (includes body and path hashing)
720
- - ✅ Standard cryptography (HMAC-SHA256)
721
-
722
- ### Troubleshooting
723
-
724
- **Problem:** 401 Unauthorized despite correct signature
725
-
726
- **Solutions:**
727
-
728
- 1. Verify service-id matches exactly (case-sensitive)
729
- 2. Verify secret is correctly configured (minimum 32 characters)
730
- 3. Check system clock synchronization (use NTP: `ntpdate -q pool.ntp.org`)
731
- 4. Increase `--auth-hmac-window` if experiencing timing issues
732
- 5. Verify Authorization header format: `HMAC-SHA256 service-id:timestamp:signature`
733
- 6. Check server logs for specific error messages
734
- 7. Ensure timestamp is in milliseconds, not seconds
735
- 8. Verify body hash calculation (must match exactly)
736
-
737
- **Problem:** Timestamp outside allowed window
738
-
739
- **Solutions:**
740
-
741
- 1. Synchronize clocks using NTP
742
- 2. Increase `--auth-hmac-window` (default: 120000ms = 2 minutes)
743
- 3. Check if timestamp is in milliseconds (not seconds)
744
- 4. Verify both server and client are using same timezone reference (UTC)
745
-
746
- **Problem:** Signature mismatch
747
-
748
- **Solutions:**
749
-
750
- 1. Verify signing string format: `METHOD|PATH|timestamp|body-hash`
751
- 2. Ensure METHOD is uppercase (GET, POST, etc.)
752
- 3. Include full path with query parameters
753
- 4. For POST/PATCH/PUT: verify body hash is SHA256(JSON.stringify(body))
754
- 5. For GET/DELETE/HEAD: body-hash must be empty string
755
- 6. Ensure secret is exactly the same on client and server
756
- 7. Use hex encoding for signature (lowercase)
757
- 8. Check for trailing whitespace in secret
758
-
759
- **Problem:** Warning about short secrets
760
-
761
- **Solutions:**
762
-
763
- 1. Use secrets of at least 32 characters
764
- 2. Recommended: 64+ characters for enhanced security
765
- 3. Generate secure random secrets:
766
- ```bash
767
- openssl rand -hex 32 # 64-character hex string
768
- node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
769
- ```
770
-
771
- **Debug Example:**
772
-
773
- ```bash
774
- # Enable debug logging
775
- DM_LOG_LEVEL=debug npm start
776
-
777
- # Check signing string in logs
778
- # Expected format: "GET|/api/v1/ldap/users|1698765432000|"
779
- ```
780
-
781
- ## LemonLDAP::NG Authentication
782
-
783
- Integration with [LemonLDAP::NG](https://lemonldap-ng.org/) (LLNG) Web SSO solution.
784
-
785
- ### Configuration
786
-
787
- ```bash
788
- --plugin core/auth/llng \
789
- --llng-ini /etc/lemonldap-ng/lemonldap-ng.ini
790
- ```
791
-
792
- **Environment Variable:**
793
-
794
- ```bash
795
- DM_LLNG_INI="/etc/lemonldap-ng/lemonldap-ng.ini"
796
- ```
797
-
798
- ### Prerequisites
799
-
800
- 1. **LemonLDAP::NG Handler**: The `lemonldap-ng-handler` npm package (optional dependency)
801
- 2. **LLNG Configuration**: Valid `lemonldap-ng.ini` file
802
- 3. **Virtual Host Configuration**: LDAP-Rest must be configured as a protected application in LLNG
803
-
804
- ### How It Works
805
-
806
- 1. Uses the LemonLDAP::NG Handler to validate requests
807
- 2. Extracts user identity from `Lm-Remote-User` header
808
- 3. Sets `req.user` to authenticated username
809
- 4. Inherits all LLNG authorization rules and features
810
-
811
- ### Installation
812
-
813
- Install the optional dependency:
814
-
815
- ```bash
816
- npm install lemonldap-ng-handler
817
- ```
818
-
819
- ### LLNG Configuration
820
-
821
- Configure LDAP-Rest as a protected virtual host in LemonLDAP::NG:
822
-
823
- ```apache
824
- # In LLNG Manager: Virtual Hosts > api.example.com
825
- <VirtualHost *:443>
826
- ServerName api.example.com
827
-
828
- # LemonLDAP::NG Handler
829
- PerlHeaderParserHandler Lemonldap::NG::Handler::ApacheMP2
830
-
831
- # Proxy to LDAP-Rest
832
- ProxyPass / http://localhost:8081/
833
- ProxyPassReverse / http://localhost:8081/
834
- </VirtualHost>
835
- ```
836
-
837
- ### Use Cases
838
-
839
- - **Enterprise SSO**: Centralized authentication for multiple applications
840
- - **Advanced Authorization**: Fine-grained access control using LLNG rules
841
- - **Session Management**: Centralized session handling
842
- - **Multi-Factor Authentication**: MFA support through LLNG
843
-
844
- ### Example: LLNG Authorization Rules
845
-
846
- Configure access rules in LLNG Manager:
847
-
848
- ```perl
849
- # Allow only HR group to access users endpoint
850
- $groups =~ /\bhr\b/ and $uri =~ m#^/api/v1/ldap/users#
851
-
852
- # Allow admins full access
853
- $groups =~ /\badmins\b/
854
-
855
- # Allow specific users to manage groups
856
- $uid eq "groupmanager" and $uri =~ m#^/api/v1/ldap/groups#
857
- ```
858
-
859
- ## OpenID Connect Authentication
860
-
861
- OAuth 2.0 / OpenID Connect authentication for modern identity providers.
862
-
863
- ### Configuration
864
-
865
- ```bash
866
- --plugin core/auth/openidconnect \
867
- --oidc-server "https://auth.example.com" \
868
- --oidc-client-id "ldap-rest-client" \
869
- --oidc-client-secret "client-secret-here" \
870
- --base-url "https://api.example.com"
871
- ```
872
-
873
- **Environment Variables:**
874
-
875
- ```bash
876
- DM_OIDC_SERVER="https://auth.example.com"
877
- DM_OIDC_CLIENT_ID="ldap-rest-client"
878
- DM_OIDC_CLIENT_SECRET="client-secret-here"
879
- DM_BASE_URL="https://api.example.com"
880
- ```
881
-
882
- ### Prerequisites
883
-
884
- 1. **OpenID Provider**: [Lemonldap-NG](https://lemonldap-ng.org), Keycloak, Auth0, Okta, Azure AD, etc.
885
- 2. **Client Registration**: LDAP-Rest registered as OAuth2/OIDC client
886
- 3. **Optional Dependency**: The `express-openid-connect` npm package
887
-
888
- ### Installation
889
-
890
- Install the optional dependency:
891
-
892
- ```bash
893
- npm install express-openid-connect
894
- ```
895
-
896
- ### How It Works
897
-
898
- 1. Uses `express-openid-connect` for OAuth2/OIDC flow
899
- 2. Handles authorization code flow automatically
900
- 3. Extracts user identity from `sub` claim
901
- 4. Sets `req.user` to user's subject identifier
902
- 5. Provides `beforeAuth` and `afterAuth` hooks for customization
903
-
904
- ### Provider Configuration
905
-
906
- #### Keycloak
907
-
908
- ```bash
909
- --oidc-server "https://keycloak.example.com/realms/master" \
910
- --oidc-client-id "ldap-rest" \
911
- --oidc-client-secret "abc123..." \
912
- --base-url "https://api.example.com"
913
- ```
914
-
915
- **Client Settings:**
916
-
917
- - Access Type: `confidential`
918
- - Valid Redirect URIs: `https://api.example.com/callback`
919
- - Standard Flow Enabled: `ON`
920
-
921
- #### Auth0
922
-
923
- ```bash
924
- --oidc-server "https://tenant.auth0.com" \
925
- --oidc-client-id "your-client-id" \
926
- --oidc-client-secret "your-client-secret" \
927
- --base-url "https://api.example.com"
928
- ```
929
-
930
- #### Azure AD
931
-
932
- ```bash
933
- --oidc-server "https://login.microsoftonline.com/{tenant-id}/v2.0" \
934
- --oidc-client-id "application-id" \
935
- --oidc-client-secret "client-secret" \
936
- --base-url "https://api.example.com"
937
- ```
938
-
939
- ### Scopes
940
-
941
- Default scopes requested:
942
-
943
- - `openid` - Basic OpenID Connect
944
- - `profile` - User profile information
945
- - `email` - User email address
946
-
947
- ### Hooks
948
-
949
- The OpenID Connect plugin supports custom hooks:
950
-
951
- #### beforeAuth Hook
952
-
953
- Called before authentication processing:
954
-
955
- ```javascript
956
- hooks: {
957
- beforeAuth: async ([req, res]) => {
958
- // Custom pre-authentication logic
959
- console.log('Authentication attempt from:', req.ip);
960
- return [req, res];
961
- };
962
- }
963
- ```
964
-
965
- #### afterAuth Hook
966
-
967
- Called after successful authentication:
968
-
969
- ```javascript
970
- hooks: {
971
- afterAuth: async ([req, res]) => {
972
- // Access OIDC user data
973
- const user = req.oidc.user;
974
- console.log('User authenticated:', user.email);
975
-
976
- // Add custom user properties
977
- req.customData = {
978
- email: user.email,
979
- name: user.name,
980
- };
981
-
982
- return [req, res];
983
- };
984
- }
985
- ```
986
-
987
- ### Use Cases
988
-
989
- - **Modern Identity Providers**: Integration with cloud identity services
990
- - **Social Login**: Google, Microsoft, GitHub authentication
991
- - **Multi-Tenant Applications**: Different OIDC providers per tenant
992
- - **Standards-Based**: Portable across OIDC-compliant providers
993
-
994
- ## Choosing an Authentication Method
995
-
996
- | Feature | Token | TOTP | HMAC | LemonLDAP::NG | OpenID Connect |
997
- | ---------------------- | ------------- | ----------------- | ---------------------- | --------------------- | -------------------------------- |
998
- | **Setup Complexity** | Simple | Simple | Medium | Medium | Medium |
999
- | **User Management** | None | Manual | Manual (service-based) | External (LLNG) | External (Provider) |
1000
- | **SSO Support** | No | No | No | Yes | Yes |
1001
- | **MFA Support** | No | Yes (TOTP itself) | N/A | Yes (via LLNG) | Yes (via Provider) |
1002
- | **Session Management** | Stateless | Stateless | Stateless | LLNG Sessions | OIDC Sessions |
1003
- | **Code Expiration** | Never | 30-60 seconds | Per-request | Session-based | Session-based |
1004
- | **Request Integrity** | No | No | Yes (body + path hash) | No | No |
1005
- | **Replay Protection** | No | Yes (time-based) | Yes (timestamp) | Session-based | Session-based |
1006
- | **Best For** | APIs, Scripts | APIs, Enhanced | Backend Services | Enterprises with LLNG | Cloud/SaaS, Enterprises with SSO |
1007
- | **Dependencies** | None | None | None | lemonldap-ng-handler | express-openid-connect |
1008
-
1009
- ## Combining with Authorization
1010
-
1011
- All authentication plugins set `req.user` to the authenticated identity. You can use hooks to implement custom authorization:
1012
-
1013
- ```javascript
1014
- hooks: {
1015
- afterAuth: async ([req, res]) => {
1016
- // Check if user can access this endpoint
1017
- if (req.path.startsWith('/api/v1/ldap/users') && !isAdmin(req.user)) {
1018
- throw new Error('Forbidden: Admin access required');
1019
- }
1020
- return [req, res];
1021
- };
1022
- }
1023
- ```
1024
-
1025
- ## Testing Authentication
1026
-
1027
- ### Token Authentication
1028
-
1029
- ```bash
1030
- # Valid request
1031
- curl -H "Authorization: Bearer valid-token" \
1032
- http://localhost:8081/api/v1/ldap/users
1033
-
1034
- # Invalid token
1035
- curl -H "Authorization: Bearer invalid-token" \
1036
- http://localhost:8081/api/v1/ldap/users
1037
- # Returns: 401 Unauthorized
1038
-
1039
- # Missing header
1040
- curl http://localhost:8081/api/v1/ldap/users
1041
- # Returns: 401 Unauthorized
1042
- ```
1043
-
1044
- ### TOTP Authentication
1045
-
1046
- ```bash
1047
- # Get current code from authenticator app (e.g., Google Authenticator)
1048
- # Code changes every 30 seconds
1049
-
1050
- # Valid request with current code
1051
- curl -H "Authorization: Bearer 123456" \
1052
- http://localhost:8081/api/v1/ldap/users
1053
-
1054
- # Invalid/expired code
1055
- curl -H "Authorization: Bearer 999999" \
1056
- http://localhost:8081/api/v1/ldap/users
1057
- # Returns: 401 Unauthorized
1058
-
1059
- # Test with browser client
1060
- node -e "
1061
- import { generateTotp } from './src/browser/shared/utils/totp.js';
1062
- const code = await generateTotp({ secret: 'JBSWY3DPEHPK3PXP', digits: 6 });
1063
- console.log('Current TOTP code:', code);
1064
- "
1065
- ```
1066
-
1067
- ### HMAC Authentication
1068
-
1069
- ```bash
1070
- # Example: GET request with HMAC signature
1071
- SERVICE_ID="registration-service"
1072
- SECRET="secret-key-minimum-32-chars"
1073
- METHOD="GET"
1074
- PATH="/api/hello"
1075
- TIMESTAMP=$(date +%s000)
1076
-
1077
- # Calculate signature
1078
- SIGNING_STRING="${METHOD}|${PATH}|${TIMESTAMP}|"
1079
- SIGNATURE=$(echo -n "$SIGNING_STRING" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)
1080
-
1081
- # Test request
1082
- curl -H "Authorization: HMAC-SHA256 ${SERVICE_ID}:${TIMESTAMP}:${SIGNATURE}" \
1083
- http://localhost:8081${PATH}
1084
-
1085
- # Invalid signature should return 401
1086
- curl -H "Authorization: HMAC-SHA256 ${SERVICE_ID}:${TIMESTAMP}:invalid-sig" \
1087
- http://localhost:8081${PATH}
1088
- # Returns: 401 Unauthorized
1089
- ```
1090
-
1091
- ### LemonLDAP::NG
1092
-
1093
- Access through LLNG portal - authentication is handled by LLNG infrastructure.
1094
-
1095
- ### OpenID Connect
1096
-
1097
- Navigate to API in browser - will redirect to OIDC provider login page, then return with authenticated session.
1098
-
1099
- ## Troubleshooting
1100
-
1101
- ### Token Authentication
1102
-
1103
- **Problem:** 401 Unauthorized despite correct token
1104
-
1105
- **Solutions:**
1106
-
1107
- 1. Ensure `Authorization: Bearer {token}` format (not just the token)
1108
- 2. Check token is in configured list
1109
- 3. Verify no whitespace in token
1110
- 4. Check server logs for token mismatch
1111
-
1112
- ### TOTP Authentication
1113
-
1114
- **Problem:** 401 Unauthorized despite correct code from authenticator app
1115
-
1116
- **Solutions:**
1117
-
1118
- 1. Verify secret matches exactly (Base32, case-sensitive)
1119
- 2. Check system clock synchronization (use NTP: `ntpdate -q pool.ntp.org`)
1120
- 3. Increase `--auth-totp-window` if experiencing timing issues
1121
- 4. Ensure `--auth-totp-step` matches authenticator app (usually 30)
1122
- 5. Check server logs: `"Unauthorized TOTP token: {code}"`
1123
- 6. Verify `Authorization: Bearer {code}` format
1124
-
1125
- **Problem:** Invalid Base32 secret warning in logs
1126
-
1127
- **Solutions:**
1128
-
1129
- 1. Secret must be valid Base32 (A-Z, 2-7 characters only)
1130
- 2. Remove any whitespace from secret
1131
- 3. Generate new secret if corrupted:
1132
- ```bash
1133
- node -e "console.log(require('crypto').randomBytes(20).toString('base32'))"
1134
- ```
1135
-
1136
- **Problem:** Codes expire too quickly
1137
-
1138
- **Solutions:**
1139
-
1140
- 1. Increase `--auth-totp-window` (default: 1, try 2-3 for more tolerance)
1141
- 2. This allows codes from previous/next time windows
1142
- 3. Be aware: larger windows reduce security slightly
1143
-
1144
- ### LemonLDAP::NG
1145
-
1146
- **Problem:** Handler not found
1147
-
1148
- **Solution:** Install optional dependency:
1149
-
1150
- ```bash
1151
- npm install lemonldap-ng-handler
1152
- ```
1153
-
1154
- **Problem:** authentication refused
1155
-
1156
- **Solutions:**
1157
-
1158
- 1. Verify LLNG handler is configured correctly
1159
- 2. Check virtual host configuration
1160
- 3. Review LLNG access logs
1161
-
1162
- ### OpenID Connect
1163
-
1164
- **Problem:** express-openid-connect not found
1165
-
1166
- **Solution:** Install optional dependency:
1167
-
1168
- ```bash
1169
- npm install express-openid-connect
1170
- ```
1171
-
1172
- **Problem:** Missing config parameter
1173
-
1174
- **Solution:** Ensure all required parameters are set:
1175
-
1176
- - `--oidc-server`
1177
- - `--oidc-client-id`
1178
- - `--oidc-client-secret`
1179
- - `--base-url`
1180
-
1181
- **Problem:** Redirect loop
1182
-
1183
- **Solutions:**
1184
-
1185
- 1. Set a long secret, shorts are refused by `openid-client`
1186
- 2. Verify `--base-url` matches actual public URL
1187
- 3. Check redirect URI in provider matches `{base-url}/callback`
1188
- 4. Ensure HTTPS in production (many providers require it)
1189
-
1190
- ## See Also
1191
-
1192
- - [LemonLDAP::NG Documentation](https://lemonldap-ng.org/documentation)
1193
- - [OpenID Connect Specification](https://openid.net/connect/)
1194
- - [express-openid-connect](https://github.com/auth0/express-openid-connect)