1

So I am designing an app with nodejs and I need to create a user forum. I decided against reinventing the wheel so I choose to use nodebb. However, my app has a user log in and so does node bb and I want the user to be logged in automatically in nodebb once logged into my site. I have never used oauth2orize before but this is what I came up with:

       server.grant(oauth2orize.grant.code(function(client, redirectUri, user, ares, callback) {
          // Create a new authorization code
          var code = new Code({
            value: uid(16),
            clientId: client._id,
            redirectUri: redirectUri,
            userId: user._id
          });

          // Save the auth code and check for errors
          code.save(function(err) {
            if (err) { return callback(err); }

            callback(null, code.value);
          });
        }));


        // Exchange authorization codes for access tokens
        server.exchange(oauth2orize.exchange.code(function(client, code, redirectUri, callback) {
            console.log(client, code, redirectUri)
          Code.findOne({ value: code }, function (err, authCode) {
            if (err) { return callback(err); }
              console.log(authCode.clientId,client._id);
            if (authCode === undefined) { return callback(null, false); }
            if (client._id.toString() !== authCode.clientId) { return callback(null, false); }
            //if (redirectUri !== authCode.redirectUri) { return callback(null, false); }

            // Delete auth code now that it has been used
            authCode.remove(function (err) {
              if(err) { return callback(err); }

              // Create a new access token
              var token = new Token({
                value: uid(256),
                clientId: authCode.clientId,
                userId: authCode.userId
              });

              // Save the access token and check for errors
              token.save(function (err) {
                if (err) { return callback(err); }

                callback(null, token);
              });
            });
          });
        }));

        module.exports.authorization = [
            server.authorization(function(clientId, redirectUri, callback) {
                Client.findOne({ id: clientId }, function (err, client) {
                  if (err) { console.log("I ran herea");return callback(err); }
                  return callback(null, client, redirectUri);
                });
              }, function (client, user, redirectUri, done) {
                console.log(redirectUri);
                setCodes(client, user, redirectUri, Code);

                Code.find({
                    clientId: client.id,
                    userId: user._id
                }, function (err, codes) {
                    console.log(codes);
                    if (err) { console.log("second"); return done(err); }
                    if (codes.length > 0) {
                        console.log("third")
                        return done(null, true);
                    } else {
                        console.log('I ran here fourth');
                        return done(null,false);
                    }
                });
            })
        ]

        // Application client token exchange endpoint
        module.exports.token = [
          server.token(),
          server.errorHandler()
        ]



        module.exports.getNodebbUsers = function(req, res){
            console.log(req.body.token);
            Token.find({value : req.body.token}, function(error, user){
                userId = user[0].userId;
                if(!error){
                    User.find({_id : userId}, function(error, user){
                        console.log(userId);
                        if(!error){
                            res.json({
                                username : user[0].userName,
                                email : user[0].email,
                                id : user[0]._id
                            })
                        } else {
                            console.log(error);
                        }
                    })
                }
            })

        }

This is my oauth2orize block of code and it works well on postman.

However, this is the plugin on nodebb that I was supposed to edit and use. I have already edited it I am really stumped now.

