Code Monkey home page Code Monkey logo

passport-http's Introduction

Passport-HTTP

HTTP Basic and Digest authentication strategies for Passport.

This module lets you authenticate HTTP requests using the standard basic and digest schemes in your Node.js applications. By plugging into Passport, support for these schemes can be easily and unobtrusively integrated into any application or framework that supports Connect-style middleware, including Express.

❤️ Sponsors


Advertisement
Node.js, Express, MongoDB & More: The Complete Bootcamp 2020
Master Node by building a real-world RESTful API and web app (with authentication, Node.js security, payments & more)


npm build coverage ...

Install

$ npm install passport-http

Usage of HTTP Basic

Configure Strategy

The HTTP Basic authentication strategy authenticates users using a userid and password. The strategy requires a verify callback, which accepts these credentials and calls done providing a user.

passport.use(new BasicStrategy(
  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 authenticate requests. Requests containing an 'Authorization' header do not require session support, so the session option can be set to false.

For example, as route middleware in an Express application:

app.get('/private', 
  passport.authenticate('basic', { session: false }),
  function(req, res) {
    res.json(req.user);
  });

Examples

For a complete, working example, refer to the Basic example.

Usage of HTTP Digest

Configure Strategy

The HTTP Digest authentication strategy authenticates users using a username and password (aka shared secret). The strategy requires a secret callback, which accepts a username and calls done providing a user and password known to the server. The password is used to compute a hash, and authentication fails if it does not match that contained in the request.

The strategy also accepts an optional validate callback, which receives nonce-related params that can be further inspected to determine if the request is valid.

passport.use(new DigestStrategy({ qop: 'auth' },
  function(username, done) {
    User.findOne({ username: username }, function (err, user) {
      if (err) { return done(err); }
      if (!user) { return done(null, false); }
      return done(null, user, user.password);
    });
  },
  function(params, done) {
    // validate nonces as necessary
    done(null, true)
  }
));

Authenticate Requests

Use passport.authenticate(), specifying the 'digest' strategy, to authenticate requests. Requests containing an 'Authorization' header do not require session support, so the session option can be set to false.

For example, as route middleware in an Express application:

app.get('/private', 
  passport.authenticate('digest', { session: false }),
  function(req, res) {
    res.json(req.user);
  });

Examples

For a complete, working example, refer to the Digest example.

License

The MIT License

Copyright (c) 2011-2013 Jared Hanson <http://jaredhanson.net/>

passport-http's People

Contributors

awick avatar jaredhanson avatar jrtc27 avatar julson avatar sameersegal avatar

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  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  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  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

passport-http's Issues

Document digest nonce validation callback

There is no example for DigestStrategy's nonce validation callback right now, which makes it difficult to understand how complete the module's implementation is and if we're less secure if we don't supply such a callback. Also, we don't know what we should actually be doing in that callback, because the only example just returns true.

  • Around line 182 of lib/passport-http/strategies/digest.js we see that if a validation callback wasn't provided, success is implied, so it appears that some extra verification can be added by this?
  • In the JSDoc, it's unclear whether params.opaque now will become params.nonce later or if they're two different concepts.
  • Internal function nonce() does seem to generate something unique, so I speculate that we might be safe against replays without a custom validation callback, but it's just an educated guess.

Password not required

Some APIs (including mine!) use HTTP Basic Auth, but read the username as an API token and ignore the password field. Notably, Stripe does this. It would be great to have the ability to pass a passwordRequired option, which defaults to true to preserve backwards compatability, but that can be set to false to disable the requirement.

From this:

var userid = credentials[0];
var password = credentials[1];
if (!userid || !password) {
    return this.fail(this._challenge());
}

To this:

var userid = credentials[0];
var password = credentials[1];
if (!userid || (options.passwordRequired && !password)) {
    return this.fail(this._challenge());
}

I'm happy to submit a pull request

Basic & Digest authentication not working for some reason...

Hi There,

I have been using Passport for numerous years now. In the current platform that I run, I use Passport's local strategy for authentication. This has been working fine for several months.

Today, I added a new Basic Strategy authentication system to the mix. This is completely separate from the standard Local Strategy that already exists.

My code is as follows:

  var basic = require('passport-http').BasicStrategy;

  passport.use(new basic({},
    function(username, password, done) {
      console.log('here we are');
    }
  ));

and the following is part of a different function

    if(path == '/the/correct/path'){
      console.log('OUTSIDE AUTH');
      passport.authenticate('basic', { session: false }, function(req, res){
        console.log('INSIDE AUTH');
      });
    }

When I make a request to /the/correct/path, OUTSIDE AUTH gets printed properly. However, I then expect here we are from the passport.use() function to get printed, which it never. I'm really frustrated, as I have no idea how this is supposed to work...

I have tried accessing this via browser, via curl calls (as per the example), using older & newer versions of the module, and using the DigestStrategy instead of the BasicStrategy. Any advice on what to do would be greatly appreciated... Also I am NOT using express if that makes a difference at all...

Best, and thanks either way,
Sami

Example for mixing Basic & Local strategies

Hello,

This is not really an issue but is there a way to mix both Basic HTTP and Local passport strategies? The reason is that I would like to use Basic for easy testing with supertest (using request(app).auth()), and some clients which are totally restful otherwise a simple login form using the Local POST strategy.

In essence, I want to apply a middleware routine using app.use('*', ensureAuthenticated, ...), where ensureAuthenticated checks if the session exists and is authenticated or the http credentials are provided).

The other examples of mixing twitter, oath and other passport strategies does not really apply since they are all based on mapping disctinct routes whereas stateless auth like basic and digest authenticate at every request.

Thanks for any advice,

Nicolas

Custom error code

Hi,
any way to send custom error codes? Something like

passport.use(new BasicStrategy(
  function(userid, password, done) {
    User.findOne({ username: userid }, function (err, user) {
      if (err) { return done(err); }
      if (!user) { return done(null, false,401); }
      if (!user.verifyPassword(password)) { return done(null, false,403); }
      return done(null, user);
    });
  }
));

so for example

  • !user => 401
  • incorrect password => 403

Any clue?

Thank you

Future of this project

Given this project appears to be abandoned, is there any good alternatives or are we able to get more contributors added so we can merge the many pull requests (often fixing the same bugs)

Info in authenticate callback.

This is strange:

passport.authenticate('basic', function(err, user, info) {
    console.log("info is: " + util.inspect(info));
}

Maybe info isn't being passed because it outputs: 'Basic realm="Users"' and when I change info param to anything else if fails silently.

PLEASE NOMINATE MAINTAINERS

@jaredhanson

This is a great library, and there are many awesome PRs waiting to be merged. You obviously need some help to take this library forward, and it seems from discussions in the issues that many want to help.

Don't let this package die, it's heavily used, and so good!

Please nominate one or two people to help maintain this? You could maybe choose those with the most PRs, as they would be most familiar with your code base.

Please let us know whether you like/hate this idea?

BasicStrategy not found

There is insufficient documentation to get a working example.

Using the snippet from the README leads to the following error:

/srv/www/routes/v1.js:8
passport.use(new BasicStrategy(
^

ReferenceError: BasicStrategy is not defined
at Object. (/srv/www/routes/v1.js:8:18)
at Module._compile (internal/modules/cjs/loader.js:688:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
at Module.load (internal/modules/cjs/loader.js:598:32)
at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
at Function.Module._load (internal/modules/cjs/loader.js:529:3)
at Module.require (internal/modules/cjs/loader.js:636:17)
at require (internal/modules/cjs/helpers.js:20:18)
at Object. (/srv/www/server.js:11:12)
at Module._compile (internal/modules/cjs/loader.js:688:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:699:10)
at Module.load (internal/modules/cjs/loader.js:598:32)
at tryModuleLoad (internal/modules/cjs/loader.js:537:12)
at Function.Module._load (internal/modules/cjs/loader.js:529:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:741:12)
at startup (internal/bootstrap/node.js:285:19)

How to custom fail page?

I try to use:

app.get('/login'
passport.authenticate('digest', { session: false,failureRedirect: '/login',
successRedirect: '/' })
);

web browser throws 302 statuscode when I visit the url.

Response of Basic

I am using basic authentication for authenticating client credentials in Oauth2orize. In my tests I am using a browser based test-client to do the testing. If the credentials are wrong I get the basic form for user and password being opened to submit username and password.

I don't want that...I just want it to return 401. Is this a problem for browser based client only or is this for all clients? If its for all clients How do I avoid it and just return 401.

Digest: How to validate nonces without user?

In the Digest constructor the 1st function passes in the username, which is where you validate the user exists and then pass back the decrypted password. In the 2nd function, you can validate nonces to avoid replay attacks, but the only parameter passed in, beside the done function, is the params object containing the nonce, cnonce, nc, and opaque values.

I'm not sure how we're supposed to determine which user we're dealing within the nonce validation function. I assume the functions are asynchronous, so theoretically if more than one user is authenticating at the same time, I can't assume that the functions will be synchronously called for the same user and save off the user in a static variable somewhere.

Am I missing something? Thanks.

When express app is mounted at non-root endpoint, passport-http returns 400

Mounting an app at a non-root endpoint fails on the uri check because passport-http is only checking the relative uri as seen by the express app, not by the uri as seen by the client.
e.g.

authApp = require('../modules/auth');
app.use('/auth', authApp);

// ../module/auth.js
app.get('/digest', passport.authenticate 'digest');

Seems to always yield 400.

How to login from HTML form?

How to login from HTML form if I'm using passport-http not passport-local since I'm using http is b/c it can be used by postman but now I don't know how to send login request using html form

The html form works fine when I'm using passport-local but since I change to passport-http it does not work

Submitting empty string for username in Digest auth will return a 400, instead of a 401.

Ran into an issue when testing my site with the Digest strategy and using an empty username. It seems that if you put in an empty string for the username then the passport module will return a 400 instead of a 401. From the digest auth spec it appears an empty username is valid and 401 should be returned. This change may seems minor but the 400 really screws up the auth caching in browsers and other HTTP stacks. In Chrome, after the 400, your credentials are now cached and it won't prompt for another user/pass until the cache is cleared (browser restart).

I suggest removing the check for a valid username in digest.js

digest.js:111 - digest:113

/*
if (!creds.username) {
return this.fail(400);
}
*/

Thanks

how to make an ajax call using basic auth

I am trying to use basicauth for ajax cors but the user and the password in the node server passport-http come undefined. What I am missing in here?

app.use(passport.initialize());
app.use(allowCrossDomain);
app.use(app.router);

where allowCrossDomain is for allowing cors requests

 $.ajax
        ({
            type: "POST",
            url: "https://kelvin-new:8000/admin",
            dataType: 'json',
            crossDomain: true,
            async: false,
            username: $("#login#username").val(),
            password: $("#login#password").val(),
            beforeSend: function(xhr){
            xhr.setRequestHeader("Authorization", "Basic " + btoa($("#login#username").val() + ":" + $("#login#password").val()))
            },
            data: '{ "comment" }',
            withCredentials: true,
            done: function (res){
                alert('Thanks for your comment!');
            },
            error: function(error) {
                alert(error.statusText);
            }
        });

User not logged-out when trying to log-in with incorrect password (BasicStrategy)

Steps to reproduce:

  • have a route that requires BasicStrategy and uses session (e.g. /api/login),
  • have a second route (with no authenticate()) that outputs user information from request.user (from session), e.g.: /api/me.
  • log-in using the first route
  • check that you get user information from the second route
  • log-in with incorrect password using the first route
  • you get a 401 / Unauthorized status
  • check the second route: you still get user information from the second route.

Expected result:

  • User is logged-out and one does not get user information from the second route.

I am not sure if this is a bug of BasicStrategy or a "feature" of Passport.js, but I think users should be forcefully logged out when trying to double-login with incorrect credentials.

Depends on passport ~0.1.3

Really rather out of date now. This means that passport-http currently picks up passport#0.1.18.

Suggest we update this to be current.

Session not saved after login using passport-http

Once I am logged in, the req.user is no longer included in any following requests. I using the express-session and the passport session in that order. All I see in the cookie is the connect-sid. I am using the default Memory Store using passport-http. I see that it tries to store the user object session which disappears in any requests following the login.

I am using express 4.X.

"body-parser": "^1.15.1",
"connect-redis": "3.0.2",
"cookie-parser": "^1.4.3",
"express": "4.13.4",
"express-handlebars": "3.0.0",
"express-logger": "0.0.3",
"express-session": "^1.13.0",
"express-static": "^1.1.0",
"fs": "0.0.1-security",
"https": "^1.0.0",
"passport": "0.3.2",
"passport-http": "0.3.0"

Digest: return algorithm in response header

I can see that the DigestStrategy already supports md5-sess

But then why in the response header it is not returned
According to the rfc2617#3.2.1 it would be assumed as md5 always

algorithm
A string indicating a pair of algorithms used to produce the digest
and a checksum. If this is not present it is assumed to be "MD5".
If the algorithm is not understood, the challenge should be ignored
(and a different one used, if there is more than one).

Since this strategy support both md5 and md5-sess, should the response header include both of them
Digest realm="", algorithm="MD5,MD5-sess", nonce="", qop=""

Strategy naming for basic auth

Maybe I'm missing something: I'm trying to implement a service using different 'layers of authentication', to do so I'd like to specify 3 different BasicStrategy. As I understood from an old issue (jaredhanson/passport#50) this is possible for LocalStrategy, but I've been unsuccessfull to do the same for BasicStrategy, since the constructor doesn't allow custom names.

Is there any reason for this asymmetric behaviour between the strategies?

I even tried to instantiate the strategy, then assign a custom name and use it like this:

var adminStrat = new BasicStrategy(.....);

passport.use('admin-strat', adminStrat);
exports.isAdmin = passport.authenticate('admin-strat', { session: false });

BASIC strategy does not support passwords that contain colons

Colons are legal characters in passwords. Because of the way the BASIC strategy splits the BASIC username:password header, passwords containing a colon character fail. Per the following code from basic.js:

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];

you can see that a split(':') on "myusername:my:password" will result in 3 parts instead of the expected 2. Better to use something like:

.split(':').slice(1).join(':')

or a regexp to get the password. Not sure that I can work up a patch before the new year, but reporting the issue now.

Example doesn't protect static routes with passport

This probably isn't a bug, but I want everything on the server to be password protected with basic HTTP authentication. This includes files under the express.static() folder. In the example code provided, none of the static files trigger the passport authentication. How would one do this?

HTTP digest on router

Hello,

I am unable to apply a DigestStrategy to a route defined in a express' Router.

Here's the following snippet. Note the variable use_router.

var handler = function(req, res) {
    res.json({"hello": "world"});
};

if (use_router) {
    var router = express.Router();
    router.get('/', passport.authenticate('digest', {session: false}), handler);
    app.use("/hello", router);
} else {
    app.get('/hello', passport.authenticate('digest', {session: false}), handler);
}

I expected to received {"hello": "world"} if I GET on /hello the right username (any value) and password ("password").

curl -v --user user:password --digest http://localhost:8888/hello

It does when use_router is false, BUT it does not when use_router is true.

I would expect aaplying a DigestStrategy to a route registered in a router to work, but it appears it does not.

Used versions:

  • express: "^4.14.0"
  • passport: "^0.3.2"
  • passport-http: "^0.3.0"

Two different basic strategies

I'm trying to implement two different basic strategies, with two different sets of correct tokens. Right now it looks like the basic strategy hard codes the name to basic, it would be nice if you could set this via options that way you could have multiple basic strategies with different names.

If there is a better way to go about handling this I'd love to hear about it.

cannot logout

I've tried everything from expressjs and connect's logout and logOut and it's just not working.

Sessions in basic auth strategy

Is the session options still applicable in basic auth strategy as I can't see anything in the code that uses this option setting. If not then the documentation is out of date. Thanks.

Request Stream Event can not work with POST mode

hi there, I just occurred a problem now,
( express or restify ) seems could not triggered request stream event anymore
after set a " asynchronous verification "

here is the simple demo which I test.

var express = require('express'),
app = express(),
passport = require('passport'),
BasicStrategy = require('passport-http').BasicStrategy;

var users = [
    { id: 1, username: 'bob', password: 'secret', email: '[email protected]' }
    , { id: 2, username: 'joe', password: 'birthday', email: '[email protected]' }
];

function findByUsername(username, fn) {
    for (var i = 0, len = users.length; i < len; i++) {
        var user = users[i];
        if (user.username === username) {
            return fn(null, user);
        }
    }
    return fn(null, null);
}

passport.use(new BasicStrategy(
    function(username, password, done) {
        process.nextTick(function () {
            findByUsername(username, function(err, user) {
                if (err) { return done(err); }
                if (!user) { return done(null, false); }
                if (user.password != password) { return done(null, false); }
                return done(null, user);
            })
        });
    }));

app.configure(function() {
    app.use(express.logger());
    app.use(passport.initialize());
    app.use(app.router);
});    

app.post('/upload', 
    passport.authenticate('basic', { session: false }),
    function(req, res, next) {

        var dataLength = 0;

        req.on('data', function(chunk) {
            console.log('loading');
            dataLength += chunk.length;

        }).on('end', function() {
            console.log('load end');
            console.log('contentLength: %s', req.headers['content-length']);
            console.log('dataLength:  : %s', dataLength);
            res.send(200);

        }); 
    });

app.listen(8080, function() {
    console.log('server is running');
});

in normal way, the console should print like:

server is running
loading
loading
loading
load end
contentLength: 355968
dataLength: : 355968

(content-length should match with the real data-length which we got)
(but in this simple code, most time can not triggered stream event, or data-length would be loss)

but if use asynchronous verification, console won't print any info from the stream event,
even it would get fail if we try to using req.pipe() to upload the data to amazon s3 by know.
and without asynchronous verification, I can not get account info from mongodb.

is there any way to verify account by asynchronous way and make sure request stream work fine ?
ps: What I Upload is a mp3 file which about 300kbs, I had try this issue with jpg image too.

Add auth info in basic callback

At the moment you are not taking info in basic auth callback. So extra information about authenticated client cannot be passed to req.authInfo object.
I changed code as follows.
this._verify(userid, password, function(err, user, info) {
if (err) { return self.error(err); }
if (!user) { return self.fail(self._challenge()); }
self.success(user, info);
});

I am sure others would also benefit if you change code as above.

Basic auth does not accept Authentication header.

I created a basic authentication example with Express and when I create a Authentication Basic header with {session: false} it still prompts my web browser with a dialog asking for username and password.

server.js

var app = express();
app.use(express.static(__dirname + '/public')); // starting static fileserver
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.use(passport.initialize());

app.get('/v1/test', 
       passport.authenticate('basic', {session: false}),
       function(req, res) {
           res.send('yup. worked.');
       });

I can include more code but this seems to really be all that is required at the moment because I cannot even get to my passport.use(new BasicStrategy....) code because my browser is prompting me for username and password.

So the issue is...the code above creates Basic auth for my server. When I run the code and curl: curl -D- -X GET -H "Authorization: Basic am9lOmpvZ" http://localhost:5000/v1/test I receive 401 Unauthorized but the header should authorize me.

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.