# Oauth/OpenId Login with Keycloak based on roles

**URL:** https://discourse.nodered.org/t/oauth-openid-login-with-keycloak-based-on-roles/96690
**Category:** General
**Tags:** security
**Created:** [21 April 2025 18:55 UTC](https://discourse.nodered.org/t/oauth-openid-login-with-keycloak-based-on-roles/96690 "2025-04-21T18:55:14Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![sara-aziz](https://avatars.discourse-cdn.com/v4/letter/s/edb3f5/32.png) [@sara-aziz](https://discourse.nodered.org/u/sara-aziz)
#### Post date: [21 April 2025 18:55 UTC](https://discourse.nodered.org/t/oauth-openid-login-with-keycloak-based-on-roles/96690/1 "2025-04-21T18:55:14Z")

</div>

Hi Everyone,

I’m integrating Keycloak authentication into Node-RED using `passport-keycloak-oauth2-oidc`. The authentication flow is successful, and I can see the correct user profile and roles returned from Keycloak. However, after authentication, the app redirects back to the login screen instead of granting access to the Node-RED editor.

**What I have so far:**

- I’ve followed the structure and logic used in the `node-red-auth-github` example.
- When I use the static `users` option (i.e. hardcoding users and permissions in `settings.js`), everything works as expected — users are authenticated and redirected correctly to the editor.
- Now, I want to fetch roles dynamically from Keycloak and assign permissions based on those roles instead of using the static `users` option.

**Keycloak Setup:**

- Realm: `MyRealm`
- Client ID: `nodered-client`
- Roles assigned in Keycloak: `nodered-editor`, `nodered-viewer`
- I confirmed that roles like `nodered-editor` are returned in the profile inside `resource_access`.

**My Passport Strategy:**

```auto
var path = require("path");
var oauth2Strategy = require("passport-keycloak-oauth2-oidc");

var requiredOptions = [
    'clientID',
    'clientSecret',
    'realm',
    'authServerURL',
    'baseURL'
];

module.exports = function (opts) {
    // Validate required options
    for (var i = 0; i < requiredOptions.length; i++) {
        if (!opts.hasOwnProperty(requiredOptions[i])) {
            throw new Error("Missing auth option: " + requiredOptions[i]);
        }
    }

    // Construct callback URL
    var callbackURL = opts.baseURL +
        ((opts.baseURL[opts.baseURL.length - 1] === "/") ? "" : "/") +
        "auth/strategy/callback";

    // Define adminAuth config
    var adminAuth = {
        type: "strategy",
        strategy: {
            name: "keycloak",
            label: "Sign in with Keycloak",
            icon: "fa-lock",
            strategy: oauth2Strategy.Strategy,
            options: {
                clientID: opts.clientID,
                clientSecret: opts.clientSecret,
                realm: opts.realm,
                authServerURL: opts.authServerURL,
                callbackURL: callbackURL,
                publicClient: 'false',
                scope: "openid profile email",
                sslRequired: 'external',
                verify: function (accessToken, refreshToken, profile, done) {
                    console.log("Keycloak profile:", profile);

                    const roles = profile.roles?.resource_access?.[opts.clientID]?.roles || [];
                    console.log("Roles for the user:", roles);

                    let permissions = [];
                    if (roles.includes("nodered-editor")) {
                        permissions = ["*"]; // Full access
                    } else if (roles.includes("nodered-viewer")) {
                        permissions = ["flows.read"]; // Read-only
                    }

                    const user = {username: profile.username || profile.preferred_username || profile.sub,
                          permissions: permissions,email: profile.email || null,};

                    return done(null, user);
                    console.log("Authenticated user:", user);
                }
            }
        }
    };

    // Optional default permission
    if (opts.hasOwnProperty("default")) {
        adminAuth.default = opts.default;
    }

    return adminAuth;
};

```

**adminAuth in settings.js:**

```
adminAuth: require('mynodered-plugin')({
clientID: "nodered-client",
clientSecret: "secret",
realm: "MyRealm",
authServerURL: "https://auth-example.com",
baseURL: "https://example.com/"

```

}),

**My user logs:**

 ![Keycloak NodeRed logs](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/0/7/075c3ddf76f2753adfbb0de1805be043ba92624b.jpeg)

Any guidance or examples that could help get role-based dynamic authentication working with Keycloak would be greatly appreciated!

---

<div class="post-metadata">

### Author: ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)
#### Post date: [20 July 2025 18:55 UTC](https://discourse.nodered.org/t/oauth-openid-login-with-keycloak-based-on-roles/96690/2 "2025-07-20T18:55:49Z")

</div>

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.
