Giter Site home page Giter Site logo

hapi-oauth2orize's Introduction

hapi-oauth2orize

A bridge between hapi8+ and OAuth2orize

OAuth2orize is an OAuth2 provider implemented as a middleware for express. Given that you are (presumably) using hapi, you will need a bridge to make it work in hapi land. Thus, hapi-oauth2orize.

Note, this documentation is somewhat out of date. This project is currently being brought into the present. The most useful things to look at are currently the documentation/examples for OAuth2orize and the OAuth2orize methods that are exposed by the plugin.

Usage

npm install hapi-oauth2orize --save

After this, the usage is similar to to using vanilla OAuth2orize, but with a couple of tweaks to ensure compatiblity with hapi (>=8.x.x series).

// Require the plugin in hapi
server.register(require('hapi-oauth2orize'), function (err) {
  console.log(err);
});

var oauth = server.plugins['hapi-oauth2orize'];

Disclaimer

The code below is extracted from a working, but incomplete project. It has not been secured, or even fully finished. However, along with the OAuth2orize docs, you should be able to create a working implementation of your own.

Implicit Grant Flow

oauth.grant(oauth.grants.token(function (client, user, ares, done) {
  server.helpers.insert('token', {
    client: client._id,
    principal: user._id,
    scope: ares.scope,
    created: Date.now(),
    expires_in: 3600
  }, function (token) {
    done(null, token._id, {expires_in: token.expires_in});
  });
}));

Authorization Code Exchange Flow

oauth.grant(oauth.grants.code(function (client, redirectURI, user, ares, done) {
  server.helpers.insert('code', {
    client: client._id,
    principal: user._id,
    scope: ares.scope,
    redirectURI: redirectURI
  }, function (code) {
    done(null, code._id);
  });
}));

oauth.exchange(oauth.exchanges.code(function (client, code, redirectURI, done) {
  server.helpers.find('code', code, function (code) {
    if (!code || client.id !== code.client || redirectURI !== code.redirectURI) {
      return done(null, false);
    }
    server.helpers.insert('refreshToken', {
      client: code.client,
      principal: code.principal,
      scope: code.scope
    }, function (refreshToken) {
      server.helpers.insert('token', {
        client: code.client,
        principal: code.principal,
        scope: code.scope,
        created: Date.now(),
        expires_in: 3600
      }, function (token) {
        server.helpers.remove('code', code._id, function () {
          done(null, token._id, refreshToken._id, {expires_in: token.expires_in});
        });
      });
    });
  });
}));

oauth.exchange(oauth.exchanges.refreshToken(function (client, refreshToken, scope, done) {
  server.helpers.find('refreshToken', refreshToken, function (refreshToken) {
    if (refreshToken.client !== client._id) {
      return done(null, false, { message: 'This refresh token is for a different client'});
    }
    scope = scope || refreshToken.scope;
    server.helpers.insert('token', {
      client: client._id,
      principal: refreshToken.principal,
      scope: scope,
      created: Date.now(),
      expires_in: 3600
    }, function (token) {
      done(null, token._id, null, {expires_in: token.expires_in});
    });
  });
}));

// Client Serializers
oauth.serializeClient(function (client, done) {
  done(null, client._id);
});

oauth.deserializeClient(function (id, done) {
  server.helpers.find('client', id, function (client) {
    done(null, client[0]);
  });
});

OAuth Endpoints

server.route([{
    method: 'GET',
    path: '/oauth/authorize',
    handler: authorize
},{
    method: 'POST',
    path: '/oauth/authorize/decision',
    handler: decision
},{
    method: 'POST',
    path: '/oauth/token',
    handler: token
}]);

function authorize(request, reply) {
  oauth.authorize(request, reply, function (req, res) {
    reply.view('oauth', {transactionID: req.oauth2.transactionID});
  }, function (clientID, redirect, done) {
    server.helpers.find('client', clientID, function (docs) {
      done(null, docs[0], docs[0].redirect_uri);
    });
  });
};