var constants = Object.freeze({
                        type: 'oauth2', // Either 'oauth' or 'oauth2'
                        name: 'create-and-login-user',  // Something unique to your OAuth provider in lowercase, like "github", or "nodebb"
                        oauth: {
                            requestTokenURL: '',
                            accessTokenURL: '',
                            userAuthorizationURL: '',
                            consumerKey: '',
                            consumerSecret: ''
                        },
                        oauth2: {
                            authorizationURL: '/api/oauth2/authorize',
                            tokenURL: '/api/oauth2/token',
                            clientID: 'nodeBB_logIn',
                            clientSecret: 'change_this_later'
                        },
                        userRoute: '/api/oauth2/users'  // This is the address to your app's "user profile" API endpoint (expects JSON)
                    }),
                    configOk = false,
                    OAuth = {}, passportOAuth, opts;

                if (!constants.name) {
                    winston.error('[sso-oauth] Please specify a name for your OAuth provider (library.js:32)');
                } else if (!constants.type || (constants.type !== 'oauth' && constants.type !== 'oauth2')) {
                    winston.error('[sso-oauth] Please specify an OAuth strategy to utilise (library.js:31)');
                } else if (!constants.userRoute) {
                    winston.error('[sso-oauth] User Route required (library.js:31)');
                } else {
                    configOk = true;
                }

                OAuth.getStrategy = function(strategies, callback) {
                    if (configOk) {
                        passportOAuth = require('passport-oauth')[constants.type === 'oauth' ? 'OAuthStrategy' : 'OAuth2Strategy'];

                        if (constants.type === 'oauth') {
                            // OAuth options
                            opts = constants.oauth;
                            opts.callbackURL = nconf.get('url') + '/auth/' + constants.name + '/callback';

                            passportOAuth.Strategy.prototype.userProfile = function(token, secret, params, done) {
                                this._oauth.get(constants.userRoute, token, secret, function(err, body, res) {
                                    if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }

                                    try {
                                        var json = JSON.parse(body);
                                        OAuth.parseUserReturn(json, function(err, profile) {
                                            if (err) return done(err);
                                            profile.provider = constants.name;

                                            done(null, profile);
                                        });
                                    } catch(e) {
                                        done(e);
                                    }
                                });
                            };
                        } else if (constants.type === 'oauth2') {
                            // OAuth 2 options
                            opts = constants.oauth2;
                            opts.callbackURL = nconf.get('url') + '/auth/' + constants.name + '/callback';

                            passportOAuth.Strategy.prototype.userProfile = function(accessToken, done) {
                                this._oauth2.get(constants.userRoute, accessToken, function(err, body, res) {
                                    if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }

                                    try {
                                        var json = JSON.parse(body);
                                        OAuth.parseUserReturn(json, function(err, profile) {
                                            if (err) return done(err);
                                            profile.provider = constants.name;

                                            done(null, profile);
                                        });
                                    } catch(e) {
                                        done(e);
                                    }
                                });
                            };
                        }

                        opts.passReqToCallback = true;

                        passport.use(constants.name, new passportOAuth(opts, function(req, token, secret, profile, done) {
                            OAuth.login({
                                oAuthid: profile.id,
                                handle: profile.displayName,
                                email: profile.emails[0].value,
                                isAdmin: profile.isAdmin
                            }, function(err, user) {
                                if (err) {
                                    return done(err);
                                }

                                authenticationController.onSuccessfulLogin(req, user.uid);
                                done(null, user);
                            });
                        }));

                        strategies.push({
                            name: constants.name,
                            url: '/auth/' + constants.name,
                            callbackURL: '/auth/' + constants.name + '/callback',
                            icon: 'fa-check-square',
                            scope: (constants.scope || '').split(',')
                        });

                        callback(null, strategies);
                    } else {
                        callback(new Error('OAuth Configuration is invalid'));
                    }
                };

                OAuth.parseUserReturn = function(data, callback) {
                    // Alter this section to include whatever data is necessary
                    // NodeBB *requires* the following: id, displayName, emails.
                    // Everything else is optional.

                    // Find out what is available by uncommenting this line:
                    // console.log(data);

                    var profile = {};
                    profile.id = data.id;
                    profile.displayName = data.name;
                    profile.emails = [{ value: data.email }];

                    // Do you want to automatically make somebody an admin? This line might help you do that...
                    // profile.isAdmin = data.isAdmin ? true : false;

                    // Delete or comment out the next TWO (2) lines when you are ready to proceed
                    process.stdout.write('===\nAt this point, you\'ll need to customise the above section to id, displayName, and emails into the "profile" object.\n===');
                    return callback(new Error('Congrats! So far so good -- please see server log for details'));

                    callback(null, profile);
                }

                OAuth.login = function(payload, callback) {
                    OAuth.getUidByOAuthid(payload.oAuthid, function(err, uid) {
                        if(err) {
                            return callback(err);
                        }

                        if (uid !== null) {
                            // Existing User
                            callback(null, {
                                uid: uid
                            });
                        } else {
                            // New User
                            var success = function(uid) {
                                // Save provider-specific information to the user
                                User.setUserField(uid, constants.name + 'Id', payload.oAuthid);
                                db.setObjectField(constants.name + 'Id:uid', payload.oAuthid, uid);

                                if (payload.isAdmin) {
                                    Groups.join('administrators', uid, function(err) {
                                        callback(null, {
                                            uid: uid
                                        });
                                    });
                                } else {
                                    callback(null, {
                                        uid: uid
                                    });
                                }
                            };

                            User.getUidByEmail(payload.email, function(err, uid) {
                                if(err) {
                                    return callback(err);
                                }

                                if (!uid) {
                                    User.create({
                                        username: payload.handle,
                                        email: payload.email
                                    }, function(err, uid) {
                                        if(err) {
                                            return callback(err);
                                        }

                                        success(uid);
                                    });
                                } else {
                                    success(uid); // Existing account -- merge
                                }
                            });
                        }
                    });
                };

                OAuth.getUidByOAuthid = function(oAuthid, callback) {
                    db.getObjectField(constants.name + 'Id:uid', oAuthid, function(err, uid) {
                        if (err) {
                            return callback(err);
                        }
                        callback(null, uid);
                    });
                };

                OAuth.deleteUserData = function(data, callback) {
                    async.waterfall([
                        async.apply(User.getUserField, data.uid, constants.name + 'Id'),
                        function(oAuthIdToDelete, next) {
                            db.deleteObjectField(constants.name + 'Id:uid', oAuthIdToDelete, next);
                        }
                    ], function(err) {
                        if (err) {
                            winston.error('[sso-oauth] Could not remove OAuthId data for uid ' + data.uid + '. Error: ' + err);
                            return callback(err);
                        }

                        callback(null, data);
                    });
                };

                module.exports = OAuth;
            }(module));

From my understanding of how this works: nodebb makes a call to my authorization end point and I check if the client is correct and grant it an access code, it then visits my token end point and exchanges this access code for a token. I take it to the user end point and hands it my users credentials to log in. I think I am wrong since it is not working and I think the issue could be from the name: create-and-login-user that I am using but I don't see how to improve on the code I have written above.

What is not clear to me is what the callback uri does, why the name callback is appended to it and if there has to be an endpoint to this url on my app.

Okay I made some little progress but I am stuck with this error:

https://www.dropbox.com/s/hm711i99iex4v1x/Screenshot%202017-02-13%2021.57.07.png?dl=0

It has to do with the callback uri. Am I supposed to provide an endpoint for it and if yes, why does it not point to my app port number but to that of nodebb

J.Ewa
  • 205
  • 3
  • 14

0 Answers0