163 lines
4.3 KiB
JavaScript
163 lines
4.3 KiB
JavaScript
/**
|
|
* Module dependencies.
|
|
*/
|
|
var passport = require('passport-strategy')
|
|
, util = require('util');
|
|
|
|
|
|
/**
|
|
* Creates an instance of `Strategy`.
|
|
*
|
|
* The HTTP Bearer authentication strategy authenticates requests based on
|
|
* a bearer token contained in the `Authorization` header field, `access_token`
|
|
* body parameter, or `access_token` query parameter.
|
|
*
|
|
* Applications must supply a `verify` callback, for which the function
|
|
* signature is:
|
|
*
|
|
* function(token, done) { ... }
|
|
*
|
|
* `token` is the bearer token provided as a credential. The verify callback
|
|
* is responsible for finding the user who posesses the token, and invoking
|
|
* `done` with the following arguments:
|
|
*
|
|
* done(err, user, info);
|
|
*
|
|
* If the token is not valid, `user` should be set to `false` to indicate an
|
|
* authentication failure. Additional token `info` can optionally be passed as
|
|
* a third argument, which will be set by Passport at `req.authInfo`, where it
|
|
* can be used by later middleware for access control. This is typically used
|
|
* to pass any scope associated with the token.
|
|
*
|
|
* Options:
|
|
*
|
|
* - `realm` authentication realm, defaults to "Users"
|
|
* - `scope` list of scope values indicating the required scope of the access
|
|
* token for accessing the requested resource
|
|
*
|
|
* Examples:
|
|
*
|
|
* passport.use(new BearerStrategy(
|
|
* function(token, done) {
|
|
* User.findByToken({ token: token }, function (err, user) {
|
|
* if (err) { return done(err); }
|
|
* if (!user) { return done(null, false); }
|
|
* return done(null, user, { scope: 'read' });
|
|
* });
|
|
* }
|
|
* ));
|
|
*
|
|
* For further details on HTTP Bearer authentication, refer to [The OAuth 2.0 Authorization Protocol: Bearer Tokens](http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer)
|
|
*
|
|
* @constructor
|
|
* @param {Object} [options]
|
|
* @param {Function} verify
|
|
* @api public
|
|
*/
|
|
function Strategy(options, verify) {
|
|
if (typeof options == 'function') {
|
|
verify = options;
|
|
options = {};
|
|
}
|
|
if (!verify) { throw new TypeError('HTTPBearerStrategy requires a verify callback'); }
|
|
|
|
passport.Strategy.call(this);
|
|
this.name = 'bearer';
|
|
this._verify = verify;
|
|
this._realm = options.realm || 'Users';
|
|
if (options.scope) {
|
|
this._scope = (Array.isArray(options.scope)) ? options.scope : [ options.scope ];
|
|
}
|
|
this._passReqToCallback = options.passReqToCallback;
|
|
}
|
|
|
|
/**
|
|
* Inherit from `passport.Strategy`.
|
|
*/
|
|
util.inherits(Strategy, passport.Strategy);
|
|
|
|
/**
|
|
* Authenticate request based on the contents of a HTTP Bearer authorization
|
|
* header, body parameter, or query parameter.
|
|
*
|
|
* @param {Object} req
|
|
* @api protected
|
|
*/
|
|
Strategy.prototype.authenticate = function(req) {
|
|
var token;
|
|
|
|
if (req.headers && req.headers.authorization) {
|
|
var parts = req.headers.authorization.split(' ');
|
|
if (parts.length == 2) {
|
|
var scheme = parts[0]
|
|
, credentials = parts[1];
|
|
|
|
if (/^Bearer$/i.test(scheme)) {
|
|
token = credentials;
|
|
}
|
|
} else {
|
|
return this.fail(400);
|
|
}
|
|
}
|
|
|
|
if (req.body && req.body.access_token) {
|
|
if (token) { return this.fail(400); }
|
|
token = req.body.access_token;
|
|
}
|
|
|
|
if (req.query && req.query.access_token) {
|
|
if (token) { return this.fail(400); }
|
|
token = req.query.access_token;
|
|
}
|
|
|
|
if (!token) { return this.fail(this._challenge()); }
|
|
|
|
var self = this;
|
|
|
|
function verified(err, user, info) {
|
|
if (err) { return self.error(err); }
|
|
if (!user) {
|
|
if (typeof info == 'string') {
|
|
info = { message: info }
|
|
}
|
|
info = info || {};
|
|
return self.fail(self._challenge('invalid_token', info.message));
|
|
}
|
|
self.success(user, info);
|
|
}
|
|
|
|
if (self._passReqToCallback) {
|
|
this._verify(req, token, verified);
|
|
} else {
|
|
this._verify(token, verified);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Build authentication challenge.
|
|
*
|
|
* @api private
|
|
*/
|
|
Strategy.prototype._challenge = function(code, desc, uri) {
|
|
var challenge = 'Bearer realm="' + this._realm + '"';
|
|
if (this._scope) {
|
|
challenge += ', scope="' + this._scope.join(' ') + '"';
|
|
}
|
|
if (code) {
|
|
challenge += ', error="' + code + '"';
|
|
}
|
|
if (desc && desc.length) {
|
|
challenge += ', error_description="' + desc + '"';
|
|
}
|
|
if (uri && uri.length) {
|
|
challenge += ', error_uri="' + uri + '"';
|
|
}
|
|
|
|
return challenge;
|
|
};
|
|
|
|
|
|
/**
|
|
* Expose `Strategy`.
|
|
*/
|
|
module.exports = Strategy;
|