How to implement SSO (Single Sign-On) based on Node-RED and passport-oauth2

I have implemented it through the following five-step process, but I don’t know how to handle steps 4 and 5. I have already obtained my access token, but I don’t know how to redirect to execute the callback verify method, write cookies, write sessions, and other process handling. I added my custom getSSOToken http callback interface to the node-red source code. This interface obtains the access_token value of my company’s SSO system. :stuck_out_tongue_closed_eyes: I don’t know what to do next? It seems that it did not callback the verify method as expected :joy:

1, Create OAuth2 Strategy: First, I use the passport.use method to create a new OAuth2Strategy. In this strategy, I provide the authorization URL, token URL, client ID, client secret, scope, state, and callback URL
This step is okay, my program can work

2, User Authentication: When a user attempts to access protected resources, I redirect them to the login page of the SSO service. On this page, the user can enter their credentials to log in.[/b]
This step is okay, my program can work

3, Obtain Access Token: Once the user logs in successfully, the SSO service redirects the user back to my application, including an authorization code in the query parameters of the redirect URL. I capture this authorization code and use it to obtain an access token from the SSO service.
This step is okay, my program can work

4, Use Access Token: After obtaining the access token, use this token to request protected resources from the SSO service. This typically involves adding the access token to the Authorization header of my HTTP requests.

I don’t know How to do at step 4? :joy:

5, Handle Callback: In the OAuth2Strategy, provide a function to handle the callback. This function is called when the SSO service returns user information. Create a user object based on the returned user information and pass it to the done callback

I don’t know How to do at step 5? :joy:

my settings.js adminAuth code


    adminAuth: {
        type: "strategy",
        strategy: {
            name: "oauth2",
            label: 'Sign in with SSO',
            icon: "fa-user",
            strategy: require("passport-oauth2").Strategy,
            options: {
                authorizationURL: 'https://mycompany.sso.com/sso/oauth/authorize?uuid=CF7E5931A9C3F11770B700F3F7106FEB',
                tokenURL: 'https://mycompany.sso.com/sso/oauth/token',
                client_id: 'aaa',
                client_secret: 'bbb',
                scope:'app',
                state:'https://0d6d-103-70-220-21.ngrok-free.app/getSSOToken',
                callbackURL: 'https://0d6d-103-70-220-21.ngrok-free.app/getSSOToken',
                verify: function(accessToken, refreshToken, profile, done) { 
                    done(null, profile);
                }
            }
        },
        users: function(username) {
            return Promise.resolve({ username: username, permissions: "*" });
        }
    },

my getSSOToken http code

var runtimeAPI;
var apiUtils = require("../util");
const axios = require('axios');
const querystring = require('querystring'); 
module.exports = {
    init: function (_runtimeAPI) {
        runtimeAPI = _runtimeAPI;
    }, 
    getSSOToken: function (req, res, next) { 
        console.info(req.query)
        var _code = req.query.code
        var _state = req.query.state
        const url = 'https://mycompany.sso.com/sso/oauth/token';
        const data = querystring.stringify({
            client_id: 'aaa',
            client_secret: 'bbb',
            grant_type: 'authorization_code',
            redirect_uri: 'https://0d6d-103-70-220-21.ngrok-free.app/getSSOToken',
            scope: 'app',
            code: _code
        });

        console.log('---------------request data json start ------------------')
        console.log(data)
        console.log('------------------request data json end -----------------') 
 
        const config = {
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        }; 
        axios.post(url, data, config)
            .then(function (response) { 
                const profile = {
                    id: "admin",
                    username: "admin",
                    displayName: "admin",
                    emails: [{ value: "1@qq.com" }],
                    photos: [{ value: "/pic.png" }]
                };
                res.send({ "access_token": response.data.access_token,
                    "refresh_token": response.data.refresh_token,
                    "profile": profile,
                     "token_type":'bearer',
                    "expires_in":43199,
                   "scope":'app',
                    "jti":'9b4731f0-88cf-415d-b0c5-35c6460474cd'
                })
            })
            .catch(function (error) {
                console.error('Error:', error);
                res.status(500).send({"error": "Internal Server Error"});
            });
    }
}



I can't answer your question directly I'm afraid. But I would not use Node-RED for the SSO/Authentication.

A proxy is ideal for this and would be preferred in all production environments. The proxy (e.g. NGINX) will have strong integrations with standards-based SSO and authentication and will handle ALL of the integration and token/session integration. Passing on to Node-RED any required metadata.

Though it may seem more complex to do it this way, in the end, it is sometimes less complex. It is almost certainly more secure and is certainly more resource efficient.

1 Like

Thank you for your reply. Your idea is not bad.
But...ah....
Using nginx as a front-end proxy for authentication means that each request to the node-red dashboard web ui section needs to have a token in the header. This can be inconvenient.

Not really. NGINX takes care of everything for you once set up. It is the tooling that takes care of tokens. This is a 100% standard approach that all properly secured websites use the approach. The tooling needs to manage sessions not just tokens (which should only be a marker for a session).

Also, Dashboard itself doesn't need the token if you are using NGINX to manage the SSO. You probably want to pass on the valid user name and maybe some other user metadata but only NGINX actually needs the tokens.

thanks @TotallyInformation , I should try it this way