From f378a67ebf0036169c776cc11b46defd375693f0 Mon Sep 17 00:00:00 2001 From: caub Date: Wed, 28 Aug 2019 10:48:58 +0200 Subject: [PATCH] Add challengeType option --- README.md | 17 +++++++++++++++++ lib/passport-http/strategies/basic.js | 23 ++++++++++++----------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 6c72714..ee7c531 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,23 @@ credentials and calls `done` providing a user. } )); +##### Avoid Basic Auth dialogs on XHR requests + +Browsers such as Safari intercept `401 Unauthorized` responses with the `Basic` challenge. In client side apps using XHR requests this creates a browser authorization dialog. To work around this you can pass the `challengeType` option. This will set a different challenge type and avoid the popup dialog on XHR requests, letting you handle the error in your own code. For example: + + passport.use(new BasicStrategy( + { challengeType: 'xBasic' }, + function(userid, password, done) { + User.findOne({ username: userid }, function (err, user) { + if (err) { return done(err); } + if (!user) { return done(null, false); } + if (!user.verifyPassword(password)) { return done(null, false); } + return done(null, user); + }); + } + )); + + #### Authenticate Requests Use `passport.authenticate()`, specifying the `'basic'` strategy, to diff --git a/lib/passport-http/strategies/basic.js b/lib/passport-http/strategies/basic.js index a1f251c..da12a04 100644 --- a/lib/passport-http/strategies/basic.js +++ b/lib/passport-http/strategies/basic.js @@ -44,9 +44,10 @@ function BasicStrategy(options, verify) { options = {}; } if (!verify) throw new Error('HTTP Basic authentication strategy requires a verify function'); - + passport.Strategy.call(this); this.name = 'basic'; + this._challengeType = options.challengeType || 'Basic'; this._verify = verify; this._realm = options.realm || 'Users'; this._passReqToCallback = options.passReqToCallback; @@ -64,33 +65,33 @@ util.inherits(BasicStrategy, passport.Strategy); * @param {Object} req * @api protected */ -BasicStrategy.prototype.authenticate = function(req) { +BasicStrategy.prototype.authenticate = function (req) { var authorization = req.headers['authorization']; if (!authorization) { return this.fail(this._challenge()); } - + var parts = authorization.split(' ') if (parts.length < 2) { return this.fail(400); } - + var scheme = parts[0] , credentials = new Buffer(parts[1], 'base64').toString().split(':'); if (!/Basic/i.test(scheme)) { return this.fail(this._challenge()); } if (credentials.length < 2) { return this.fail(400); } - + var userid = credentials[0]; var password = credentials[1]; if (!userid || !password) { return this.fail(this._challenge()); } - + var self = this; - + function verified(err, user) { if (err) { return self.error(err); } if (!user) { return self.fail(self._challenge()); } self.success(user); } - + if (self._passReqToCallback) { this._verify(req, userid, password, verified); } else { @@ -103,12 +104,12 @@ BasicStrategy.prototype.authenticate = function(req) { * * @api private */ -BasicStrategy.prototype._challenge = function() { - return 'Basic realm="' + this._realm + '"'; +BasicStrategy.prototype._challenge = function () { + return this._challengeType + ' realm="' + this._realm + '"'; } /** * Expose `BasicStrategy`. - */ + */ module.exports = BasicStrategy;