keycloak-express-middleware 4.5.1 β†’ 6.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.
Files changed (3) hide show
  1. package/README.md +98 -14
  2. package/index.js +1 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -378,6 +378,93 @@ app.listen(PORT, () => {
378
378
  console.log(`Server running at http://localhost:${PORT}`);
379
379
  });
380
380
  ```
381
+ ---
382
+
383
+ ## Handling Unauthorized Access (401/403) Gracefully
384
+
385
+ When a user tries to access a protected resource without the proper roles, the `keycloak-express-middleware` may respond with a plain `401` or `403` message containing `access_denied`.
386
+ While technically correct, this behavior results in a **blank browser page** showing only that message.
387
+ To improve user experience, you can easily intercept these responses and display a custom HTML page or redirect users
388
+ elsewhere using the [`responseinterceptor`](https://www.npmjs.com/package/responseinterceptor) middleware.
389
+ This allows developers to present a more user-friendly "Access Denied" page or redirect unauthorized users to
390
+ a login or error page.
391
+
392
+ > πŸ›ˆ Note: In a secure application, users should normally not reach protected routes without authentication.
393
+ > However, for simplicity or flexibility during development, this interception approach can be convenient.
394
+
395
+ ### Example 1 β€” Custom Access Denied Page
396
+
397
+ ```js
398
+ import responseinterceptor from 'responseinterceptor';
399
+ import keycloakMiddleware from 'keycloak-express-middleware';
400
+
401
+ function tmpInterceptor(req, respond) {
402
+ respond(200, '<h1>Access Denied</h1><p>You are not authorized to view this page.</p>');
403
+ }
404
+
405
+ app.get(
406
+ '/test403',
407
+ responseinterceptor.interceptByStatusCode(403, tmpInterceptor),
408
+ keycloakMiddleware.protectMiddleware('role'),
409
+ (req, res) => {
410
+ res.render('welcome');
411
+ }
412
+ );
413
+ ```
414
+
415
+ ### Example 2 β€” Redirect to a Dedicated Page (Dynamic Redirect)
416
+
417
+ ```js
418
+ function tmpInterceptorDinamic(req, respond) {
419
+ //your log
420
+ switch (req.path) {
421
+ case '/':
422
+ respond('/access-denied');
423
+ break
424
+ case '/help':
425
+ respond('/access-denied-help');
426
+ break
427
+ default:
428
+ respond('/access-denied-default');
429
+ }
430
+ }
431
+
432
+ app.get('/access-denied', (req, res) => {
433
+ res.render('access-denied');
434
+ });
435
+
436
+ app.get(
437
+ '/test403redirectDynamic',
438
+ responseinterceptor.interceptByStatusCodeRedirectTo(403, tmpInterceptorDinamic),
439
+ keycloakMiddleware.protectMiddleware('none'),
440
+ (req, res) => {
441
+ res.render('welcome');
442
+ }
443
+ );
444
+ ```
445
+
446
+ ### Example 3 β€” Static Redirect to a Route
447
+
448
+ ```js
449
+ app.get(
450
+ '/test403redirectStatic',
451
+ responseinterceptor.interceptByStatusCodeRedirectTo(403, '/access-denied'),
452
+ keycloakMiddleware.protectMiddleware('none'),
453
+ (req, res) => {
454
+ res.render('welcome');
455
+ }
456
+ );
457
+ ```
458
+
459
+ ### Summary
460
+
461
+ | Scenario | Middleware Used | Action |
462
+ |-----------|------------------|---------|
463
+ | Replace response content | `interceptByStatusCode()` | Renders a custom message or template |
464
+ | Redirect dynamically | `interceptByStatusCodeRedirectTo()` + callback | Redirects to a route computed in code |
465
+ | Redirect statically | `interceptByStatusCodeRedirectTo()` + string | Redirects to a predefined route |
466
+
467
+
381
468
  ---
382
469
  ## 🧩 Configuration
383
470
  In your Express application:
@@ -918,15 +1005,13 @@ app.get('/logout', (req, res) => {
918
1005
 
919
1006
  ---
920
1007
 
921
- ### `redirectToUserAccountConsole(req, res)`
1008
+ ### `redirectToUserAccountConsole(res)`
922
1009
  `redirectToUserAccountConsole` Function is not a middleware, but a **classic synchronous function** that redirect
923
1010
  the users to keycloak Admin console where they can view and manage their personal profile and account settings.
924
1011
 
925
-
926
1012
  **` -- @parameters -- `**
927
- - **req:** `[required]` Express `Request` object
928
1013
  - **res:** `[required]` Express `Response` object
929
- - **redirectTo:** `[required]` URL to redirect the user to after successful logout
1014
+
930
1015
 
931
1016
 
932
1017
  --- Design suggestions ---
@@ -937,28 +1022,27 @@ This way, the app page remains open, and the user can easily return to it after
937
1022
  Example:
938
1023
  Suppose that https://auth.example.com/user/account is the endpoint used by the redirectToUserAccountConsole function
939
1024
  here’s a possible example:
1025
+ βœ… Usage example:
940
1026
  ```html
941
- <a href="https://auth.example.com/user/account" target="_blank">
1027
+ <a href="https://auth.example.com/user/account/console" target="_blank">
942
1028
  Manage my profile
943
1029
  </a>
944
1030
  ```
945
1031
 
946
-
947
- The user opens the account console in a new tab, uses it, and then manually returns to your app.
948
- βœ… Simple, no special configuration required.
949
-
950
-
951
- βœ… Usage example:
952
1032
  ```js
953
1033
 
954
- app.get('/logout', (req, res) => {
1034
+ app.get('/user/account/console', (req, res) => {
955
1035
  // Any custom logic before logout
956
- // ...
957
- keycloakAdapter.logout(req, res, "http://localhost:3001/home");
1036
+ keycloakAdapter.redirectToUserAccountConsole(res);
958
1037
  });
959
1038
 
960
1039
  ```
961
1040
 
1041
+ The user opens the account console in a new tab, uses it, and then manually returns to your app.
1042
+ βœ… Simple, no special configuration required.
1043
+
1044
+ ---
1045
+
962
1046
  --- Requirements ---
963
1047
  - The user must be authenticated with Keycloak and have a valid token in `req.kauth.grant`.
964
1048
  - The URL specified in `redirectTo` must be present in the `Valid Redirect URIs` in the Keycloak client.
package/index.js CHANGED
@@ -1274,7 +1274,7 @@ class keycloakExpressMiddleware {
1274
1274
  }
1275
1275
 
1276
1276
 
1277
- redirectToUserAccountConsole(req,res){
1277
+ redirectToUserAccountConsole(res){
1278
1278
  let redirectUrL=`${this.authServerUrl}/realms/${this.realmName}/account/`
1279
1279
  res.redirect(redirectUrL);
1280
1280
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "keycloak-express-middleware",
3
- "version": "4.5.1",
3
+ "version": "6.0.0",
4
4
  "description": "Adapter API to integrate Node.js (Express) applications with Keycloak. Provides middleware for authentication, authorization, token validation, and route protection via OpenID Connect.",
5
5
  "main": "index.js",
6
6
  "scripts": {