keycloak-api-manager 5.0.7 → 6.0.1

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.
@@ -0,0 +1,294 @@
1
+ # OIDC Methods Migration Plan - keycloak-api-manager
2
+
3
+ ## 🚀 Current Status: v6.0.0 - MIGRATION RELEASED
4
+
5
+ ✅ **OIDC Methods Deprecated:** All OIDC authentication methods are now marked `@deprecated` in v6.0.0.
6
+
7
+ ✅ **keycloak-express-middleware v6.1.0 Released:** OIDC methods now available in middleware package with full test coverage.
8
+
9
+ 📅 **Removal Timeline:**
10
+ - **v6.0.0** (NOW) - Methods work but marked @deprecated
11
+ - **v7.0.0** (FUTURE) - Methods will be permanently removed
12
+
13
+ ---
14
+
15
+ ## Overview
16
+
17
+ L'architettura prevede una **migrazione pianificata** dei metodi OIDC (`auth()`, `login()`, `loginPKCE()`) da `keycloak-api-manager` a `keycloak-express-middleware`.
18
+
19
+ ## Current State (v5.0.8)
20
+
21
+ **In keycloak-api-manager:**
22
+ - ✅ `auth(credentials)` - OIDC token endpoint wrapper
23
+ - ✅ `login(credentials)` - Generic token grant helper
24
+ - ✅ `generateAuthorizationUrl(options)` - PKCE URL generator
25
+ - ✅ `loginPKCE(credentials)` - PKCE token exchange
26
+
27
+ ## Current State (v6.0.0) - NOW
28
+
29
+ **Status Changes in keycloak-api-manager:**
30
+ - ⚠️ `auth(credentials)` - Marked @deprecated
31
+ - ⚠️ `login(credentials)` - Marked @deprecated
32
+ - ⚠️ `generateAuthorizationUrl(options)` - Marked @deprecated
33
+ - ⚠️ `loginPKCE(credentials)` - Marked @deprecated
34
+
35
+ ✅ Methods **still work** but show deprecation warnings in JSDoc and IDE.
36
+
37
+ **Status in keycloak-express-middleware v6.1.0:**
38
+ - ✅ `generateAuthorizationUrl(options)` - Fully implemented & tested
39
+ - ✅ `login(credentials)` - Fully implemented & tested
40
+ - ✅ `loginPKCE(credentials)` - Fully implemented & tested
41
+ - ✅ All 21 tests passing
42
+
43
+ ## Why This Migration?
44
+
45
+ ### Separation of Concerns
46
+
47
+ ```
48
+ keycloak-api-manager (Admin API Management)
49
+ ├── configure() ← Admin setup
50
+ ├── Users.find() ← Admin operations
51
+ ├── Realms.create() ← Admin operations
52
+ └── ❌ login() / auth() ← Should NOT be here!
53
+
54
+ keycloak-express-middleware (User Authentication)
55
+ ├── protectMiddleware() ← Route protection
56
+ ├── Express integration ← Session, cookies
57
+ └── ✅ generateAuthorizationUrl() ← Belongs here
58
+ └── ✅ login() ← Belongs here
59
+ └── ✅ loginPKCE() ← Belongs here
60
+ ```
61
+
62
+ ### Why Middleware is Better
63
+
64
+ 1. **Natural Context:** Express app has sessions, cookies, redirects
65
+ 2. **No Admin Context:** Users don't need admin API management
66
+ 3. **Tighter Integration:** Works with middleware ecosystem
67
+ 4. **Cleaner Namespaces:** Each package has clear responsibilities
68
+
69
+ ## Migration Timeline
70
+
71
+ ### Phase 1: ✅ DONE (Now)
72
+ - [x] Create ready-to-integrate files in middleware (`oidc-methods.js`)
73
+ - [x] Write comprehensive tests (21 tests, all passing)
74
+ - [x] Document integration guide
75
+ - [x] Commit to middleware repo
76
+ - [x] Integrate OIDC methods into keycloak-express-middleware v6.1.0
77
+ - [x] Release keycloak-express-middleware v6.1.0 to npm
78
+
79
+ **Status:** ✅ COMPLETE & RELEASED
80
+
81
+ ### Phase 2: ✅ DONE (Done)
82
+ - [x] Mark methods as @deprecated in keycloak-api-manager index.js
83
+ - [x] Update README with deprecation notices
84
+ - [x] Update API documentation with deprecation notices
85
+ - [x] Add migration guide in PKCE-Login-Flow docs
86
+ - [x] Release keycloak-api-manager v6.0.0
87
+
88
+ **Status:** ✅ COMPLETE - v6.0.0 released with @deprecated warnings
89
+
90
+ ### Phase 3: TODO (Future - v7.0.0)
91
+ - [ ] Remove OIDC methods from keycloak-api-manager
92
+ - [ ] Release keycloak-api-manager v7.0.0 (breaking change)
93
+ - [ ] Update all documentation to reference keycloak-express-middleware only
94
+
95
+ **Timeline:** TBD based on user feedback and adoption
96
+
97
+ ---
98
+
99
+ ## What You Need to Know
100
+
101
+ ### For Current Users (v5.0.8 or earlier)
102
+
103
+ **Action Required:** Migrate to keycloak-express-middleware before v7.0.0.
104
+
105
+ **Timeline:** v6.0.0 is deprecated (warnings only), v7.0.0 will remove methods entirely.
106
+
107
+ **Steps:**
108
+ 1. Install keycloak-express-middleware v6.1.0+
109
+ 2. Replace method calls (see examples below)
110
+ 3. Test thoroughly
111
+ 4. Deploy before v7.0.0 is released
112
+
113
+ ### For New Projects
114
+
115
+ **Action Required:** Do NOT use OIDC methods from keycloak-api-manager.
116
+
117
+ **Recommendation:** Use keycloak-express-middleware v6.1.0+ for all user authentication.
118
+
119
+ ---
120
+
121
+ ## NPM Packages
122
+
123
+ ### keycloak-api-manager
124
+
125
+ | Version | OIDC Methods | Status |
126
+ |---------|------------|--------|
127
+ | v5.0.8 | Supported | Legacy (should migrate) |
128
+ | v6.0.0 | Deprecated | Current (shows warnings) |
129
+ | v7.0.0 | Removed | Future (no OIDC methods) |
130
+
131
+ **NPM:** https://www.npmjs.com/package/keycloak-api-manager
132
+
133
+ ### keycloak-express-middleware
134
+
135
+ | Version | OIDC Methods | Status |
136
+ |---------|------------|--------|
137
+ | < 6.1.0 | Not available | Legacy |
138
+ | v6.1.0+ | Available | Current - RECOMMENDED |
139
+
140
+ **NPM:** https://www.npmjs.com/package/keycloak-express-middleware
141
+
142
+ **GitHub:** https://github.com/smartenv-crs4/keycloak-express-middleware
143
+
144
+ ---
145
+
146
+ ### `auth(credentials)` - Generic OIDC Token Grant (DEPRECATED)
147
+
148
+ ```javascript
149
+ // ⚠️ DEPRECATED - Don't use in new code
150
+ const token = await KeycloakManager.auth({
151
+ grant_type: 'password',
152
+ username: 'user',
153
+ password: 'pass'
154
+ });
155
+ ```
156
+
157
+ **Migration Path:**
158
+ ```javascript
159
+ // ✅ NEW - Use keycloak-express-middleware instead
160
+ const token = await keycloakMiddleware.login({
161
+ grant_type: 'password',
162
+ username: 'user',
163
+ password: 'pass'
164
+ });
165
+ ```
166
+
167
+ ---
168
+
169
+ ### `login(credentials)` - Preferred Alias (DEPRECATED)
170
+
171
+ ```javascript
172
+ // ⚠️ DEPRECATED - Don't use in new code
173
+ const token = await KeycloakManager.login({
174
+ grant_type: 'client_credentials'
175
+ });
176
+ ```
177
+
178
+ **Migration Path:**
179
+ ```javascript
180
+ // ✅ NEW - Use keycloak-express-middleware instead
181
+ const token = await keycloakMiddleware.login({
182
+ grant_type: 'client_credentials'
183
+ });
184
+ ```
185
+
186
+ ---
187
+
188
+ ### `generateAuthorizationUrl(options)` - PKCE URL Generator (DEPRECATED)
189
+
190
+ ```javascript
191
+ // ⚠️ DEPRECATED - Don't use in new code
192
+ const pkceFlow = KeycloakManager.generateAuthorizationUrl({
193
+ redirect_uri: 'https://app/callback'
194
+ });
195
+ ```
196
+
197
+ **Migration Path:**
198
+ ```javascript
199
+ // ✅ NEW - Use keycloak-express-middleware instead
200
+ const pkceFlow = keycloakMiddleware.generateAuthorizationUrl({
201
+ redirect_uri: 'https://app/callback'
202
+ });
203
+ ```
204
+
205
+ ---
206
+
207
+ ### `loginPKCE(credentials)` - PKCE Token Exchange (DEPRECATED)
208
+
209
+ ```javascript
210
+ // ⚠️ DEPRECATED - Don't use in new code
211
+ const token = await KeycloakManager.loginPKCE({
212
+ code: req.query.code,
213
+ redirect_uri: 'https://app/callback',
214
+ code_verifier: req.session.verifier
215
+ });
216
+ ```
217
+
218
+ **Migration Path:**
219
+ ```javascript
220
+ // ✅ NEW - Use keycloak-express-middleware instead
221
+ const token = await keycloakMiddleware.loginPKCE({
222
+ code: req.query.code,
223
+ redirect_uri: 'https://app/callback',
224
+ code_verifier: req.session.verifier
225
+ });
226
+ ```
227
+
228
+ **Migration Path:**
229
+ ```javascript
230
+ // Move to middleware
231
+ const token = await keycloakMiddleware.loginPKCE({
232
+ code: req.query.code,
233
+ redirect_uri: 'https://app/callback',
234
+ code_verifier: req.session.verifier
235
+ });
236
+ ```
237
+
238
+ ---
239
+
240
+ ## What Stays in keycloak-api-manager
241
+
242
+ ✅ **These remain unchanged forever:**
243
+ - `configure(credentials)` - Admin authentication
244
+ - `setConfig(overrides)` - Configuration management
245
+ - `getToken()` - Get current admin token
246
+ - `stop()` - Cleanup
247
+ - **All handlers:** `users`, `realms`, `clients`, `groups`, `roles`, etc.
248
+
249
+ The package remains the **dedicated Admin API Manager** - exactly what it should be.
250
+
251
+ ## Migration Guide for Users (TBD)
252
+
253
+ When ready, we'll publish:
254
+
255
+ ```markdown
256
+ # Migrating OIDC Methods from keycloak-api-manager to keycloak-express-middleware
257
+
258
+ ## Version Support
259
+
260
+ | Method | deprecated | removed | alternative |
261
+ |--------|-----------|---------|-------------|
262
+ | `auth()` | v6.0.0 | v7.0.0 | middleware.login() |
263
+ | `login()` | v6.0.0 | v7.0.0 | middleware.login() |
264
+ | `generateAuthorizationUrl()` | v6.0.0 | v7.0.0 | middleware.generateAuthorizationUrl() |
265
+ | `loginPKCE()` | v6.0.0 | v7.0.0 | middleware.loginPKCE() |
266
+
267
+ ## Migration Steps
268
+
269
+ 1. Install/update middleware
270
+ 2. Replace method calls
271
+ 3. Update imports
272
+ 4. Test
273
+ ```
274
+
275
+ ## Next Actions
276
+
277
+ ### You Should Do:
278
+ 1. Review `keycloak-express-middleware/OIDC_INTEGRATION_GUIDE.md`
279
+ 2. Decide if you want to integrate manually or have me automate it
280
+ 3. Once middleware is ready, let me know
281
+
282
+ ### I Will Do (When You Say):
283
+ 1. Integrate methods into middleware `index.js`
284
+ 2. Release `keycloak-express-middleware v6.1.0`
285
+ 3. Deprecate in `keycloak-api-manager v6.0.0`
286
+ 4. Create migration guide
287
+ 5. Update all documentation
288
+
289
+ ## Questions?
290
+
291
+ - How should we handle the transition period?
292
+ - Do we support both packages simultaneously?
293
+ - Timeline for full migration?
294
+ - Any concerns about the approach?
package/README.md CHANGED
@@ -25,6 +25,12 @@ It provides a stable, function-oriented interface for managing Keycloak resource
25
25
  npm install keycloak-api-manager