function decision(request, reply) {
    oauth.decision(request, reply);
};

function token(request, reply) {
  oauth.authorize(function (clientID, redirect, done) {
    done(null, clientID, redirect);
  });
};

hapi-oauth2orize's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hapi-oauth2orize's Issues

Update docs

Bring docs up to date with changes in v1 and v2.

different signatures in oauth.authorize

Hello,
In the example oauth.authorize is passed with two different signatures, the first one is (request, reply, function ... ) and the second one is (function ...), was that an error? Because when token() is called, the following error is raised:
TypeError: Uncaught error: Cannot read property 'lazy' of undefined

at Object.internals.convertToExpress (/path/to/node_modules/hapi-oauth2orize/index.js:202:20)

function authorize(request, reply) {
  oauth.authorize(request, reply, function (req, res) {
    reply.view('oauth', {transactionID: req.oauth2.transactionID});
  }, function (clientID, redirect, done) {
    server.helpers.find('client', clientID, function (docs) {
      done(null, docs[0], docs[0].redirect_uri);
    });
  });
};

function decision(request, reply) {
    oauth.decision(request, reply);
};

function token(request, reply) {
  oauth.authorize(function (clientID, redirect, done) {
    done(null, clientID, redirect);
  });
};

Also I wonder if it's possible to include authentication in the example. Should I use hapi-auth-cookie to handle authentication with oauth2orize?

Add some documentation

Would be great if there were some docs and an example on how to integrate it with travelogue

Help needed regarding implementation of resource owner password grant.

I am using hapi-ouath2orize wrapper in my Hapi API.
In my application, i need to implement resource owner password grant. So far i understand i have to use following curl command to implement this grant.

  1. curl -XPOST "http://localhost:3000/oauth/token" -d "grant_type=password&client_id=abc123&client_secret=ssh-secret&username=bob&password=secret"
    return: TOKEN
  2. curl -H 'Authorization: Bearer TOKEN' -GET "http://localhost:3000/api/userinfo"
    can access protected resource using this command.

can anyone help me what will flow with some guidance(some sample code will be appreciable) ?

Hapi 8 and updated docs

Any word on testing with Hapi 8+?
Also, updated docs?

My team is looking to implement oauth for our API so we may be able to help contrib to this module.

Cheers.

Hapi 17

Any plans to update for Hapi 17 :) oauth2orize is the standard for NodeJS, this plugin is amazing too :)

Error: Invalid plugin options {}

i am getting this error when i try to register.

throw new Error(msgs.join(' ') || 'Unknown error');
^

Error: Invalid plugin options {}

[1] "0" must be a string
at Object.exports.contain.exports.reachTemplate.exports.assert.condition as assert
at Object.exports.apply (/Users/Lutfor/Documents/vincari-api/node_modules/hapi/lib/schema.js:17:10)
at module.exports.internals.Plugin.internals.Plugin.register.each as register
at Object. (/Users/Lutfor/Documents/vincari-api/dist/index.js:14:8)
at Module._compile (module.js:413:34)
at Object.Module._extensions..js (module.js:422:10)
at Module.load (module.js:357:32)
at Function.Module._load (module.js:314:12)
at Function.Module.runMain (module.js:447:10)
at startup (node.js:139:18)
at node.js:999:3

authorize endpoint: Uncaught error: reply interface called twice

Hello,

This is my code for controllers/oauth2.js where I have the handler for '/oauth/authorize'

   authorize: function (request, reply) {
      oauth.authorize(request, reply, function (req, res) {
          reply.view('oauth', {transactionID: req.app.transactionID});
      }, function (clientID, redirect, done) {
        server.helpers.find('client', clientID, function (docs) {
          done(null, docs[0], docs[0].redirect_uri);
        });
      });
    },

In the third line I get this error stack trace:

