node-oauth2-server
Advanced tools
Comparing version 2.2.2 to 2.4.0
## Changelog | ||
### 2.4.0 | ||
- Set Cache-Control and Pragma headers | ||
- Allow any valid URI for extension grants | ||
- Expose `client` to `extendedGrant` and after via `req.oauth.client` | ||
- Fix express depreciation warning for `res.send()` | ||
- Expose `user` to `generateToken` and after via `req.user` | ||
- Fix lockdown pattern for express 3 | ||
- Add redis example | ||
- Fix docs to use new express bodyParser module | ||
- Fix docs for `redirect_uri` | ||
- Clarify docs for `clientIdRegex` | ||
- Fix docs for missing `req` argument in `generateToken` | ||
- Fix docs for `user`/`userId` `getAccessToken` | ||
- Fix docs for argument order in `getRefreshToken` | ||
### 2.3.0 | ||
- Support "state" param for auth_code grant type | ||
- Docs for client_credentials grant type | ||
- Fix `getRefreshToken` in postgres model example | ||
### 2.2.2 | ||
@@ -4,0 +27,0 @@ |
var express = require('express'), | ||
bodyParser = require('body-parser'), | ||
oauthserver = require('../../'); // Would be: 'node-oauth2-server' | ||
oauthserver = require('../../'); // Would be: 'oauth2-server' | ||
var app = express(); | ||
app.use(bodyParser()); | ||
app.use(bodyParser.urlencoded({ extended: true })); | ||
app.use(bodyParser.json()); | ||
app.oauth = oauthserver({ | ||
@@ -10,0 +12,0 @@ model: require('./model'), |
@@ -27,3 +27,3 @@ /** | ||
// | ||
// node-oauth2-server callbacks | ||
// oauth2-server callbacks | ||
// | ||
@@ -30,0 +30,0 @@ model.getAccessToken = function (bearerToken, callback) { |
@@ -66,3 +66,3 @@ var model = module.exports; | ||
if(elem.clientId === clientId && | ||
(clientSecret === null || elem.client_secret === clientSecret)) { | ||
(clientSecret === null || elem.clientSecret === clientSecret)) { | ||
return callback(false, elem); | ||
@@ -69,0 +69,0 @@ } |
@@ -63,3 +63,3 @@ /** | ||
// | ||
// node-oauth2-server callbacks | ||
// oauth2-server callbacks | ||
// | ||
@@ -112,3 +112,6 @@ model.getAccessToken = function (bearerToken, callback) { | ||
OAuthUsersModel.findOne({ username: username, password: password }, callback); | ||
OAuthUsersModel.findOne({ username: username, password: password }, function(err, user) { | ||
if(err) return callback(err); | ||
callback(null, user._id); | ||
}); | ||
}; | ||
@@ -115,0 +118,0 @@ |
var express = require('express'), | ||
bodyParser = require('body-parser'), | ||
oauthserver = require('../../'); // Would be: 'node-oauth2-server' | ||
oauthserver = require('../../'); // Would be: 'oauth2-server' | ||
var app = express(); | ||
app.use(bodyParser()); | ||
app.use(bodyParser.urlencoded({ extended: true })); | ||
app.use(bodyParser.json()); | ||
app.oauth = oauthserver({ | ||
@@ -10,0 +12,0 @@ model: require('./model'), |
@@ -104,3 +104,3 @@ /** | ||
model.saveRefreshToken = function (refreshToken, clientId, userId, expires, callback) { | ||
model.saveRefreshToken = function (refreshToken, clientId, expires, userId, callback) { | ||
pg.connect(connString, function (err, client, done) { | ||
@@ -107,0 +107,0 @@ if (err) return callback(err); |
@@ -191,3 +191,4 @@ /** | ||
function redirect (done) { | ||
this.res.redirect(this.client.redirectUri + '?code=' + this.authCode); | ||
this.res.redirect(this.client.redirectUri + '?code=' + this.authCode + | ||
(this.req.query.state ? '&state=' + this.req.query.state : '')); | ||
@@ -194,0 +195,0 @@ if (this.config.continueAfterResponse) |
@@ -43,7 +43,10 @@ /** | ||
this.headers = { | ||
'Cache-Control': 'no-store', | ||
'Pragma': 'no-cache' | ||
}; | ||
switch (error) { | ||
case 'invalid_client': | ||
this.headers = { | ||
'WWW-Authenticate': 'Basic realm="Service"' | ||
}; | ||
this.headers['WWW-Authenticate'] = 'Basic realm="Service"'; | ||
/* falls through */ | ||
@@ -50,0 +53,0 @@ case 'invalid_grant': |
@@ -34,2 +34,3 @@ /** | ||
checkGrantType, | ||
exposeUser, | ||
generateAccessToken, | ||
@@ -135,2 +136,3 @@ saveAccessToken, | ||
function checkClient (done) { | ||
var self = this; | ||
this.model.getClient(this.client.clientId, this.client.clientSecret, | ||
@@ -144,2 +146,5 @@ function (err, client) { | ||
// Expose validated client | ||
self.req.oauth = { client: client }; | ||
done(); | ||
@@ -156,3 +161,4 @@ }); | ||
function checkGrantType (done) { | ||
if (this.grantType.match(/^http(s|):\/\//) && this.model.extendedGrant) { | ||
if (this.grantType.match(/^[a-zA-Z][a-zA-Z0-9+.-]+:/) | ||
&& this.model.extendedGrant) { | ||
return useExtendedGrant.call(this, done); | ||
@@ -350,2 +356,14 @@ } | ||
/** | ||
* Expose user | ||
* | ||
* @param {Function} done | ||
* @this OAuth | ||
*/ | ||
function exposeUser (done) { | ||
this.req.user = this.user; | ||
done(); | ||
} | ||
/** | ||
* Generate an access token | ||
@@ -456,3 +474,6 @@ * | ||
this.res.jsonp(response); | ||
this.res | ||
.set('Cache-Control', 'no-store') | ||
.set('Pragma', 'no-cache') | ||
.jsonp(response); | ||
@@ -459,0 +480,0 @@ if (this.config.continueAfterResponse) |
@@ -70,3 +70,3 @@ /** | ||
return function (req, res, next) { | ||
new Authorise(self, req, next); | ||
return new Authorise(self, req, next); | ||
}; | ||
@@ -131,3 +131,3 @@ }; | ||
res.send(err.code, err); | ||
res.status(err.code).send(err); | ||
}; | ||
@@ -218,3 +218,5 @@ }; | ||
for (var method in app.routes) { | ||
app.routes[method].callbacks.forEach(lockdownExpress3); | ||
app.routes[method].forEach(function (route) { | ||
lockdownExpress3(route.callbacks); | ||
}); | ||
} | ||
@@ -221,0 +223,0 @@ } else { |
{ | ||
"name": "node-oauth2-server", | ||
"description": "Complete, compliant and well tested module for implementing an OAuth2 Server/Provider with express in node.js", | ||
"version": "2.2.2", | ||
"version": "2.4.0", | ||
"keywords": [ | ||
@@ -44,4 +44,4 @@ "oauth", | ||
"type": "git", | ||
"url": "https://github.com/nightworld/node-oauth2-server.git" | ||
"url": "https://github.com/thomseddon/node-oauth2-server.git" | ||
} | ||
} |
@@ -8,3 +8,3 @@ # 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) | ||
``` | ||
npm install node-oauth2-server | ||
npm install oauth2-server | ||
``` | ||
@@ -19,8 +19,10 @@ | ||
bodyParser = require('body-parser'), | ||
oauthserver = require('node-oauth2-server'); | ||
oauthserver = require('oauth2-server'); | ||
var app = express(); | ||
app.use(bodyParser()); // REQUIRED | ||
app.use(bodyParser.urlencoded({ extended: true })); | ||
app.use(bodyParser.json()); | ||
app.oauth = oauthserver({ | ||
@@ -61,3 +63,3 @@ model: {}, // See below for specification | ||
- *function|boolean* **debug** | ||
- If `true` errors will be logged to console. You may also pass a custom function, in which case that function will be called with the error as it's first argument | ||
- If `true` errors will be logged to console. You may also pass a custom function, in which case that function will be called with the error as its first argument | ||
- Default: `false` | ||
@@ -76,4 +78,4 @@ - *number* **accessTokenLifetime** | ||
- *regexp* **clientIdRegex** | ||
- Regex to match auth codes against before checking model | ||
- Default: `/^[a-z0-9-_]{3,40}$/i` | ||
- Regex to sanity check client id against before checking model. Note: the default just matches common `client_id` structures, change as needed | ||
- Default: `/^[a-z0-9-_]{3,40}$/i` | ||
- *boolean* **passthroughErrors** | ||
@@ -105,4 +107,5 @@ - If true, **non grant** errors will not be handled internally (so you can ensure a consistent format with the rest of your api) | ||
- `null` to indicate the token **never expires** | ||
- *string|number* **userId** | ||
- The user id (saved in req.user.id) | ||
- *mixed* **user** *or* *string|number* **userId** | ||
- If a `user` key exists, this is saved as `req.user` | ||
- Otherwise a `userId` key must exist, which is saved in `req.user.id` | ||
@@ -121,2 +124,3 @@ #### getClient (clientId, clientSecret, callback) | ||
- *string* **clientId** | ||
- *string* **redirectUri** (`authorization_code` grant type only) | ||
@@ -197,4 +201,4 @@ #### grantTypeAllowed (clientId, grantType, callback) | ||
- *string* **refreshToken** | ||
- The bearer token (access token) that has been provided | ||
- *function* **callback (error, accessToken)** | ||
- The bearer token (refresh token) that has been provided | ||
- *function* **callback (error, refreshToken)** | ||
- *mixed* **error** | ||
@@ -225,3 +229,5 @@ - Truthy to indicate an error | ||
#### extendedGrant (req, callback) | ||
#### extendedGrant (grantType, req, callback) | ||
- *string* **grantType** | ||
- The (custom) grant type | ||
- *object* **req** | ||
@@ -240,7 +246,24 @@ - The raw request | ||
### Required for `client_credentials` grant type | ||
#### getUserFromClient (clientId, clientSecret, callback) | ||
- *string* **clientId** | ||
- *string* **clientSecret** | ||
- *function* **callback (error, user)** | ||
- *mixed* **error** | ||
- Truthy to indicate an error | ||
- *object* **user** | ||
- The user retrieved from storage or falsey to indicate an invalid user | ||
- Saved in `req.user` | ||
- Must contain the following keys: | ||
- *string|number* **id** | ||
### Optional | ||
#### generateToken (type, callback) | ||
#### generateToken (type, req, callback) | ||
- *string* **type** | ||
- `accessToken` or `refreshToken` | ||
- *object* **req** | ||
- The current express request | ||
- *function* **callback (error, token)** | ||
@@ -258,4 +281,4 @@ - *mixed* **error** | ||
You can support extension/custom grants by implementing the extendedGrant method as outlined above. | ||
Any requests that begin with http(s):// (as [defined in the spec](http://tools.ietf.org/html/rfc6749#section-4.5)) will be passed to it for you to handle. | ||
You can access the grant type via req.oauth.grantType and you should pass back supported as `false` if you do not support it to ensure a consistent (and compliant) response. | ||
Any grant type that is a valid URI will be passed to it for you to handle (as [defined in the spec](http://tools.ietf.org/html/rfc6749#section-4.5)). | ||
You can access the grant type via the first argument and you should pass back supported as `false` if you do not support it to ensure a consistent (and compliant) response. | ||
@@ -262,0 +285,0 @@ ## Example using the `password` grant type |
@@ -293,2 +293,33 @@ /** | ||
it('should accept valid request and return code and state using GET', function (done) { | ||
var code; | ||
var app = bootstrap({ | ||
getClient: function (clientId, clientSecret, callback) { | ||
callback(false, { | ||
clientId: 'thom', | ||
redirectUri: 'http://nightworld.com' | ||
}); | ||
}, | ||
saveAuthCode: function (authCode, clientId, expires, user, callback) { | ||
should.exist(authCode); | ||
code = authCode; | ||
callback(); | ||
} | ||
}, [false, true]); | ||
request(app) | ||
.get('/authorise') | ||
.query({ | ||
response_type: 'code', | ||
client_id: 'thom', | ||
redirect_uri: 'http://nightworld.com', | ||
state: 'some_state' | ||
}) | ||
.expect(302, function (err, res) { | ||
res.header.location.should.equal('http://nightworld.com?code=' + code + '&state=some_state'); | ||
done(); | ||
}); | ||
}); | ||
it('should continue after success response if continueAfterResponse = true', function (done) { | ||
@@ -295,0 +326,0 @@ var app = bootstrap({ |
@@ -31,6 +31,19 @@ var should = require('should'); | ||
it('should expose `headers` if error is `invalid_client`', function () { | ||
it('should set cache `headers`', function () { | ||
var error = new OAuth2Error('invalid_request'); | ||
error.headers.should.eql({ | ||
'Cache-Control': 'no-store', | ||
'Pragma': 'no-cache' | ||
}); | ||
}); | ||
it('should include WWW-Authenticate `header` if error is `invalid_client`', function () { | ||
var error = new OAuth2Error('invalid_client'); | ||
error.headers.should.eql({ 'WWW-Authenticate': 'Basic realm="Service"' }); | ||
error.headers.should.eql({ | ||
'Cache-Control': 'no-store', | ||
'Pragma': 'no-cache', | ||
'WWW-Authenticate': 'Basic realm="Service"' | ||
}); | ||
}); | ||
@@ -37,0 +50,0 @@ |
@@ -124,3 +124,3 @@ /** | ||
getClient: function (id, secret, callback) { | ||
callback(false, true); | ||
callback(false, { clientId: 'thom', clientSecret: 'nightworld' }); | ||
}, | ||
@@ -131,7 +131,9 @@ grantTypeAllowed: function (clientId, grantType, callback) { | ||
extendedGrant: function (grantType, req, callback) { | ||
req.oauth.client.clientId.should.equal('thom'); | ||
req.oauth.client.clientSecret.should.equal('nightworld'); | ||
callback(false, true, { id: 3 }); | ||
}, | ||
saveAccessToken: function () { | ||
done(); // That's enough | ||
} | ||
saveAccessToken: function (token, clientId, expires, user, cb) { | ||
cb(); | ||
}, | ||
}, | ||
@@ -151,2 +153,32 @@ grants: ['http://custom.com'] | ||
}); | ||
it('should allow any valid URI valid request', function (done) { | ||
var app = bootstrap({ | ||
model: { | ||
getClient: function (id, secret, callback) { | ||
callback(false, true); | ||
}, | ||
grantTypeAllowed: function (clientId, grantType, callback) { | ||
callback(false, true); | ||
}, | ||
extendedGrant: function (grantType, req, callback) { | ||
callback(false, true, { id: 3 }); | ||
}, | ||
saveAccessToken: function (token, clientId, expires, user, cb) { | ||
cb(); | ||
}, | ||
}, | ||
grants: ['urn:custom:grant'] | ||
}); | ||
request(app) | ||
.post('/oauth/token') | ||
.set('Content-Type', 'application/x-www-form-urlencoded') | ||
.send({ | ||
grant_type: 'urn:custom:grant', | ||
client_id: 'thom', | ||
client_secret: 'nightworld' | ||
}) | ||
.expect(200, done); | ||
}); | ||
}); |
@@ -255,2 +255,36 @@ /** | ||
it('should include client and user in request', function (done) { | ||
var app = bootstrap({ | ||
model: { | ||
getClient: function (id, secret, callback) { | ||
callback(false, { clientId: 'thom', clientSecret: 'nightworld' }); | ||
}, | ||
grantTypeAllowed: function (clientId, grantType, callback) { | ||
callback(false, true); | ||
}, | ||
getUser: function (uname, pword, callback) { | ||
callback(false, { id: 1 }); | ||
}, | ||
generateToken: function (type, req, callback) { | ||
req.oauth.client.clientId.should.equal('thom'); | ||
req.oauth.client.clientSecret.should.equal('nightworld'); | ||
req.user.id.should.equal(1); | ||
callback(false, 'thommy'); | ||
}, | ||
saveAccessToken: function (token, clientId, expires, user, cb) { | ||
token.should.equal('thommy'); | ||
cb(); | ||
} | ||
}, | ||
grants: ['password'] | ||
}); | ||
request(app) | ||
.post('/oauth/token') | ||
.set('Content-Type', 'application/x-www-form-urlencoded') | ||
.send(validBody) | ||
.expect(200, /thommy/, done); | ||
}); | ||
it('should reissue if model returns object', function (done) { | ||
@@ -381,2 +415,4 @@ var app = bootstrap({ | ||
.expect(200) | ||
.expect('Cache-Control', 'no-store') | ||
.expect('Pragma', 'no-cache') | ||
.end(function (err, res) { | ||
@@ -423,2 +459,4 @@ if (err) return done(err); | ||
.expect(200) | ||
.expect('Cache-Control', 'no-store') | ||
.expect('Pragma', 'no-cache') | ||
.end(function (err, res) { | ||
@@ -425,0 +463,0 @@ if (err) return done(err); |
@@ -23,2 +23,3 @@ /** | ||
var oauth2server = require('../'); | ||
var Authorise = require('../lib/authorise'); | ||
@@ -90,2 +91,46 @@ var bootstrap = function (oauthConfig) { | ||
}); | ||
describe('in express 3', function () { | ||
var app, privateAction, publicAction; | ||
beforeEach(function () { | ||
privateAction = function () {}; | ||
publicAction = function () {}; | ||
// mock express 3 app | ||
app = { | ||
routes: { get: [] } | ||
}; | ||
app.oauth = oauth2server({ model: {} }); | ||
app.routes.get.push({ callbacks: [ privateAction ] }); | ||
app.routes.get.push({ callbacks: [ app.oauth.bypass, publicAction ] }) | ||
app.oauth.lockdown(app); | ||
}); | ||
function mockRequest(authoriseFactory) { | ||
var req = { | ||
get: function () {}, | ||
query: { access_token: { expires: null } } | ||
}; | ||
var next = function () {}; | ||
app.oauth.model.getAccessToken = function (t, c) { c(null, t); }; | ||
return authoriseFactory(req, null, next); | ||
} | ||
it('adds authorise to non-bypassed routes', function () { | ||
var authorise = mockRequest(app.routes.get[0].callbacks[0]); | ||
authorise.should.be.an.instanceOf(Authorise); | ||
}); | ||
it('runs non-bypassed routes after authorise', function () { | ||
app.routes.get[0].callbacks[1].should.equal(privateAction); | ||
}); | ||
it('removes oauth.bypass from bypassed routes', function () { | ||
app.routes.get[1].callbacks[0].should.equal(publicAction); | ||
}); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
160977
42
3857
325