26
26
  ```
27
27
 
28
+ > **⚠️ DEPRECATION NOTICE (v6.0.0):** The OIDC authentication methods (`login()`, `loginPKCE()`, `generateAuthorizationUrl()`, `auth()`) have been **deprecated** and moved to [`keycloak-express-middleware`](https://github.com/smartenv-crs4/keycloak-express-middleware).
29
+ >
30
+ > **This package is now exclusively for Keycloak admin resource management.** For user authentication flows, use `keycloak-express-middleware` instead.
31
+ >
32
+ > See [OIDC_MIGRATION_PLAN.md](OIDC_MIGRATION_PLAN.md) for migration details.
33
+
28
34
  ## Quick Start
29
35
 
30
36
  ```js
@@ -48,6 +54,8 @@ console.log(users.length);
48
54
  KeycloakManager.stop();
49
55
  ```
50
56
 
57
+ > **💡 Tip:** For user authentication (login with credentials, PKCE flow, token exchange), use [`keycloak-express-middleware`](https://github.com/smartenv-crs4/keycloak-express-middleware) instead. See [PKCE Login Flow Guide](docs/guides/PKCE-Login-Flow.md#-migration-to-keycloak-express-middleware-recommended) for migration examples.
58
+
51
59
  ## Keycloak Feature Flags
52
60
 
53
61
  For full API coverage in this package (especially Organizations, Client Policies, User Profile, Group permissions), run Keycloak with:
@@ -65,16 +73,13 @@ In Keycloak 26.x, management-permissions APIs used by group/user fine-grained te
65
73
  - `configure(credentials)`
66
74
  - `setConfig(overrides)`
67
75
  - `getToken()`
68
- - `login(credentials)`
69
- - `loginPKCE(credentials)`
70
- - `auth(credentials)`
71
76
  - `stop()`
77
+ - ~~`login(credentials)`~~ **DEPRECATED** - moved to keycloak-express-middleware
78
+ - ~~`generateAuthorizationUrl(options)`~~ **DEPRECATED** - moved to keycloak-express-middleware
79
+ - ~~`loginPKCE(credentials)`~~ **DEPRECATED** - moved to keycloak-express-middleware
80
+ - ~~`auth(credentials)`~~ **DEPRECATED** - moved to keycloak-express-middleware
72
81
 
73
- `login(credentials)` is the preferred OIDC token endpoint helper for login/token grant flows (user/client).
74
-
75
- `loginPKCE(credentials)` is a specialized helper for Authorization Code + PKCE token exchange.
76
-
77
- `auth(credentials)` is kept as backward-compatible alias and does not replace the internal admin session configured by `configure()`.
82
+ **Note:** OIDC authentication methods have been deprecated in v6.0.0. Use [`keycloak-express-middleware`](https://github.com/smartenv-crs4/keycloak-express-middleware) for user authentication flows.
78
83
 
79
84
  Configured handler namespaces:
80
85
 
@@ -158,10 +163,15 @@ docs/ # Centralized documentation
158
163
 
159
164
  ## Versioning and Compatibility
160
165
 
161
- - Package version: `5.0.1`
166
+ - Package version: `6.0.0`
162
167
  - Keycloak Admin client dependency: `@keycloak/keycloak-admin-client`
163
168
  - Main compatibility target: Keycloak 25/26
164
169
 
170
+ ### Breaking Changes in v6.0.0
171
+
172
+ OIDC authentication methods (`login()`, `loginPKCE()`, `generateAuthorizationUrl()`, `auth()`) are now deprecated.
173
+ These methods will be removed in v7.0.0. Migrate to `keycloak-express-middleware` for user authentication.
174
+
165
175
  ## License
166
176
 
167
177
  MIT
@@ -8,6 +8,7 @@ Core API methods for initializing and managing the Keycloak Admin Client connect
8
8
  - [setConfig()](#setconfig)
9
9
  - [getToken()](#gettoken)
10
10
  - [login()](#login)
11
+ - [generateAuthorizationUrl()](#generateauthorizationurl)
11
12
  - [loginPKCE()](#loginpkce)
12
13
  - [auth()](#auth)
13
14
  - [stop()](#stop)
@@ -238,9 +239,15 @@ const response = await axios.get('https://keycloak.example.com/admin/realms/mast
238
239
 
239
240
  ## auth()
240
241
 
241
- Backward-compatible alias of `login()`.
242
+ ⚠️ **DEPRECATED (v6.0.0)** - Use [`keycloak-express-middleware.login()`](https://github.com/smartenv-crs4/keycloak-express-middleware) instead.
242
243
 
243
- Use `login()` in new code for clearer intent.
244
+ This method will be removed in v7.0.0. For user authentication flows, use `keycloak-express-middleware` v6.1.0+.
245
+
246
+ See: [Migration Guide](../guides/PKCE-Login-Flow.md#-migration-to-keycloak-express-middleware-recommended)
247
+
248
+ ---
249
+
250
+ **Legacy Note:** Backward-compatible alias of `login()`. Use `login()` instead (also deprecated).
244
251
 
245
252
  **Syntax:**
246
253
  ```javascript
