keycloak-express-middleware 3.0.8 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +143 -3
- package/index.js +1215 -1205
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,112 @@ it is based on **'keycloak-connect'**, and **'express-session'**
|
|
|
13
13
|
- ⚙️ Configurable Keycloak client and realm settings
|
|
14
14
|
- 👤 User info extraction from token
|
|
15
15
|
- 🌍 CORS support and integration with frontend apps (SPA or mobile)
|
|
16
|
+
---
|
|
17
|
+
## ⚠️ keycloak-express-middleware evolution by Version 4.0.0
|
|
18
|
+
The new version of keycloak-express-middleware introduces a substantial evolution in its architecture.
|
|
19
|
+
It now embraces an object-oriented paradigm, which means each instance of the middleware is self-contained and independent.
|
|
20
|
+
Concretely, you can instantiate the library multiple times within the same application—each time pointing to a different client in Keycloak
|
|
21
|
+
and the instances will not share internal connections or state across modules.
|
|
22
|
+
This is a major shift from the previous version(until 3.0.9), where the library maintained a single shared
|
|
23
|
+
connection and did not support using distinct Keycloak clients simultaneously within the same
|
|
24
|
+
application scope. By moving to this new ***one instance = one client*** model, you gain the flexibility to support scenarios such as:
|
|
25
|
+
- a single Express application acting as multiple Keycloak clients, each with different realms, client-ids or roles,
|
|
26
|
+
- isolating middleware logic per client without risking cross-contamination of sessions or grants,
|
|
27
|
+
- simplifying multitenancy or micro-service architectures where different parts of an app authenticate against different Keycloak clients.
|
|
28
|
+
|
|
29
|
+
**To summarize:** the new version enables multi-client usage within the same app by turning the middleware into configurable,
|
|
30
|
+
independent object instances — something that the earlier version did not support.
|
|
31
|
+
|
|
32
|
+
### 🏗️ Migration Guide: From Old to New Version
|
|
33
|
+
|
|
34
|
+
🧩 Old Version (pre–object-oriented)
|
|
35
|
+
```js
|
|
36
|
+
// OLD VERSION UNTILL 3.0.9
|
|
37
|
+
const express = require('express');
|
|
38
|
+
const keycloackAdapter = require('keycloak-express-middleware');
|
|
39
|
+
|
|
40
|
+
const app = express();
|
|
41
|
+
await keycloackAdapter.configure(app,{
|
|
42
|
+
"realm": "Realm-Project",
|
|
43
|
+
"auth-server-url": "https://YourKeycloakUrl:30040/",
|
|
44
|
+
"ssl-required": "external",
|
|
45
|
+
"resource": "keycloackclientName",
|
|
46
|
+
"credentials": {
|
|
47
|
+
"secret": "aaaaaaaaaa"
|
|
48
|
+
},
|
|
49
|
+
"confidential-port": 0
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
session:{
|
|
53
|
+
secret: 'mySecretForSession',
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Example of protection with keycloackAdapter.protectMiddleware middleware
|
|
58
|
+
// whith a static client role validation string
|
|
59
|
+
// Access is allowed only for authenticated admin users
|
|
60
|
+
app.get('/privateStaticClientRole', keycloackAdapter.protectMiddleware("admin"), (req, res) => {
|
|
61
|
+
// "Your Custom Code"
|
|
62
|
+
res.send("Is its admin.");
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
🆕 New Version (Object-Oriented Design) Up to 4.0.0
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
// NEW VERSION UP TO 4.0.0
|
|
70
|
+
const express = require('express');
|
|
71
|
+
const { keycloackAdapter } = require('keycloak-express-middleware');
|
|
72
|
+
|
|
73
|
+
const app = express();
|
|
74
|
+
|
|
75
|
+
// Create independent Keycloak clients
|
|
76
|
+
const keycloakA = new keycloackAdapter(app,{
|
|
77
|
+
"realm": "Realm-Project",
|
|
78
|
+
"auth-server-url": "https://YourKeycloakUrl:30040/",
|
|
79
|
+
"ssl-required": "external",
|
|
80
|
+
"resource": "keycloackclientName_A",
|
|
81
|
+
"credentials": {
|
|
82
|
+
"secret": "aaaaaaaaaa"
|
|
83
|
+
},
|
|
84
|
+
"confidential-port": 0
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
session:{
|
|
88
|
+
secret: 'mySecretForSession',
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const keycloakB = new keycloackAdapter(app,{
|
|
93
|
+
"realm": "Realm-Project",
|
|
94
|
+
"auth-server-url": "https://YourKeycloakUrl:30040/",
|
|
95
|
+
"ssl-required": "external",
|
|
96
|
+
"resource": "keycloackclientName_B",
|
|
97
|
+
"credentials": {
|
|
98
|
+
"secret": "aaaaaaaaaa"
|
|
99
|
+
},
|
|
100
|
+
"confidential-port": 0
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
session:{
|
|
104
|
+
secret: 'mySecretForSession',
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
// Example protected routes
|
|
111
|
+
app.get('/clientA/secure', keycloakA.protect(), (req, res) => {
|
|
112
|
+
res.send('Protected route for Client A');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
app.get('/clientB/secure', keycloakB.protect(), (req, res) => {
|
|
116
|
+
res.send('Protected route for Client B');
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
app.listen(3000, () => console.log('Server running on port 3000'));
|
|
120
|
+
```
|
|
121
|
+
|
|
16
122
|
---
|
|
17
123
|
## 🚀 Installation
|
|
18
124
|
```bash
|
|
@@ -42,11 +148,35 @@ the Keycloak Admin Console → clients (left sidebar) → choose your client →
|
|
|
42
148
|
## 📄 Usage Example
|
|
43
149
|
```js
|
|
44
150
|
const express = require('express');
|
|
45
|
-
const
|
|
151
|
+
const keycloackAdapterClass = require('keycloak-express-middleware'); // import keycloackAdapter from 'keycloak-express-middleware';
|
|
152
|
+
|
|
153
|
+
/*
|
|
154
|
+
Old Style until version 3.0.9
|
|
155
|
+
const keycloackAdapter = require('keycloak-express-middleware'); // import keycloackAdapter from 'keycloak-express-middleware';
|
|
156
|
+
*/
|
|
46
157
|
|
|
47
158
|
const app = express();
|
|
48
159
|
|
|
49
160
|
|
|
161
|
+
// Configure and Initialize Keycloak adapter
|
|
162
|
+
keycloackAdapter= new keycloackAdapterClass(app,{
|
|
163
|
+
"realm": "Realm-Project",
|
|
164
|
+
"auth-server-url": "https://YourKeycloakUrl:30040/",
|
|
165
|
+
"ssl-required": "external",
|
|
166
|
+
"resource": "keycloackclientName",
|
|
167
|
+
"credentials": {
|
|
168
|
+
"secret": "aaaaaaaaaa"
|
|
169
|
+
},
|
|
170
|
+
"confidential-port": 0
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
session:{
|
|
174
|
+
secret: 'mySecretForSession',
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
/*
|
|
179
|
+
OLD STYLE UNTIL VERSION 3.0.9
|
|
50
180
|
// Configure and Initialize Keycloak adapter
|
|
51
181
|
await keycloackAdapter.configure(app,{
|
|
52
182
|
"realm": "Realm-Project",
|
|
@@ -63,6 +193,8 @@ await keycloackAdapter.configure(app,{
|
|
|
63
193
|
secret: 'mySecretForSession',
|
|
64
194
|
}
|
|
65
195
|
});
|
|
196
|
+
*/
|
|
197
|
+
|
|
66
198
|
|
|
67
199
|
|
|
68
200
|
// -------------- Public route -----------------------
|
|
@@ -275,7 +407,9 @@ It is an async function and returns a promise
|
|
|
275
407
|
|
|
276
408
|
**` -- @parameters -- `**
|
|
277
409
|
- **app**: `[required]` Express application instance (e.g., const app = express();)
|
|
278
|
-
- **keyCloakConfig:** `[required]`JSON object containing the Keycloak client configuration. This can be obtained from the Keycloak admin console: Clients → [client name] → Installation → "Keycloak OIDC JSON" → Download
|
|
410
|
+
- **keyCloakConfig:** `[required]`JSON object containing the Keycloak client configuration. This can be obtained from the Keycloak admin console: Clients → [client name] → Installation → "Keycloak OIDC JSON" → Download. It accepts other parameter not defined in downloaded config like:
|
|
411
|
+
- "verifyTokenAudience": If verify-token-audience = true, the adapter rejects the token if its audience does not match the client that receives it.
|
|
412
|
+
- "bearerOnly": for public client. if it is set to true the client cannot call login services
|
|
279
413
|
Example:
|
|
280
414
|
```json
|
|
281
415
|
|
|
@@ -439,7 +573,9 @@ protected by flexible policies.
|
|
|
439
573
|
|
|
440
574
|
**` -- @parameters -- `**
|
|
441
575
|
- **conditions:** a check control string or function
|
|
442
|
-
- ***As a string:*** contain the name of the resource or permission to check
|
|
576
|
+
- ***As a string or array of strings:*** contain the name of the resource or permission to check. String Examples:
|
|
577
|
+
- ui-admin-resource: Apply the policies associated to the `ui-admin-resource` resource
|
|
578
|
+
- ui-admin-resource:write: Apply the policies associateo to `ui-admin-resource`resource and `write` scope
|
|
443
579
|
- ***as a function:*** custom check function with signature:
|
|
444
580
|
***`function(token, req, callback)`***
|
|
445
581
|
- token: decoded Keycloak token
|
|
@@ -484,6 +620,10 @@ app.get('/onlyAdminroute', keycloakAdapter.enforcerMiddleware('ui-admin-resource
|
|
|
484
620
|
res.send('You are an authorized admin for this resource');
|
|
485
621
|
});
|
|
486
622
|
|
|
623
|
+
app.get('/onlyAdminrouteByScope', keycloakAdapter.enforcerMiddleware('ui-admin-resource:write'), (req, res) => {
|
|
624
|
+
res.send('You are an authorized admin for this resource');
|
|
625
|
+
});
|
|
626
|
+
|
|
487
627
|
// Check with custom function (async with callback)
|
|
488
628
|
app.get('/onlyAdminrouteByfunction', keycloakAdapter.enforcerMiddleware(function(token, req, callback) {
|
|
489
629
|
token.hasPermission('ui-admin-resource', function(permission) {
|