keycloak-api-manager 6.0.1 → 6.0.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.
@@ -1,667 +1,21 @@
1
- # PKCE Login Flow Guide
1
+ # PKCE Login Flow (Deprecated In This Package)
2
2
 
3
- ⚠️ **DEPRECATION NOTICE (v6.0.0):** This guide describes PKCE implementation using **deprecated methods** in keycloak-api-manager.
3
+ This package is focused on Keycloak Admin API resource management.
4
4
 
5
- **👉 NEW APPROACH (Recommended):** For user authentication flows, use [`keycloak-express-middleware v6.1.0+`](https://github.com/smartenv-crs4/keycloak-express-middleware) instead. The middleware package provides a more integrated and Express-native implementation of PKCE flows.
5
+ PKCE and user-authentication helpers in this package are deprecated since v6.0.0 and kept only for backward compatibility:
6
6
 
7
- **See:** Migration instructions at the end of this guide.
7
+ - `generateAuthorizationUrl(options)`
8
+ - `loginPKCE(credentials)`
9
+ - `login(credentials)`
10
+ - `auth(credentials)`
8
11
 
9
- ---
12
+ These methods are planned for removal in v7.0.0.
10
13
 
11
- This guide walks you through implementing OAuth2 Authorization Code + PKCE flow in your application using Keycloak and the keycloak-api-manager library.
14
+ For production user authentication flows (including Authorization Code + PKCE), use:
12
15
 
13
- ## Overview
16
+ - https://github.com/smartenv-crs4/keycloak-express-middleware
14
17
 
15
- PKCE (Proof Key for Code Exchange) is the modern, secure way for browser-based and mobile applications to authenticate users through Keycloak. Unlike the legacy resource owner password grant, PKCE:
18
+ Migration references:
16
19
 
17
- - Never exposes user passwords to your backend
18
- - Works seamlessly with Keycloak's authorization server
19
- - ✅ Provides built-in CSRF protection via state parameter
20
- - ✅ Protects against authorization code interception attacks
21
- - ✅ Is the OAuth2 standard for public clients
22
-
23
- ## Flow Diagram
24
-
25
- ```
26
- ┌─────────────┐ ┌──────────────┐
27
- │ Browser │ │ Keycloak │
28
- │ (User) │ │ Server │
29
- └──────┬──────┘ └──────────────┘
30
- │ ▲
31
- │ 1. Click "Login" │
32
- ├─────────────────────────────────────────────────►
33
- │ │
34
- │ 2. Verify state, generate PKCE pair │
35
- │ 3. Redirect to Keycloak /auth with │
36
- │ code_challenge & state │
37
- │ │
38
- │◄─────────────────────────────────────────────────┤
39
- │ Keycloak login page │
40
- │ │
41
- │ 4. User enters credentials │
42
- ├─────────────────────────────────────────────────►
43
- │ │
44
- │ 5. Verify credentials │
45
- │ 6. Redirect to /callback with │
46
- │ code + state │
47
- │ │
48
- │◄─────────────────────────────────────────────────┤
49
- │ code=abc123&state=xyz789 │
50
- │ │
51
- │ 7. Exchange code for token │
52
- │ (with code_verifier) │
53
- │──────────────────────────────────────────────────►
54
- │ POST /auth/callback backend │
55
- │ │
56
- │ ┌────────────┐
57
- │ │ Backend │
58
- │ │ (Node.js) │
59
- │ └────────────┘
60
- │ ▲
61
- │ │
62
- │ │
63
- │ 8. Call loginPKCE()
64
- │ with code, verifier
65
- │ │
66
- │ Keycloak validates
67
- │ code_challenge vs
68
- │ code_verifier
69
- │ │
70
- │ 9. Return access token
71
- │ (JWT)
72
- │ │
73
- │ 10. Set secure HttpOnly cookie │
74
- │◄──────────────────────────────────────────┤
75
- │ (with access_token + refresh_token) │
76
- │ │
77
- │ Browser is now authenticated! │
78
- │ │
79
- ```
80
-
81
- ## Step-by-Step Implementation
82
-
83
- ### Step 1: Generate Authorization URL
84
-
85
- When the user clicks "Login", use `generateAuthorizationUrl()` from keycloak-api-manager to generate the PKCE pair and authorization URL:
86
-
87
- ```javascript
88
- const pkceFlow = KeycloakManager.generateAuthorizationUrl({
89
- redirect_uri: `${process.env.APP_URL}/auth/callback`,
90
- scope: 'openid profile email' // optional, defaults to 'openid profile email'
91
- });
92
-
93
- // Result contains:
94
- // {
95
- // authUrl: 'https://keycloak.example.com/realms/my-realm/protocol/openid-connect/auth?...',
96
- // state: 'random_state_value',
97
- // codeVerifier: 'random_verifier_value'
98
- // }
99
- ```
100
-
101
- Store the `state` and `codeVerifier` in your session, then redirect the user to the authorization URL:
102
-
103
- ```javascript
104
- app.get('/auth/login', (req, res) => {
105
- const pkceFlow = KeycloakManager.generateAuthorizationUrl({
106
- redirect_uri: `${process.env.APP_URL}/auth/callback`
107
- });
108
-
109
- // Store state and verifier in session for callback validation
110
- req.session.pkce_state = pkceFlow.state;
111
- req.session.pkce_verifier = pkceFlow.codeVerifier;
112
-
113
- // Redirect user to Keycloak login
114
- res.redirect(pkceFlow.authUrl);
115
- });
116
- ```
117
-
118
- **Why this works:**
119
- - `generateAuthorizationUrl()` handles all PKCE complexity internally
120
- - Returns a ready-to-use authorization URL
121
- - State parameter provides CSRF protection
122
- - Code verifier is stored server-side (never exposed to client)
123
-
124
- When Keycloak redirects back with the authorization code, you exchange it for an access token using `loginPKCE()`:
125
-
126
- ```javascript
127
- // User callback after Keycloak login
128
- app.get('/auth/callback', async (req, res) => {
129
- try {
130
- const { code, state, error } = req.query;
131
-
132
- // 1. Validate state parameter (CSRF protection)
133
- if (state !== req.session.pkce_state) {
134
- return res.status(400).send('Invalid state parameter - CSRF attack detected');
135
- }
136
-
137
- // 2. Check for authorization errors
138
- if (error) {
139
- return res.status(400).send(`Authorization failed: ${error}`);
140
- }
141
-
142
- // 3. Retrieve stored verifier from session
143
- const code_verifier = req.session.pkce_verifier;
144
- if (!code_verifier) {
145
- return res.status(400).send('PKCE verifier not found in session');
146
- }
147
-
148
- // 4. Exchange code for token using keycloak-api-manager
149
- const tokenResponse = await KeycloakManager.loginPKCE({
150
- code,
151
- redirect_uri: `${process.env.APP_URL}/auth/callback`,
152
- code_verifier
153
- });
154
-
155
- // 5. Set secure HTTPOnly cookie with access token
156
- res.cookie('access_token', tokenResponse.access_token, {
157
- httpOnly: true, // Prevent XSS access
158
- secure: true, // HTTPS only
159
- sameSite: 'strict', // CSRF protection
160
- maxAge: tokenResponse.expires_in * 1000
161
- });
162
-
163
- // Also store refresh token separately
164
- res.cookie('refresh_token', tokenResponse.refresh_token, {
165
- httpOnly: true,
166
- secure: true,
167
- sameSite: 'strict',
168
- maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
169
- });
170
-
171
- // 6. Clear sensitive session data
172
- delete req.session.pkce_verifier;
173
- delete req.session.pkce_state;
174
-
175
- // Redirect to application home
176
- res.redirect('/dashboard');
177
-
178
- } catch (error) {
179
- console.error('Token exchange failed:', error);
180
- res.status(500).send('Authentication failed');
181
- }
182
- });
183
- ```
184
-
185
- **Security checks in this step:**
186
- - ✅ Validate `state` matches what we stored (CSRF protection)
187
- - ✅ Check for authorization errors
188
- - ✅ Verify `code_verifier` exists in session
189
- - ✅ Exchange code with verifier (proves we initiated the flow)
190
- - ✅ Store token in HttpOnly cookie (prevents XSS theft)
191
- - ✅ Clear sensitive session data
192
-
193
- ## Complete Working Example
194
-
195
- Here's a complete Express.js application with PKCE flow:
196
-
197
- ```javascript
198
- const express = require('express');
199
- const session = require('express-session');
200
- const jwt = require('jsonwebtoken');
201
- const cookieParser = require('cookie-parser');
202
- const KeycloakManager = require('keycloak-api-manager');
203
-
204
- const app = express();
205
-
206
- // Middleware
207
- app.use(express.json());
208
- app.use(cookieParser());
209
- app.use(session({
210
- secret: process.env.SESSION_SECRET || 'dev-secret',
211
- resave: false,
212
- saveUninitialized: true,
213
- cookie: { httpOnly: true, secure: false } // Set secure: true in production
214
- }));
215
-
216
- // Initialize Keycloak Manager
217
- KeycloakManager.configure({
218
- baseUrl: process.env.KEYCLOAK_URL,
219
- realmName: process.env.KEYCLOAK_REALM,
220
- clientId: process.env.KEYCLOAK_CLIENT_ID,
221
- clientSecret: process.env.KEYCLOAK_CLIENT_SECRET,
222
- grantType: 'client_credentials'
223
- });
224
-
225
- // Routes
226
- app.get('/auth/login', (req, res) => {
227
- // Generate PKCE pair and authorization URL
228
- const pkceFlow = KeycloakManager.generateAuthorizationUrl({
229
- redirect_uri: `${process.env.APP_URL}/auth/callback`,
230
- scope: 'openid profile email'
231
- });
232
-
233
- // Store state and verifier in session (server-side only!)
234
- req.session.pkce_state = pkceFlow.state;
235
- req.session.pkce_verifier = pkceFlow.codeVerifier;
236
-
237
- // Redirect user to Keycloak login
238
- res.redirect(pkceFlow.authUrl);
239
- });
240
-
241
- app.get('/auth/callback', async (req, res) => {
242
- try {
243
- const { code, state, error } = req.query;
244
-
245
- // Validate state (CSRF protection)
246
- if (state !== req.session.pkce_state) {
247
- return res.status(400).send('Invalid state parameter');
248
- }
249
-
250
- if (error) {
251
- return res.status(400).send(`Authorization failed: ${error}`);
252
- }
253
-
254
- const code_verifier = req.session.pkce_verifier;
255
- if (!code_verifier) {
256
- return res.status(400).send('PKCE verifier not found');
257
- }
258
-
259
- // Exchange code for token (client_id + client_secret from configure())
260
- const tokenResponse = await KeycloakManager.loginPKCE({
261
- code,
262
- redirect_uri: `${process.env.APP_URL}/auth/callback`,
263
- code_verifier
264
- });
265
-
266
- // Set secure cookies
267
- res.cookie('access_token', tokenResponse.access_token, {
268
- httpOnly: true,
269
- secure: true,
270
- sameSite: 'strict',
271
- maxAge: tokenResponse.expires_in * 1000
272
- });
273
-
274
- res.cookie('refresh_token', tokenResponse.refresh_token, {
275
- httpOnly: true,
276
- secure: true,
277
- sameSite: 'strict',
278
- maxAge: 7 * 24 * 60 * 60 * 1000
279
- });
280
-
281
- // Clear sensitive data
282
- delete req.session.pkce_verifier;
283
- delete req.session.pkce_state;
284
-
285
- res.redirect('/dashboard');
286
-
287
- } catch (error) {
288
- console.error('Token exchange failed:', error);
289
- res.status(500).send('Authentication failed');
290
- }
291
- });
292
-
293
- app.get('/dashboard', (req, res) => {
294
- const token = req.cookies.access_token;
295
- if (!token) {
296
- return res.redirect('/auth/login');
297
- }
298
-
299
- try {
300
- const decoded = jwt.decode(token); // Or verify with public key in production
301
- res.send(`Welcome, ${decoded.preferred_username}!`);
302
- } catch (error) {
303
- res.redirect('/auth/login');
304
- }
305
- });
306
-
307
- app.get('/logout', (req, res) => {
308
- res.clearCookie('access_token');
309
- res.clearCookie('refresh_token');
310
- req.session.destroy();
311
- res.redirect('/');
312
- });
313
-
314
- // Start server
315
- app.listen(3000, () => {
316
- console.log('Server running on http://localhost:3000');
317
- console.log('Login at http://localhost:3000/auth/login');
318
- });
319
- ```
320
-
321
- ## Environment Variables
322
-
323
- ```bash
324
- KEYCLOAK_URL=http://localhost:8080
325
- KEYCLOAK_REALM=master
326
- KEYCLOAK_CLIENT_ID=my-app
327
- KEYCLOAK_CLIENT_SECRET=your-client-secret
328
- APP_URL=http://localhost:3000
329
- SESSION_SECRET=your-session-secret
330
- ```
331
-
332
- ## Security Best Practices
333
-
334
- ### ✅ DO
335
-
336
- - ✅ Store PKCE verifier in **secure server-side session**, never in cookies
337
- - ✅ Validate state parameter every time (CSRF protection)
338
- - ✅ Use **HttpOnly cookies** for tokens (prevents XSS theft)
339
- - ✅ Use **Secure flag** on cookies (HTTPS only in production)
340
- - ✅ Use **SameSite=strict** on cookies (CSRF protection)
341
- - ✅ Clear sensitive data from session after token exchange
342
- - ✅ Use SHA256 for code_challenge (`S256` method)
343
- - ✅ Generate cryptographically secure random values (use `crypto` module)
344
-
345
- ### ❌ DON'T
346
-
347
- - ❌ Store code_verifier in browser (localStorage, sessionStorage, etc.)
348
- - ❌ Skip state parameter validation
349
- - ❌ Use weak random generators
350
- - ❌ Expose tokens in URL parameters
351
- - ❌ Store tokens in browser storage (vulnerable to XSS)
352
- - ❌ Use plain HTTP (always HTTPS in production)
353
- - ❌ Reuse PKCE pairs or state values
354
-
355
- ## Common Issues & Troubleshooting
356
-
357
- ### "Invalid state parameter - CSRF attack detected"
358
-
359
- **Cause:** Browser tabs have separate sessions, or cookies are not being persisted.
360
-
361
- **Solution:**
362
- ```javascript
363
- // Ensure session cookies are sent with redirects
364
- app.use(session({
365
- cookie: {
366
- httpOnly: true,
367
- secure: true,
368
- sameSite: 'lax' // Allow cross-site for redirects
369
- }
370
- }));
371
- ```
372
-
373
- ### "PKCE verifier not found in session"
374
-
375
- **Cause:** Session was lost between `/auth/login` and `/auth/callback`.
376
-
377
- **Debug:**
378
- ```javascript
379
- app.get('/auth/callback', (req, res) => {
380
- console.log('Session ID:', req.sessionID);
381
- console.log('Session data:', req.session);
382
- // ... rest of callback
383
- });
384
- ```
385
-
386
- ### "Invalid code_challenge"
387
-
388
- **Cause:** The code_challenge calculated by Keycloak doesn't match our SHA256 hash.
389
-
390
- **Verify:** The `createPkcePair()` function uses S256 (SHA256). Ensure code_challenge is:
391
- 1. Lowercase base64url-encoded
392
- 2. Derived from code_verifier with SHA256, not any other hash
393
-
394
- ### Access token not being set
395
-
396
- **Cause:** `loginPKCE()` threw an error that wasn't caught, or response format is different.
397
-
398
- **Debug:**
399
- ```javascript
400
- const tokenResponse = await KeycloakManager.loginPKCE({...});
401
- console.log('Token response:', JSON.stringify(tokenResponse, null, 2));
402
- ```
403
-
404
- Expected response:
405
- ```json
406
- {
407
- "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
408
- "expires_in": 300,
409
- "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
410
- "token_type": "Bearer",
411
- "scope": "openid profile email"
412
- }
413
- ```
414
-
415
- ## Production Considerations
416
-
417
- ### 1. Session Storage
418
-
419
- For production, use Redis instead of in-memory sessions:
420
-
421
- ```javascript
422
- const RedisStore = require('connect-redis').default;
423
- const { createClient } = require('redis');
424
-
425
- const redisClient = createClient();
426
- redisClient.connect();
427
-
428
- app.use(session({
429
- store: new RedisStore({ client: redisClient }),
430
- secret: process.env.SESSION_SECRET,
431
- resave: false,
432
- saveUninitialized: false,
433
- cookie: {
434
- httpOnly: true,
435
- secure: true,
436
- sameSite: 'strict',
437
- maxAge: 1000 * 60 * 60 * 24 // 24 hours
438
- }
439
- }));
440
- ```
441
-
442
- ### 2. Token Refresh
443
-
444
- Access tokens expire. Implement refresh token logic:
445
-
446
- ```javascript
447
- function isTokenExpiring(token) {
448
- const decoded = jwt.decode(token);
449
- const now = Math.floor(Date.now() / 1000);
450
- return decoded.exp - now < 60; // Refresh if less than 60 seconds left
451
- }
452
-
453
- app.use(async (req, res, next) => {
454
- const token = req.cookies.access_token;
455
- const refreshToken = req.cookies.refresh_token;
456
-
457
- if (!token) return next();
458
-
459
- if (isTokenExpiring(token) && refreshToken) {
460
- try {
461
- const newTokens = await KeycloakManager.login({
462
- grant_type: 'refresh_token',
463
- refresh_token: refreshToken,
464
- client_id: process.env.KEYCLOAK_CLIENT_ID,
465
- client_secret: process.env.KEYCLOAK_CLIENT_SECRET
466
- });
467
-
468
- res.cookie('access_token', newTokens.access_token, { httpOnly: true, secure: true });
469
- res.cookie('refresh_token', newTokens.refresh_token, { httpOnly: true, secure: true });
470
- } catch (error) {
471
- res.clearCookie('access_token');
472
- res.clearCookie('refresh_token');
473
- }
474
- }
475
-
476
- next();
477
- });
478
- ```
479
-
480
- ### 3. Token Verification
481
-
482
- Always verify tokens using Keycloak's public key:
483
-
484
- ```javascript
485
- const jwksClient = require('jwks-rsa');
486
-
487
- const client = jwksClient({
488
- jwksUri: `${process.env.KEYCLOAK_URL}/auth/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/certs`
489
- });
490
-
491
- function getKey(header, callback) {
492
- client.getSigningKey(header.kid, (err, key) => {
493
- if (err) return callback(err);
494
- callback(null, key.getPublicKey());
495
- });
496
- }
497
-
498
- function verifyToken(token) {
499
- return new Promise((resolve, reject) => {
500
- jwt.verify(token, getKey, {
501
- algorithms: ['RS256'],
502
- issuer: `${process.env.KEYCLOAK_URL}/auth/realms/${process.env.KEYCLOAK_REALM}`,
503
- audience: process.env.KEYCLOAK_CLIENT_ID
504
- }, (err, decoded) => {
505
- err ? reject(err) : resolve(decoded);
506
- });
507
- });
508
- }
509
- ```
510
-
511
- ## Related Documentation
512
-
513
- - [loginPKCE() API Reference](../api/configuration.md#loginpkce)
514
- - [login() API Reference](../api/configuration.md#login)
515
- - [OAuth2 PKCE Specification](https://tools.ietf.org/html/rfc7636)
516
- - [Keycloak Authorization Code Flow](https://www.keycloak.org/docs/latest/server_admin/#_oidc)
517
-
518
- ---
519
-
520
- ## 🚀 Migration to keycloak-express-middleware (Recommended)
521
-
522
- The methods described in this guide (`generateAuthorizationUrl()`, `loginPKCE()`, `login()`) are **deprecated in v6.0.0** and will be removed in v7.0.0.
523
-
524
- ### Why Migrate?
525
-
526
- `keycloak-express-middleware` provides:
527
- - ✅ Native Express integration (sessions, cookies, redirects)
528
- - ✅ Cleaner PKCE implementation focused on user authentication
529
- - ✅ Better separation of concerns (admin API vs user auth)
530
- - ✅ Tighter integration with Express middleware patterns
531
-
532
- ### Migration Example
533
-
534
- **Old Code (keycloak-api-manager, DEPRECATED):**
535
- ```javascript
536
- const KeycloakManager = require('keycloak-api-manager');
537
-
538
- // Configure admin API
539
- await KeycloakManager.configure({
540
- baseUrl: 'https://keycloak:8443',
541
- realmName: 'master',
542
- clientId: 'admin-cli',
543
- username: 'admin',
544
- password: 'admin'
545
- });
546
-
547
- // Use OIDC methods (deprecated)
548
- const pkceFlow = KeycloakManager.generateAuthorizationUrl({
549
- redirect_uri: 'http://localhost:3000/callback'
550
- });
551
-
552
- const tokens = await KeycloakManager.loginPKCE({
553
- code: req.query.code,
554
- redirect_uri: 'http://localhost:3000/callback',
555
- code_verifier: req.session.pkce_verifier
556
- });
557
- ```
558
-
559
- **New Code (keycloak-express-middleware, RECOMMENDED):**
560
- ```javascript
561
- const KeycloakMiddleware = require('keycloak-express-middleware');
562
-
563
- // Configure middleware for user authentication
564
- const keycloakMiddleware = new KeycloakMiddleware({
565
- baseUrl: 'https://keycloak:8443',
566
- realmName: 'my-realm',
567
- clientId: 'my-app',
568
- clientSecret: 'my-app-secret'
569
- });
570
-
571
- // Use OIDC methods from middleware
572
- const pkceFlow = keycloakMiddleware.generateAuthorizationUrl({
573
- redirect_uri: 'http://localhost:3000/callback'
574
- });
575
-
576
- const tokens = await keycloakMiddleware.loginPKCE({
577
- code: req.query.code,
578
- redirect_uri: 'http://localhost:3000/callback',
579
- code_verifier: req.session.pkce_verifier
580
- });
581
- ```
582
-
583
- ### Step-by-Step Migration
584
-
585
- **1. Install keycloak-express-middleware:**
586
- ```bash
587
- npm install keycloak-express-middleware@6.1.0
588
- npm uninstall keycloak-api-manager # if no longer needed for admin operations
589
- ```
590
-
591
- **2. Initialize middleware instead of manager:**
592
- ```javascript
593
- // Replace this:
594
- // const KeycloakManager = require('keycloak-api-manager');
595
- // await KeycloakManager.configure({...});
596
-
597
- // With this:
598
- const KeycloakMiddleware = require('keycloak-express-middleware');
599
- const keycloakMiddleware = new KeycloakMiddleware({
600
- baseUrl: process.env.KEYCLOAK_URL,
601
- realmName: process.env.KEYCLOAK_REALM,
602
- clientId: process.env.KEYCLOAK_CLIENT_ID,
603
- clientSecret: process.env.KEYCLOAK_CLIENT_SECRET
604
- });
605
- ```
606
-
607
- **3. Replace method calls:**
608
- ```javascript
609
- // Old (keycloak-api-manager)
610
- const pkceFlow = KeycloakManager.generateAuthorizationUrl({...});
611
- const tokens = await KeycloakManager.loginPKCE({...});
612
- const newTokens = await KeycloakManager.login({...});
613
-
614
- // New (keycloak-express-middleware)
615
- const pkceFlow = keycloakMiddleware.generateAuthorizationUrl({...});
616
- const tokens = await keycloakMiddleware.loginPKCE({...});
617
- const newTokens = await keycloakMiddleware.login({...});
618
- ```
619
-
620
- **4. Keep using keycloak-api-manager for admin operations (unchanged):**
621
- ```javascript
622
- const KeycloakManager = require('keycloak-api-manager');
623
-
624
- await KeycloakManager.configure({
625
- baseUrl: 'https://keycloak:8443',
626
- realmName: 'master',
627
- clientId: 'admin-cli',
628
- username: 'admin',
629
- password: 'admin'
630
- });
631
-
632
- // Admin operations still work the same
633
- const users = await KeycloakManager.users.find();
634
- const realms = await KeycloakManager.realms.find();
635
- ```
636
-
637
- ### API Comparison
638
-
639
- | Operation | keycloak-api-manager (Deprecated) | keycloak-express-middleware (Recommended) |
640
- |-----------|-----------------------------------|------------------------------------------|
641
- | Generate PKCE URL | `KeycloakManager.generateAuthorizationUrl()` | `middleware.generateAuthorizationUrl()` |
642
- | Login PKCE | `KeycloakManager.loginPKCE()` | `middleware.loginPKCE()` |
643
- | Token Grant | `KeycloakManager.login()` | `middleware.login()` |
644
- | Deprecated Alias | `KeycloakManager.auth()` | *(Use login()*) |
645
-
646
- ### Additional Resources
647
-
648
- - **Middleware Documentation:** https://github.com/smartenv-crs4/keycloak-express-middleware
649
- - **Migration Guide:** https://github.com/smartenv-crs4/keycloak-api-manager/blob/main/OIDC_MIGRATION_PLAN.md
650
- - **Middleware Integration Report:** See keycloak-express-middleware/DETAILED_INTEGRATION_REPORT.md
651
-
652
- ### Deprecation Timeline
653
-
654
- | Version | Status | Notes |
655
- |---------|--------|-------|
656
- | v5.0.8 | Supported | Last version with working OIDC methods |
657
- | v6.0.0 | Deprecated | Methods work but marked @deprecated |
658
- | v7.0.0 | Removed | OIDC methods will be permanently removed |
659
-
660
- **Action Required:** Migrate to keycloak-express-middleware before v7.0.0 is released.
661
-
662
- ## Related Documentation
663
-
664
- - [loginPKCE() API Reference](../api/configuration.md#loginpkce)
665
- - [login() API Reference](../api/configuration.md#login)
666
- - [OAuth2 PKCE Specification](https://tools.ietf.org/html/rfc7636)
667
- - [Keycloak Authorization Code Flow](https://www.keycloak.org/docs/latest/server_admin/#_oidc)
20
+ - [OIDC Migration Plan](../../OIDC_MIGRATION_PLAN.md)
21
+ - [Configuration & Authentication](../api/configuration.md)