@@ -255,6 +262,14 @@ await KeycloakManager.auth(credentials)
255
262
 
256
263
  ## login()
257
264
 
265
+ ⚠️ **DEPRECATED (v6.0.0)** - Use [`keycloak-express-middleware.login()`](https://github.com/smartenv-crs4/keycloak-express-middleware) instead.
266
+
267
+ This method will be removed in v7.0.0. For user authentication flows, use `keycloak-express-middleware` v6.1.0+.
268
+
269
+ See: [Migration Guide](../guides/PKCE-Login-Flow.md#-migration-to-keycloak-express-middleware-recommended)
270
+
271
+ ---
272
+
258
273
  Request tokens from Keycloak via the OIDC token endpoint.
259
274
 
260
275
  This method is intended for application-level login/token flows (for users, service clients, or third-party integrations) using this package as a wrapper.
@@ -348,13 +363,118 @@ console.log(refreshed.access_token);
348
363
 
349
364
  ---
350
365
 
366
+ ## generateAuthorizationUrl()
367
+
368
+ ⚠️ **DEPRECATED (v6.0.0)** - Use [`keycloak-express-middleware.generateAuthorizationUrl()`](https://github.com/smartenv-crs4/keycloak-express-middleware) instead.
369
+
370
+ This method will be removed in v7.0.0. For PKCE authentication flows, use `keycloak-express-middleware` v6.1.0+.
371
+
372
+ See: [Migration Guide](../guides/PKCE-Login-Flow.md#-migration-to-keycloak-express-middleware-recommended)
373
+
374
+ ---
375
+
376
+ Generate OAuth2 Authorization Code + PKCE flow initialization. Returns a ready-to-use authorization URL and PKCE pair for server-side session storage.
377
+
378
+ This helper simplifies the first step of PKCE login: generating the authorization URL with PKCE challenge and state parameter.
379
+
380
+ **Syntax:**
381
+ ```javascript
382
+ const pkceFlow = KeycloakManager.generateAuthorizationUrl(options)
383
+ ```
384
+
385
+ ### Parameters
386
+
387
+ #### options (Object) ⚠️ Required
388
+
389
+ | Property | Type | Required | Description |
390
+ |----------|------|----------|-------------|
391
+ | `redirect_uri` | string | ⚠️ Yes* | Redirect URI where user returns after login |
392
+ | `redirectUri` | string | ⚠️ Yes* | CamelCase alias of `redirect_uri` |
393
+ | `scope` | string | 📋 Optional | Space-separated scopes (default: `'openid profile email'`) |
394
+ | `state` | string | 📋 Optional | Custom state value (auto-generated if not provided) |
395
+
396
+ `*` required with either snake_case or camelCase form.
397
+
398
+ ### Returns
399
+
400
+ **Object** - PKCE flow initialization data:
401
+
402
+ ```javascript
403
+ {
404
+ authUrl: 'https://keycloak.example.com/realms/my-realm/protocol/openid-connect/auth?...',
405
+ state: 'random_state_string',
406
+ codeVerifier: 'random_code_verifier_string'
407
+ }
408
+ ```
409
+
410
+ - `authUrl`: Ready-to-use authorization URL to redirect user to
411
+ - `state`: CSRF token to validate in callback (store in session)
412
+ - `codeVerifier`: PKCE proof to exchange for code in callback (store in session, **never expose to client**)
413
+
414
+ ### Example
415
+
416
+ ```javascript
417
+ // Step 1: Generate authorization URL
418
+ app.get('/auth/login', (req, res) => {
419
+ const pkceFlow = KeycloakManager.generateAuthorizationUrl({
420
+ redirect_uri: `${process.env.APP_URL}/auth/callback`,
421
+ scope: 'openid profile email'
422
+ });
423
+
424
+ // Store in session server-side
425
+ req.session.pkce_state = pkceFlow.state;
426
+ req.session.pkce_verifier = pkceFlow.codeVerifier;
427
+
428
+ // Redirect user to Keycloak
429
+ res.redirect(pkceFlow.authUrl);
430
+ });
431
+
432
+ // Step 2: In callback, recover verifier and exchange code
433
+ app.get('/auth/callback', async (req, res) => {
434
+ const { code, state } = req.query;
435
+
436
+ // Validate state
437
+ if (state !== req.session.pkce_state) {
438
+ return res.status(400).send('CSRF attack detected');
439
+ }
440
+
441
+ // Exchange code for token
442
+ const tokens = await KeycloakManager.loginPKCE({
443
+ code,
444
+ redirect_uri: `${process.env.APP_URL}/auth/callback`,
445
+ code_verifier: req.session.pkce_verifier
446
+ });
447
+
448
+ // Use tokens...
449
+ });
450
+ ```
451
+
452
+ ### Notes
453
+
454
+ - `generateAuthorizationUrl()` does **not** call Keycloak; it generates URLs and PKCE values locally.
455
+ - `state` and `codeVerifier` must be stored **server-side only** in session storage, never in cookies or local storage.
456
+ - `codeVerifier` must be kept secret and never exposed to the browser.
457
+ - `state` provides CSRF protection and must be validated in the callback.
458
+ - Uses cryptographically secure random generation for `codeVerifier` and `state`.
459
+ - Code challenge is SHA256-hashed (S256 method), not plain text.
460
+
461
+ ---
462
+
351
463
  ## loginPKCE()
352
464
 
465
+ ⚠️ **DEPRECATED (v6.0.0)** - Use [`keycloak-express-middleware.loginPKCE()`](https://github.com/smartenv-crs4/keycloak-express-middleware) instead.
466
+
467
+ This method will be removed in v7.0.0. For PKCE authentication flows, use `keycloak-express-middleware` v6.1.0+.
468
+
469
+ See: [Migration Guide](../guides/PKCE-Login-Flow.md#-migration-to-keycloak-express-middleware-recommended)
470
+
471
+ ---
472
+
353
473
  Perform Authorization Code + PKCE token exchange.
354
474
 
355
475
  This helper is intended for the callback step after user login on Keycloak, where your backend receives an authorization `code` and exchanges it with `code_verifier`.
356
476
 
357
- > **📖 For a complete step-by-step guide on implementing PKCE flow in your application, see [PKCE Login Flow Guide](../guides/PKCE-Login-Flow.md)**
477
+ > **📖 For a complete step-by-step guide on implementing PKCE flow in your application, see [PKCE Login Flow Guide](../guides/PKCE-Login-Flow.md#-migration-to-keycloak-express-middleware-recommended)**
358
478
 
359
479
  **Syntax:**
360
480
  ```javascript
@@ -80,6 +80,7 @@ KeycloakManager.stop();
80
80
  | `setConfig()` | Runtime configuration | Core |
81
81
  | `getToken()` | Get current access token | Core |
82
82
  | `login()` | Preferred OIDC token grant/login endpoint wrapper | Core |
83
+ | `generateAuthorizationUrl()` | Generate PKCE authorization URL and verifier pair | Core |
83
84
  | `loginPKCE()` | Authorization Code + PKCE token exchange helper | Core |
84
85
  | `auth()` | Backward-compatible alias of `login()` | Core |
85
86
  | `stop()` | Stop token refresh timer | Core |
@@ -1,5 +1,13 @@
1
1
  # PKCE Login Flow Guide
2
2
 
3
+ ⚠️ **DEPRECATION NOTICE (v6.0.0):** This guide describes PKCE implementation using **deprecated methods** in keycloak-api-manager.
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.
6
+
7
+ **See:** Migration instructions at the end of this guide.
8
+
9
+ ---
10
+
3
11
  This guide walks you through implementing OAuth2 Authorization Code + PKCE flow in your application using Keycloak and the keycloak-api-manager library.
4
12
 
5
13
  ## Overview
@@ -72,98 +80,51 @@ PKCE (Proof Key for Code Exchange) is the modern, secure way for browser-based a
72
80
 
73
81
  ## Step-by-Step Implementation
74
82
 
75
- ### Step 1: Generate PKCE Pair
83
+ ### Step 1: Generate Authorization URL
76
84
 
77
- When the user clicks "Login", your backend generates a PKCE pair and stores it securely:
85
+ When the user clicks "Login", use `generateAuthorizationUrl()` from keycloak-api-manager to generate the PKCE pair and authorization URL:
78
86
 
79
87
  ```javascript
80
- const crypto = require('crypto');
81
-
82
- function base64url(buf) {
83
- return buf
84
- .toString('base64')
85
- .replace(/\+/g, '-')
86
- .replace(/\//g, '_')
87
- .replace(/=/g, '');
88
- }
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
+ });
89
92
 
90
- function createPkcePair() {
91
- // Generate code_verifier (random 128-char string)
92
- const code_verifier = base64url(crypto.randomBytes(96));
93
-
94
- // Generate code_challenge (SHA256 hash of verifier)
95
- const code_challenge = base64url(
96
- crypto.createHash('sha256').update(code_verifier).digest()
97
- );
98
-
99
- // Generate state (CSRF protection)
100
- const state = base64url(crypto.randomBytes(32));
101
-
102
- return { code_verifier, code_challenge, state };
103
- }
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
+ // }
104
99
  ```
105
100
 
106
- **Why this works:**
107
- - `code_verifier`: A random, unguessable string
108
- - `code_challenge`: The SHA256 hash of the verifier, sent to Keycloak during login
109
- - `state`: A random token to prevent CSRF attacks; Keycloak will return it unchanged
110
-
111
- ### Step 2: Redirect to Keycloak Authorization Endpoint
112
-
113
- Store the PKCE pair in the session, then redirect the user to Keycloak:
101
+ Store the `state` and `codeVerifier` in your session, then redirect the user to the authorization URL:
114
102
 
115
103
  ```javascript
116
- const express = require('express');
117
- const session = require('express-session');
118
- const KeycloakManager = require('keycloak-api-manager');
119
-
120
- const app = express();
121
-
122
- // Session configuration (store verifier securely server-side)
123
- app.use(session({
124
- secret: 'your-secret-key',
125
- resave: false,
126
- saveUninitialized: true,
127
- cookie: { httpOnly: true, secure: true } // secure: true in production (HTTPS only)
128
- }));
129
-
130
- // 1. User clicks "Login" button
131
104
  app.get('/auth/login', (req, res) => {
132
- const { code_verifier, code_challenge, state } = createPkcePair();
133
-
134
- // Store verifier and state in session (server-side only!)
135
- req.session.pkce_verifier = code_verifier;
136
- req.session.pkce_state = state;
137
-
138
- // Build Keycloak authorization URL
139
- const keycloakAuthUrl = `${process.env.KEYCLOAK_URL}/auth/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/auth`;
140
- const authUrl = new URL(keycloakAuthUrl);
105
+ const pkceFlow = KeycloakManager.generateAuthorizationUrl({
106
+ redirect_uri: `${process.env.APP_URL}/auth/callback`
107
+ });
141
108
 
142
- authUrl.searchParams.append('client_id', process.env.KEYCLOAK_CLIENT_ID);
143
- authUrl.searchParams.append('redirect_uri', `${process.env.APP_URL}/auth/callback`);
144
- authUrl.searchParams.append('response_type', 'code');
145
- authUrl.searchParams.append('scope', 'openid profile email');
146
- authUrl.searchParams.append('code_challenge', code_challenge);
147
- authUrl.searchParams.append('code_challenge_method', 'S256'); // S256 = SHA256
148
- authUrl.searchParams.append('state', state);
109
+ // Store state and verifier in session for callback validation
110
+ req.session.pkce_state = pkceFlow.state;
111
+ req.session.pkce_verifier = pkceFlow.codeVerifier;
149
112
 
150
- // Redirect user to Keycloak login page
151
- res.redirect(authUrl.toString());
113
+ // Redirect user to Keycloak login
114
+ res.redirect(pkceFlow.authUrl);
152
115
  });
153
116
  ```
154
117
 
155
- **What happens:**
156
- - User is redirected to Keycloak
157
- - They see the login page
158
- - They enter their username/password
159
- - On successful auth, Keycloak redirects back to your `/auth/callback` endpoint with `code` and `state`
160
-
161
- ### Step 3: Exchange Authorization Code for Token
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)
162
123
 
163
- When Keycloak redirects back with the authorization code, you exchange it for an access token:
124
+ When Keycloak redirects back with the authorization code, you exchange it for an access token using `loginPKCE()`:
164
125
 
165
126
  ```javascript
166
- // 2. Keycloak redirects back with authorization code
127
+ // User callback after Keycloak login
167
128
  app.get('/auth/callback', async (req, res) => {
168
129
  try {
169
130
  const { code, state, error } = req.query;
@@ -180,18 +141,15 @@ app.get('/auth/callback', async (req, res) => {
180
141
 
181
142
  // 3. Retrieve stored verifier from session
182
143
  const code_verifier = req.session.pkce_verifier;
183
-
184
144
  if (!code_verifier) {
185
145
  return res.status(400).send('PKCE verifier not found in session');
186
146
  }
187
147
 
188
- // 4. Exchange code for token using loginPKCE()
148
+ // 4. Exchange code for token using keycloak-api-manager
189
149
  const tokenResponse = await KeycloakManager.loginPKCE({
190
150
  code,
191
151
  redirect_uri: `${process.env.APP_URL}/auth/callback`,
192
- code_verifier,
193
- client_id: process.env.KEYCLOAK_CLIENT_ID,
194
- client_secret: process.env.KEYCLOAK_CLIENT_SECRET
152
+ code_verifier
195
153
  });
196
154
 
197
155
  // 5. Set secure HTTPOnly cookie with access token
@@ -232,35 +190,6 @@ app.get('/auth/callback', async (req, res) => {
232
190
  - ✅ Store token in HttpOnly cookie (prevents XSS theft)
233
191
  - ✅ Clear sensitive session data
234
192
 
235
- ### Step 4: Use the Access Token
236
-
237
- Now the user has an access token in a secure cookie. Use it to access protected resources:
238
-
239
- ```javascript
240
- // Middleware to verify access token
241
- app.use((req, res, next) => {
242
- const token = req.cookies.access_token;
243
-
244
- if (!token) {
245
- return res.status(401).send('Not authenticated');
246
- }
247
-
248
- // Verify and decode the token
249
- try {
250
- const decoded = jwt.verify(token, process.env.JWT_PUBLIC_KEY);
251
- req.user = decoded; // User data available in request
252
- next();
253
- } catch (error) {
254
- return res.status(401).send('Invalid token');
255
- }
256
- });
257
-
258
- // Protected route
259
- app.get('/dashboard', (req, res) => {
260
- res.send(`Welcome, ${req.user.preferred_username}!`);
261
- });
262
- ```
263
-
264
193
  ## Complete Working Example
265
194
 
266
195
  Here's a complete Express.js application with PKCE flow:
@@ -268,7 +197,6 @@ Here's a complete Express.js application with PKCE flow:
268
197
  ```javascript
269
198
  const express = require('express');
270
199
  const session = require('express-session');
271
- const crypto = require('crypto');
272
200
  const jwt = require('jsonwebtoken');
273
201
  const cookieParser = require('cookie-parser');
274
202
  const KeycloakManager = require('keycloak-api-manager');
@@ -287,55 +215,34 @@ app.use(session({
287
215
 
288
216
  // Initialize Keycloak Manager
289
217
  KeycloakManager.configure({
218
+ baseUrl: process.env.KEYCLOAK_URL,
290
219
  realmName: process.env.KEYCLOAK_REALM,
291
220
  clientId: process.env.KEYCLOAK_CLIENT_ID,
292
221
  clientSecret: process.env.KEYCLOAK_CLIENT_SECRET,
293
- keycloakUrl: process.env.KEYCLOAK_URL
222
+ grantType: 'client_credentials'
294
223
  });
295
224
 
296
- // Helper functions
297
- function base64url(buf) {
298
- return buf
299
- .toString('base64')
300
- .replace(/\+/g, '-')
301
- .replace(/\//g, '_')
302
- .replace(/=/g, '');
303
- }
304
-
305
- function createPkcePair() {
306
- const code_verifier = base64url(crypto.randomBytes(96));
307
- const code_challenge = base64url(
308
- crypto.createHash('sha256').update(code_verifier).digest()
309
- );
310
- const state = base64url(crypto.randomBytes(32));
311
- return { code_verifier, code_challenge, state };
312
- }
313
-
314
225
  // Routes
315
226
  app.get('/auth/login', (req, res) => {
316
- const { code_verifier, code_challenge, state } = createPkcePair();
317
-
318
- req.session.pkce_verifier = code_verifier;
319
- req.session.pkce_state = state;
320
-
321
- const keycloakAuthUrl = `${process.env.KEYCLOAK_URL}/auth/realms/${process.env.KEYCLOAK_REALM}/protocol/openid-connect/auth`;
322
- const authUrl = new URL(keycloakAuthUrl);
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
+ });
323
232
 
324
- authUrl.searchParams.append('client_id', process.env.KEYCLOAK_CLIENT_ID);
325
- authUrl.searchParams.append('redirect_uri', `${process.env.APP_URL}/auth/callback`);
326
- authUrl.searchParams.append('response_type', 'code');
327
- authUrl.searchParams.append('scope', 'openid profile email');
328
- authUrl.searchParams.append('code_challenge', code_challenge);
329
- authUrl.searchParams.append('code_challenge_method', 'S256');
330
- authUrl.searchParams.append('state', state);
233
+ // Store state and verifier in session (server-side only!)
234
+ req.session.pkce_state = pkceFlow.state;
235
+ req.session.pkce_verifier = pkceFlow.codeVerifier;
331
236
 
332
- res.redirect(authUrl.toString());
237
+ // Redirect user to Keycloak login
238
+ res.redirect(pkceFlow.authUrl);
333
239
  });
334
240
 
335
241
  app.get('/auth/callback', async (req, res) => {
336
242
  try {
337
243
  const { code, state, error } = req.query;
338
244
 
245
+ // Validate state (CSRF protection)
339
246
  if (state !== req.session.pkce_state) {
340
247
  return res.status(400).send('Invalid state parameter');
341
248
  }
@@ -349,13 +256,11 @@ app.get('/auth/callback', async (req, res) => {
349
256
  return res.status(400).send('PKCE verifier not found');
350
257
  }
351
258
 
352
- // Exchange code for token
259
+ // Exchange code for token (client_id + client_secret from configure())
353
260
  const tokenResponse = await KeycloakManager.loginPKCE({
354
261
  code,
355
262
  redirect_uri: `${process.env.APP_URL}/auth/callback`,
356
- code_verifier,
357
- client_id: process.env.KEYCLOAK_CLIENT_ID,
358
- client_secret: process.env.KEYCLOAK_CLIENT_SECRET
263
+ code_verifier
359
264
  });
360
265
 
361
266
  // Set secure cookies
@@ -373,6 +278,7 @@ app.get('/auth/callback', async (req, res) => {
373
278
  maxAge: 7 * 24 * 60 * 60 * 1000
374
279
  });
375
280
 
281
+ // Clear sensitive data
376
282
  delete req.session.pkce_verifier;
377
283
  delete req.session.pkce_state;
378
284
 
@@ -608,3 +514,154 @@ function verifyToken(token) {
608
514
  - [login() API Reference](../api/configuration.md#login)
609
515
  - [OAuth2 PKCE Specification](https://tools.ietf.org/html/rfc7636)
610
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)
package/index.js CHANGED
@@ -177,14 +177,50 @@ async function requestOidcToken(credentials = {}) {
177
177
  return payload;
178
178
  }
179
179
 
180
+ /**
181
+ * @deprecated v6.0.0 - This method has been moved to keycloak-express-middleware.
182
+ * Use the middleware package for user authentication instead. See:
183
+ * https://github.com/smartenv-crs4/keycloak-express-middleware#oidc-authentication
184
+ *
185
+ * This API manager is intended for Keycloak admin resource management only.
186
+ * For user authentication flows, import from keycloak-express-middleware.
187
+ *
188
+ * @see {@link https://github.com/smartenv-crs4/keycloak-express-middleware|keycloak-express-middleware}
189
+ * @param {object} credentials - OIDC token request credentials
190
+ * @returns {Promise<object>} Token response containing access_token, refresh_token, etc.
191
+ */
180
192
  exports.auth = async function auth(credentials = {}) {
181
193
  return requestOidcToken(credentials);
182
194
  };
183
195
 
196
+ /**
197
+ * @deprecated v6.0.0 - This method has been moved to keycloak-express-middleware.
198
+ * Use the middleware package for user authentication instead. See:
199
+ * https://github.com/smartenv-crs4/keycloak-express-middleware#oidc-authentication
200
+ *
201
+ * This API manager is intended for Keycloak admin resource management only.
202
+ * For user authentication flows, import from keycloak-express-middleware.
203
+ *
204
+ * @see {@link https://github.com/smartenv-crs4/keycloak-express-middleware|keycloak-express-middleware}
205
+ * @param {object} credentials - OIDC token request credentials (supports any OAuth2 grant type)
206
+ * @returns {Promise<object>} Token response containing access_token, refresh_token, etc.
207
+ */
184
208
  exports.login = async function login(credentials = {}) {
185
209
  return requestOidcToken(credentials);
186
210
  };
187
211
 
212
+ /**
213
+ * @deprecated v6.0.0 - This method has been moved to keycloak-express-middleware.
214
+ * Use the middleware package for user authentication instead. See:
215
+ * https://github.com/smartenv-crs4/keycloak-express-middleware#oidc-pkce-flow
216
+ *
217
+ * This API manager is intended for Keycloak admin resource management only.
218
+ * For user authentication flows, import from keycloak-express-middleware.
219
+ *
220
+ * @see {@link https://github.com/smartenv-crs4/keycloak-express-middleware|keycloak-express-middleware}
221
+ * @param {object} credentials - PKCE authorization code exchange parameters
222
+ * @returns {Promise<object>} Token response containing access_token, refresh_token, etc.
223
+ */
188
224
  exports.loginPKCE = async function loginPKCE(credentials = {}) {
189
225
  const {
190
226
  code,
@@ -225,3 +261,75 @@ exports.loginPKCE = async function loginPKCE(credentials = {}) {
225
261
  ...rest
226
262
  });
227
263
  };
264
+
265
+ /**
266
+ * @deprecated v6.0.0 - This method has been moved to keycloak-express-middleware.
267
+ * Use the middleware package for user authentication instead. See:
268
+ * https://github.com/smartenv-crs4/keycloak-express-middleware#generating-authorization-urls
269
+ *
270
+ * This API manager is intended for Keycloak admin resource management only.
271
+ * For user authentication flows, import from keycloak-express-middleware.
272
+ *
273
+ * @see {@link https://github.com/smartenv-crs4/keycloak-express-middleware|keycloak-express-middleware}
274
+ * @param {object} options - Authorization URL generation options
275
+ * @returns {object} Object with { authUrl, state, codeVerifier } for PKCE flow
276
+ */
277
+ exports.generateAuthorizationUrl = function generateAuthorizationUrl(options = {}) {
278
+ assertConfigured();
279
+
280
+ const {
281
+ redirect_uri,
282
+ redirectUri,
283
+ scope,
284
+ state: customState
285
+ } = options;
286
+
287
+ const resolvedRedirectUri = redirect_uri || redirectUri;
288
+ if (!resolvedRedirectUri) {
289
+ throw new Error('generateAuthorizationUrl requires "redirect_uri" (or "redirectUri").');
290
+ }
291
+
292
+ const crypto = require('crypto');
293
+
294
+ // Helper to encode bytes to base64url
295
+ function base64url(buffer) {
296
+ return buffer
297
+ .toString('base64')
298
+ .replace(/\+/g, '-')
299
+ .replace(/\//g, '_')
300
+ .replace(/=/g, '');
301
+ }
302
+
303
+ // Generate PKCE pair
304
+ const codeVerifier = base64url(crypto.randomBytes(96));
305
+ const codeChallenge = base64url(
306
+ crypto.createHash('sha256').update(codeVerifier).digest()
307
+ );
308
+
309
+ // Generate or use provided state
310
+ const state = customState || base64url(crypto.randomBytes(32));
311
+
312
+ // Build authorization URL
313
+ const authUrl = new URL(
314
+ `${runtimeConfig.baseUrl}/realms/${runtimeConfig.realmName}/protocol/openid-connect/auth`
315
+ );
316
+
317
+ authUrl.searchParams.append('client_id', runtimeConfig.clientId);
318
+ authUrl.searchParams.append('response_type', 'code');
319
+ authUrl.searchParams.append('redirect_uri', resolvedRedirectUri);
320
+ authUrl.searchParams.append('code_challenge', codeChallenge);
321
+ authUrl.searchParams.append('code_challenge_method', 'S256');
322
+ authUrl.searchParams.append('state', state);
323
+
324
+ if (scope) {
325
+ authUrl.searchParams.append('scope', scope);
326
+ } else {
327
+ authUrl.searchParams.append('scope', 'openid profile email');
328
+ }
329
+
330
+ return {
331
+ authUrl: authUrl.toString(),
332
+ state,
333
+ codeVerifier
334
+ };
335
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keycloak-api-manager",
3
- "version": "5.0.7",
3
+ "version": "6.0.1",
4
4
  "description": "Enhanced Node.js wrapper for Keycloak Admin REST API. Professional alternative to @keycloak/keycloak-admin-client with advanced features, bug fixes, automatic token refresh, Organizations API support, fine-grained permissions, and comprehensive resource management. Battle-tested with 113+ integration tests.",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/test-output.log DELETED
@@ -1,72 +0,0 @@
1
-
2
- > keycloak-api-manager@4.1.0 test
3
- > npm --prefix test install && npm --prefix test test
4
-
5
-
6
- up to date, audited 260 packages in 2s
7
-
8
- 48 packages are looking for funding
9
- run `npm fund` for details
10
-
11
- 12 vulnerabilities (3 low, 3 moderate, 4 high, 2 critical)
12
-
13
- To address all issues possible (including breaking changes), run:
14
- npm audit fix --force
15
-
16
- Some issues need review, and may require choosing
17
- a different dependency.
18
-
19
- Run `npm audit` for details.
20
-
21
- > keycloak-api-manager-tests@1.0.0 test
22
- > NODE_ENV=test NODE_PATH=./node_modules mocha --exit
23
-
24
-
25
- Exception during run: /Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/Handlers/userProfileHandler.js:79
26
- body: JSON.strasync function(filter) {
27
- ^^^^^^^^
28
-
29
- SyntaxError: Unexpected token 'function'
30
- at wrapSafe (node:internal/modules/cjs/loader:1515:18)
31
- at Module._compile (node:internal/modules/cjs/loader:1537:20)
32
- at Object..js (node:internal/modules/cjs/loader:1708:10)
33
- at Module.load (node:internal/modules/cjs/loader:1318:32)
34
- at Function._load (node:internal/modules/cjs/loader:1128:12)
35
- at TracingChannel.traceSync (node:diagnostics_channel:322:14)
36
- at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
37
- at Module.require (node:internal/modules/cjs/loader:1340:12)
38
- at require (node:internal/modules/helpers:138:16)
39
- at Object.<anonymous> (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/index.js:15:24)
40
- at Module._compile (node:internal/modules/cjs/loader:1565:14)
41
- at Object..js (node:internal/modules/cjs/loader:1708:10)
42
- at Module.load (node:internal/modules/cjs/loader:1318:32)
43
- at Function._load (node:internal/modules/cjs/loader:1128:12)
44
- at TracingChannel.traceSync (node:diagnostics_channel:322:14)
45
- at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
46
- at Module.require (node:internal/modules/cjs/loader:1340:12)
47
- at require (node:internal/modules/helpers:138:16)
48
- at Object.<anonymous> (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/enableServerFeatures.js:47:25)
49
- at Module._compile (node:internal/modules/cjs/loader:1565:14)
50
- at Object..js (node:internal/modules/cjs/loader:1708:10)
51
- at Module.load (node:internal/modules/cjs/loader:1318:32)
52
- at Function._load (node:internal/modules/cjs/loader:1128:12)
53
- at TracingChannel.traceSync (node:diagnostics_channel:322:14)
54
- at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
55
- at Module.require (node:internal/modules/cjs/loader:1340:12)
56
- at require (node:internal/modules/helpers:138:16)
57
- at Object.<anonymous> (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/setup.js:29:30)
58
- at Module._compile (node:internal/modules/cjs/loader:1565:14)
59
- at Object..js (node:internal/modules/cjs/loader:1708:10)
60
- at Module.load (node:internal/modules/cjs/loader:1318:32)
61
- at Function._load (node:internal/modules/cjs/loader:1128:12)
62
- at TracingChannel.traceSync (node:diagnostics_channel:322:14)
63
- at wrapModuleLoad (node:internal/modules/cjs/loader:219:24)
64
- at cjsLoader (node:internal/modules/esm/translators:263:5)
65
- at ModuleWrap.<anonymous> (node:internal/modules/esm/translators:196:7)
66
- at ModuleJob.run (node:internal/modules/esm/module_job:271:25)
67
- at async onImport.tracePromise.__proto__ (node:internal/modules/esm/loader:547:26)
68
- at async formattedImport (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/node_modules/mocha/lib/nodejs/esm-utils.js:9:14)
69
- at async exports.requireOrImport (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/node_modules/mocha/lib/nodejs/esm-utils.js:42:28)
70
- at async exports.loadFilesAsync (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/node_modules/mocha/lib/nodejs/esm-utils.js:100:20)
71
- at async singleRun (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/node_modules/mocha/lib/cli/run-helpers.js:162:3)
72
- at async exports.handler (/Users/Alessandro/Src/WorkSpace/WorkspaceDemo/Idealia/Keyclock/keycloak-api-manager/test/node_modules/mocha/lib/cli/run.js:375:5)