Own custom OAuth/OpenID provider implementation

Hello everyone,
I need some help if it is possible. Here is the short description of my node-red setup. I want to implement my own custom Passport.js Strategy and use it with node-red. Note: the node-red storage engine is overridden with my own implementation. I have reached the point where I successfully take a JWT token from my own custom provider and it is stored in editor’s (browser) localStorage. The token is attached to every request as a bearer token. But then comes the problem, the editor-api doesn’t recognize as a valid access-token. I followed the route of bearer authentication and found out that at the token validation (@node-red/editor-api/lib/auth/strategies.js:33) there is no such token stored and therefore the token is marked as invalid. During the process the customStorage’s saveSessions method is not called at all. The question is where Twitter’s, Github’s or other provider’s access_tokens are stored and how they are verified?
Here is my settings.js content as well:

const customStorageModule = require("./storage_module");

module.exports = {
    httpAdminRoot:"/red/",
    httpNodeRoot: "/api",
    userDir: workingDirectory + sep + '.node-red',
    coreNodesDir: "node_repository",
    storageModule: customStorageModule,
    functionGlobalContext: {},    // enables global context
    adminAuth: require('./cloud_passport.js')({
        baseURL: "http://cloud.localhost/red/"
    })

And my Passport.js custom Strategy implementation (cloud_passport.js):

const util = require("util");
const passport = require('passport-strategy');


function Strategy(arg) {
	passport.Strategy.call(this);
	this.name = arg.name;
	this._verify = arg.verify;
}
util.inherits(Strategy, passport.Strategy);

Strategy.prototype.authenticate = function (req, res) {
	var self = this;

	function verified(err, user, info) {
		if (err) {
			return self.error(err);
		}
		if (!user) {
			return self.fail(info);
		}
		self.success(user, info);
	}

	try {
		this._verify(req, verified);
	} catch (ex) {
		return self.error(ex);
	}
};
module.exports = function(opts) {
    var callbackURL = opts.baseURL+
        ((opts.baseURL[opts.baseURL.length-1] === "/")?"":"/")+
        "auth/strategy/callback";

    var adminAuth = {
        type:"strategy",
        strategy: {
            name: "Szilveszter",
            label: "Sign in with Szilveszter",
            icon:"fa-twitter",
            strategy: Strategy,
            options: {
                callbackURL: callbackURL,
                baseURL: opts.baseURL,
                name: "Szilveszter",
                verify: function (req, callback) {
                    callback(null, {
                        username: "Szilveszter",
                        permissions: ["*"],
                        tokens: {
                            accessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
                        }
                    });
                }
            }
        },
        users: async arg => {
            return {
                username: arg,
                permissions: ["*"]
            }
        },
    };

That is not how it works.

The auth plugin verifies a user is valid and then the runtime generates one of our own tokens for the user and that is what the editor uses. We do not store any tokens generated by the auth plugin.

You should not be doing anything in the editor to attach your own bearer tokens - the editor takes care of that using its own token.

1 Like