Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: oauthjs/node-oauth2-server
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: marsanla/node-oauth2-server-restify
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.
  • 8 commits
  • 10 files changed
  • 1 contributor

Commits on Oct 30, 2014

  1. Update to restify

    marsanla committed Oct 30, 2014
    Copy the full SHA
    c295461 View commit details
  2. Update to restify

    marsanla committed Oct 30, 2014
    Copy the full SHA
    1644377 View commit details

Commits on Dec 17, 2014

  1. Update

    marsanla committed Dec 17, 2014
    Copy the full SHA
    1cd73e5 View commit details
  2. Update

    marsanla committed Dec 17, 2014
    Copy the full SHA
    0909aa5 View commit details
  3. Update

    marsanla committed Dec 17, 2014
    Copy the full SHA
    fa59bfe View commit details

Commits on Feb 2, 2015

  1. update

    marsanla committed Feb 2, 2015
    Copy the full SHA
    206e4a3 View commit details
  2. Update grant.js

    marsanla committed Feb 2, 2015
    Copy the full SHA
    4f2397f View commit details
  3. Update package.json

    marsanla committed Feb 2, 2015
    Copy the full SHA
    d0736ad View commit details
Showing with 377 additions and 397 deletions.
  1. +1 −0 .gitignore
  2. +13 −14 Readme.md
  3. +40 −44 lib/authCodeGrant.js
  4. +42 −40 lib/authorise.js
  5. +0 −67 lib/error.js
  6. +118 −124 lib/grant.js
  7. +94 −98 lib/oauth2server.js
  8. +3 −3 lib/token.js
  9. +57 −0 npm-debug.log
  10. +9 −7 package.json
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
node_modules
.idea
27 changes: 13 additions & 14 deletions Readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Node OAuth2 Server [![Build Status](https://travis-ci.org/thomseddon/node-oauth2-server.png?branch=2.0)](https://travis-ci.org/thomseddon/node-oauth2-server)
# Node OAuth2 Server

Complete, compliant and well tested module for implementing an OAuth2 Server/Provider with [express](http://expressjs.com/) in [node.js](http://nodejs.org/)
Complete, compliant and well tested module for implementing an OAuth2 Server/Provider with [resitfy](http://mcavage.me/node-restify/) in [node.js](http://nodejs.org/)

## Installation

@@ -10,32 +10,31 @@ npm install oauth2-server

## Quick Start

The module provides two middlewares, one for authorization and routing, another for error handling, use them as you would any other middleware:
The module provides one middleware for authorization and routing, use it as you would any other middleware:

```js
var express = require('express'),
bodyParser = require('body-parser'),
oauthserver = require('oauth2-server');
var restify = require('restify'),
oauthserver = require('oauth2-server-restify');

var app = express();
var server = restify.createServer();

app.use(bodyParser()); // REQUIRED
server.use(restify.bodyParser({})); // REQUIRED

app.oauth = oauthserver({
server.oauth = oauthserver({
model: {}, // See below for specification
grants: ['password'],
debug: true
});

app.all('/oauth/token', app.oauth.grant());
server.post('/oauth/token', server.oauth.grant());

app.get('/', app.oauth.authorise(), function (req, res) {
server.get('/', server.oauth.authorise(), function (req, res, next) {
res.send('Secret area');
next();
});

app.use(app.oauth.errorHandler());

app.listen(3000);
server.listen(3000);
```

After running with node, visting http://127.0.0.1:3000 should present you with a json response saying your access token could not be found.
@@ -311,7 +310,7 @@ See: https://github.com/thomseddon/node-oauth2-server/blob/master/Changelog.md

## Credits

Copyright (c) 2013 Thom Seddon
Copyright (c) 2013 Thom Seddon & Marcos Sanz

## License

84 changes: 40 additions & 44 deletions lib/authCodeGrant.js
Original file line number Diff line number Diff line change
@@ -14,9 +14,9 @@
* limitations under the License.
*/

var error = require('./error'),
runner = require('./runner'),
token = require('./token');
var error = require('node-restify-errors'),
runner = require('./runner'),
token = require('./token');

module.exports = AuthCodeGrant;

@@ -54,7 +54,7 @@ function AuthCodeGrant(config, req, res, next, check) {
if (err && res.oauthRedirect) {
// Custom redirect error handler
res.redirect(self.client.redirectUri + '?error=' + err.error +
'&error_description=' + err.error_description + '&code=' + err.code);
'&error_description=' + err.error_description + '&code=' + err.code);

return self.config.continueAfterResponse ? next() : null;
}
@@ -66,131 +66,127 @@ function AuthCodeGrant(config, req, res, next, check) {
/**
* Check Request Params
*
* @param {Function} done
* @param {Function} next
* @this OAuth
*/
function checkParams (done) {
function checkParams (next) {
var body = this.req.body;
var query = this.req.query;
if (!body && !query) return done(error('invalid_request'));
if (!body && !query) return next(new error.BadMethodError());

// Response type
this.responseType = body.response_type || query.response_type;
if (this.responseType !== 'code') {
return done(error('invalid_request',
'Invalid response_type parameter (must be "code")'));
return next(new error.BadMethodError('Invalid response_type parameter (must be "code")'));
}

// Client
this.clientId = body.client_id || query.client_id;
if (!this.clientId) {
return done(error('invalid_request',
'Invalid or missing client_id parameter'));
return next(new error.BadMethodError('Invalid or missing client_id parameter'));
}

// Redirect URI
this.redirectUri = body.redirect_uri || query.redirect_uri;
if (!this.redirectUri) {
return done(error('invalid_request',
'Invalid or missing redirect_uri parameter'));
return next(new error.BadMethodError('Invalid or missing redirect_uri parameter'));
}

done();
next();
}

/**
* Check client against model
*
* @param {Function} done
* @param {Function} next
* @this OAuth
*/
function checkClient (done) {
function checkClient (next) {
var self = this;
this.model.getClient(this.clientId, null, function (err, client) {
if (err) return done(error('server_error', false, err));
if (err) return next(new error.InternalError(err));

if (!client) {
return done(error('invalid_client', 'Invalid client credentials'));
return next(new error.InvalidCredentialsError('Invalid client credentials'));
} else if (Array.isArray(client.redirectUri)) {
if (client.redirectUri.indexOf(self.redirectUri) === -1) {
return done(error('invalid_request', 'redirect_uri does not match'));
if (client.redirecturi.indexOf(self.redirectUri) === -1) {
return next(new error.BadMethodError('redirect_uri does not match'));
}
client.redirectUri = self.redirectUri;
} else if (client.redirectUri !== self.redirectUri) {
return done(error('invalid_request', 'redirect_uri does not match'));
client.redirecturi = self.redirectUri;
} else if (client.redirecturi !== self.redirectUri) {
return next(new error.BadMethodError('redirect_uri does not match'));
}

// The request contains valid params so any errors after this point
// are redirected to the redirect_uri
self.res.oauthRedirect = true;
self.client = client;

done();
next();
});
}

/**
* Check client against model
*
* @param {Function} done
* @param {Function} next
* @this OAuth
*/
function checkUserApproved (done) {
function checkUserApproved (next) {
var self = this;
this.check(this.req, function (err, allowed, user) {
if (err) return done(error('server_error', false, err));
if (err) return new next(error.InternalError(err));

if (!allowed) {
return done(error('access_denied',
'The user denied access to your application'));
return next(new error.NotAuthorizedError('The user denied access to your application'));
}

self.user = user;
done();
next();
});
}

/**
* Check client against model
*
* @param {Function} done
* @param {Function} next
* @this OAuth
*/
function generateCode (done) {
function generateCode (next) {
var self = this;
token(this, 'authorization_code', function (err, code) {
self.authCode = code;
done(err);
next(err);
});
}

/**
* Check client against model
*
* @param {Function} done
* @param {Function} next
* @this OAuth
*/
function saveAuthCode (done) {
function saveAuthCode (next) {
var expires = new Date();
expires.setSeconds(expires.getSeconds() + this.config.authCodeLifetime);

this.model.saveAuthCode(this.authCode, this.client.clientId, expires,
this.model.saveAuthCode(this.authCode, this.client.clientId || this.client.id, expires,
this.user, function (err) {
if (err) return done(error('server_error', false, err));
done();
});
if (err) return new next(error.InternalError(err));
next();
});
}

/**
* Check client against model
*
* @param {Function} done
* @param {Function} next
* @this OAuth
*/
function redirect (done) {
this.res.redirect(this.client.redirectUri + '?code=' + this.authCode +
(this.req.query.state ? '&state=' + this.req.query.state : ''));
function redirect (next) {
this.res.redirect(this.client.redirecturi + '?code=' + this.authCode +
(this.req.query.state ? '&state=' + this.req.query.state : ''));

if (this.config.continueAfterResponse)
return done();
return next();
}
82 changes: 42 additions & 40 deletions lib/authorise.js
Original file line number Diff line number Diff line change
@@ -14,8 +14,8 @@
* limitations under the License.
*/

var error = require('./error'),
runner = require('./runner');
var error = require('node-restify-errors'),
runner = require('./runner');

module.exports = Authorise;

@@ -50,81 +50,83 @@ function Authorise (config, req, next) {
*
* Extract token from request according to RFC6750
*
* @param {Function} done
* @param {Function} next
* @this OAuth
*/
function getBearerToken (done) {
var headerToken = this.req.get('Authorization'),
getToken = this.req.query.access_token,
postToken = this.req.body ? this.req.body.access_token : undefined;
function getBearerToken (next) {
var headerToken = this.req.authorization,
getToken = this.req.query.access_token,
postToken = this.req.body ? this.req.body.access_token : undefined;

// Check exactly one method was used
var methodsUsed = (headerToken !== undefined) + (getToken !== undefined) +
(postToken !== undefined);
var methodsUsed = (headerToken !== undefined && Object.keys(headerToken).length > 0) + (getToken !== undefined) +
(postToken !== undefined);

if (methodsUsed > 1) {
return done(error('invalid_request',
'Only one method may be used to authenticate at a time (Auth header, ' +
'GET or POST).'));
return next(new error.BadMethodError('Only one method may be used to authenticate at a time (Auth header, GET or POST).'));
} else if (methodsUsed === 0) {
return done(error('invalid_request', 'The access token was not found'));
return next(new error.InvalidCredentialsError('The access token was not found'));
}

// Header: http://tools.ietf.org/html/rfc6750#section-2.1
if (headerToken) {
var matches = headerToken.match(/Bearer\s(\S+)/);
if (headerToken && headerToken.credentials) {
var matches = (headerToken.scheme === 'Bearer') ? headerToken.credentials : null;

if (!matches) {
return done(error('invalid_request', 'Malformed auth header'));
return next(new error.InvalidHeaderError('Malformed auth header'));
}

headerToken = matches[1];
headerToken = matches;
} else {
headerToken = undefined;
}

// POST: http://tools.ietf.org/html/rfc6750#section-2.2
if (postToken) {
if (this.req.method === 'GET') {
return done(error('invalid_request',
'Method cannot be GET When putting the token in the body.'));
return next(new error.BadMethodError('Method cannot be GET When putting the token in the body.'));
}

if (!this.req.is('application/x-www-form-urlencoded')) {
return done(error('invalid_request', 'When putting the token in the ' +
'body, content type must be application/x-www-form-urlencoded.'));
return next(new error.BadMethodError('When putting the token in the ' +
'body, content type must be application/x-www-form-urlencoded.'));
}
}

this.bearerToken = headerToken || postToken || getToken;
done();
next();
}

/**
* Check token
*
* Check it against model, ensure it's not expired
* @param {Function} done
* @param {Function} next
* @this OAuth
*/
function checkToken (done) {
function checkToken (next) {
var self = this;
this.model.getAccessToken(this.bearerToken, function (err, token) {
if (err) return done(error('server_error', false, err));

if (!token) {
return done(error('invalid_token',
'The access token provided is invalid.'));
}
if (this.model && Object.keys(this.model).length > 0) {
this.model.getAccessToken(this.bearerToken, function (err, token) {
if (err) return next(new error.InternalError(err));

if (token.expires !== null &&
(!token.expires || token.expires < new Date())) {
return done(error('invalid_token',
'The access token provided has expired.'));
}
if (!token) {
return next(new error.InvalidCredentialsError('The access token provided is invalid.'));
}

// Expose params
self.req.oauth = { bearerToken: token };
self.req.user = token.user ? token.user : { id: token.userId };
if (token.expires !== null &&
(!token.expires || token.expires < new Date())) {
return next(new error.InvalidCredentialsError('The access token provided has expired.'));
}

done();
});
// Expose params
self.req.oauth = {bearerToken: token};
self.req.user = token.user ? token.user : {id: token.userId};

next();
});
} else {
next(new error.InvalidCredentialsError('The access token can not be find.'));
}
}
Loading