Debug: internal, implementation, error 
   ** Error: Uncaught error: reply interface called twice**
    at Object.exports.contain.exports.reachTemplate.exports.assert.condition [as assert] (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/hapi/node_modules/hoek/lib/index.js:732:11)
    at Function.internals.Reply.interface.internals.response (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/hapi/lib/reply.js:132:10)
    at reply (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/hapi/lib/reply.js:70:22)
    at Object.ExpressServer.res.end (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/hapi-oauth2orize/index.js:271:32)
    at errorHandler (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/oauth2orize/lib/middleware/errorHandler.js:67:18)
    at /home/pablo/devLab/audienceLeap/api/server/src/node_modules/hapi-oauth2orize/index.js:91:59
    at errorHandler (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/oauth2orize/lib/middleware/errorHandler.js:73:60)
    at /home/pablo/devLab/audienceLeap/api/server/src/node_modules/hapi-oauth2orize/index.js:88:57
    at /home/pablo/devLab/audienceLeap/api/server/src/node_modules/oauth2orize/lib/middleware/authorization.js:121:25
    at pass (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/oauth2orize/lib/server.js:283:14)
    at Server._parse (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/oauth2orize/lib/server.js:285:5)
    at authorization (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/oauth2orize/lib/middleware/authorization.js:120:12)
    at Object.internals.authorize (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/hapi-oauth2orize/index.js:85:66)
    at oauth2.authorization (/home/pablo/devLab/audienceLeap/api/server/src/controllers/oauth2.js:103:13)
    at Object.exports.execute.internals.prerequisites.internals.handler.callback [as handler] (/home/pablo/devLab/audienceLeap/api/server/src/node_modules/hapi/lib/handler.js:96:36)
    at /home/pablo/devLab/audienceLeap/api/server/src/node_modules/hapi/lib/handler.js:30:23

Any ideas how we fix this?

oauth2orize is not working with hapijs

How do I implement oauth2orize in hapijs. Please suggest. I did this code but it's not working when I am hitting the API. I am new in hapijs and oauth2orize. Also hapi-oauth2orize is not working as I am using hapi 13.4.1 which is not compatible with hapi-oauth2orize 1.3.0, throwing error 'Invalid plugin options {}' .Please suggest me a way to implement oauth2orize in hapijs.

const Hapi = require('hapi');
const server = new Hapi.Server();
const oauth2orize = require('oauth2orize');
var oauth = oauth2orize.createServer();

server.connection({ 
    host: 'localhost', 
    port: 8000 
});

server.register([{
    register: require('hapi-mongodb'),
    options: dbOpts
}], function (err) {
    if (err) {
        console.error(err);
        throw err;
    }
    server.start();

    server.route([
                {
                  method: 'GET',
                  path: '/oauth/authorizegrant',
                  config: {
                    auth: false,
                    handler: function(request, reply) {
                        var clientId = request.query.client_id,
                            redirectUrl = request.query.redirect_uri,
                            resType = request.query.response_type,
                            state = request.query.state;
                        oauth.grant(oauth2orize.grant.code(function(clientId,redirectUrl,resType,state,callback) {
                          // Create a new authorization code
                              console.log('client', client);
                              var db = request.server.plugins['hapi-mongodb'].db;
                              var code = new Code({
                                value: uid(16),
                                clientId: client._id,
                                redirectUri: redirectUri,
                                userId: user._id
                              });

                          // Save the auth code and check for errors
                        db.collection('codes').insert(code, function(err) {
                            if (err) { console.log('err*********', err); return callback(err); }

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

                    }
                  }
                },
            ]);
});

Hapi 12+ and yar bug fix

From https://github.com/hapijs/yar

Starting with Hapi 12 the request.session placeholder was removed.
The guidance from Hapi maintainer Eran Hammer was for this and similar modules to move data storage away from request.session and use a more unique location. So, starting in 6.x.x the yar storage has been moved to request.yar

My solution:

index.js line 201 should be:
request.yar.lazy(true);

index.js line 206 should be:
session: request.yar,

Maybe you prefer a different approach to solve the issue

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.