Socket
Socket
Sign inDemoInstall

passport-jwt

Package Overview
Dependencies
15
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.2.1 to 3.0.0

docs/migrating_v1_to_v2.md

12

lib/extract_jwt.js

@@ -9,3 +9,4 @@ "use strict";

var AUTH_HEADER = "authorization",
DEFAULT_AUTH_SCHEME = "JWT";
LEGACY_AUTH_SCHEME = "JWT",
BEARER_AUTH_SCHEME = 'bearer';

@@ -54,2 +55,3 @@

extractors.fromAuthHeaderWithScheme = function (auth_scheme) {
var auth_scheme_lower = auth_scheme.toLowerCase();
return function (request) {

@@ -60,3 +62,3 @@

var auth_params = auth_hdr.parse(request.headers[AUTH_HEADER]);
if (auth_params && auth_scheme === auth_params.scheme) {
if (auth_params && auth_scheme_lower === auth_params.scheme.toLowerCase()) {
token = auth_params.value;

@@ -71,4 +73,4 @@ }

extractors.fromAuthHeader = function () {
return extractors.fromAuthHeaderWithScheme(DEFAULT_AUTH_SCHEME);
extractors.fromAuthHeaderAsBearerToken = function () {
return extractors.fromAuthHeaderWithScheme(BEARER_AUTH_SCHEME);
};

@@ -109,3 +111,3 @@

extractors.versionOneCompatibility = function (options) {
var authScheme = options.authScheme || DEFAULT_AUTH_SCHEME,
var authScheme = options.authScheme || LEGACY_AUTH_SCHEME,
bodyField = options.tokenBodyField || 'auth_token',

@@ -112,0 +114,0 @@ queryParam = options.tokenQueryParameterName || 'auth_token';

var passport = require('passport-strategy')
, auth_hdr = require('./auth_header')
, util = require('util')
, url = require('url');
, url = require('url')
, assign = require('./helpers/assign.js');

@@ -12,3 +13,8 @@

* @param options
* secretOrKey: (REQUIRED) String or buffer containing the secret or PEM-encoded public key
* secretOrKey: String or buffer containing the secret or PEM-encoded public key. Required unless secretOrKeyProvider is provided.
* secretOrKeyProvider: callback in the format secretOrKeyProvider(request, rawJwtToken, done)`,
* which should call done with a secret or PEM-encoded public key
* (asymmetric) for the given undecoded jwt token string and request
* combination. done has the signature function done(err, secret).
* REQUIRED unless `secretOrKey` is provided.
* jwtFromRequest: (REQUIRED) Function that accepts a reqeust as the only parameter and returns the either JWT as a string or null

@@ -28,4 +34,14 @@ * issuer: If defined issuer will be verified against this value

this._secretOrKey = options.secretOrKey;
if (!this._secretOrKey) {
this._secretOrKeyProvider = options.secretOrKeyProvider;
if (options.secretOrKey) {
if (this._secretOrKeyProvider) {
throw new TypeError('JwtStrategy has been given both a secretOrKey and a secretOrKeyProvider');
}
this._secretOrKeyProvider = function (request, rawJwtToken, done) {
done(null, options.secretOrKey)
};
}
if (!this._secretOrKeyProvider) {
throw new TypeError('JwtStrategy requires a secret or key');

@@ -45,21 +61,14 @@ }

this._passReqToCallback = options.passReqToCallback;
this._verifOpts = {};
var jsonWebTokenOptions = options.jsonWebTokenOptions || {};
//for backwards compatibility, still allowing you to pass
//audience / issuer / algorithms / ignoreExpiration
//on the options.
this._verifOpts = assign({}, jsonWebTokenOptions, {
audience: options.audience,
issuer: options.issuer,
algorithms: options.algorithms,
ignoreExpiration: !!options.ignoreExpiration
});
if (options.issuer) {
this._verifOpts.issuer = options.issuer;
}
if (options.audience) {
this._verifOpts.audience = options.audience;
}
if (options.algorithms) {
this._verifOpts.algorithms = options.algorithms;
}
if (options.ignoreExpiration != null) {
this._verifOpts.ignoreExpiration = options.ignoreExpiration;
}
};
}
util.inherits(JwtStrategy, passport.Strategy);

@@ -93,27 +102,33 @@

// Verify the JWT
JwtStrategy.JwtVerifier(token, this._secretOrKey, this._verifOpts, function(jwt_err, payload) {
if (jwt_err) {
return self.fail(jwt_err);
this._secretOrKeyProvider(req, token, function(secretOrKeyError, secretOrKey) {
if (secretOrKeyError) {
self.fail(secretOrKeyError)
} else {
// Pass the parsed token to the user
var verified = function(err, user, info) {
if(err) {
return self.error(err);
} else if (!user) {
return self.fail(info);
// Verify the JWT
JwtStrategy.JwtVerifier(token, secretOrKey, self._verifOpts, function(jwt_err, payload) {
if (jwt_err) {
return self.fail(jwt_err);
} else {
return self.success(user, info);
}
};
// Pass the parsed token to the user
var verified = function(err, user, info) {
if(err) {
return self.error(err);
} else if (!user) {
return self.fail(info);
} else {
return self.success(user, info);
}
};
try {
if (self._passReqToCallback) {
self._verify(req, payload, verified);
} else {
self._verify(payload, verified);
try {
if (self._passReqToCallback) {
self._verify(req, payload, verified);
} else {
self._verify(payload, verified);
}
} catch(ex) {
self.error(ex);
}
}
} catch(ex) {
self.error(ex);
}
});
}

@@ -120,0 +135,0 @@ });

var jwt = require('jsonwebtoken');
module.exports = function(token, secretOrKey, options, callback) {
module.exports = function(token, secretOrKey, options, callback) {
return jwt.verify(token, secretOrKey, options, callback);
};
{
"name": "passport-jwt",
"version": "2.2.1",
"version": "3.0.0",
"description": "Passport authentication strategy using JSON Web Tokens",

@@ -5,0 +5,0 @@ "main": "./lib",

@@ -6,2 +6,3 @@

[![Build Status](https://travis-ci.org/themikenicholson/passport-jwt.svg?branch=master)](https://travis-ci.org/themikenicholson/passport-jwt)
[![Code Climate](https://codeclimate.com/github/themikenicholson/passport-jwt/badges/gpa.svg)](https://codeclimate.com/github/themikenicholson/passport-jwt)

@@ -29,8 +30,11 @@ A [Passport](http://passportjs.org/) strategy for authenticating with a

* `secretOrKey` is a REQUIRED string or buffer containing the secret
* `secretOrKey` is a string or buffer containing the secret
(symmetric) or PEM-encoded public key (asymmetric) for verifying the token's
signature.
signature. REQUIRED unless `secretOrKeyProvider` is provided.
* `secretOrKeyProvider` is a callback in the format `function secretOrKeyProvider(request, rawJwtToken, done)`,
which should call `done` with a secret or PEM-encoded public key (asymmetric) for the given key and request combination.
`done` accepts arguments in the format `function done(err, secret)`. Note it is up to the implementer to decode rawJwtToken.
REQUIRED unless `secretOrKey` is provided.
* `jwtFromRequest` (REQUIRED) Function that accepts a request as the only
parameter and returns either the JWT as a string or *null*. See
parameter and returns either the JWT as a string or *null*. See
[Extracting the JWT from the request](#extracting-the-jwt-from-the-request) for

@@ -46,2 +50,4 @@ more details.

callback. i.e. verify(request, jwt_payload, done_callback).
* `jsonWebTokenOptions`: passport-jwt is verifying the token using [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken).
Pass here an options object for any other option you can pass the jsonwebtoken verifier. (i.e maxAge)

@@ -55,3 +61,3 @@ `verify` is a function with the parameters `verify(jwt_payload, done)`

An example configuration which reads the JWT from the http
Authorization header with the scheme 'JWT':
Authorization header with the scheme 'bearer':

@@ -62,6 +68,6 @@ ```js

var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeader();
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = 'secret';
opts.issuer = "accounts.examplesoft.com";
opts.audience = "yoursite.net";
opts.issuer = 'accounts.examplesoft.com';
opts.audience = 'yoursite.net';
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {

@@ -73,5 +79,5 @@ User.findOne({id: jwt_payload.sub}, function(err, user) {

if (user) {
done(null, user);
return done(null, user);
} else {
done(null, false);
return done(null, false);
// or you could create a new account

@@ -90,3 +96,3 @@ }

#### Included extractors
#### Included extractors

@@ -104,4 +110,4 @@ A number of extractor factory functions are provided in passport-jwt.ExtractJwt. These factory

authorization header, expecting the scheme to match auth_scheme.
* ```fromAuthHeader()``` creates a new extractor that looks for the JWT in the authorization header
with the scheme 'JWT'
* ```fromAuthHeaderAsBearerToken()``` creates a new extractor that looks for the JWT in the authorization header
with the scheme 'bearer'
* ```fromExtractors([array of extractor functions])``` creates a new extractor using an array of

@@ -113,3 +119,3 @@ extractors provided. Each extractor is attempted in order until one returns a token.

If the supplied extractors don't meet your needs you can easily provide your own callback. For
example, if you are using the cookie-parser middleware and want to extract the JWT in a cookie
example, if you are using the cookie-parser middleware and want to extract the JWT in a cookie
you could use the following function as the argument to the jwtFromRequest option:

@@ -133,3 +139,3 @@

```js
app.post('/profile', passport.authenticate('jwt', { session: false}),
app.post('/profile', passport.authenticate('jwt', { session: false }),
function(req, res) {

@@ -158,43 +164,18 @@ res.send(req.user.profile);

## Migrating from version 1.x.x to 2.x.x
## Migrating from 2.x.x to 3.x.x
The v2 API is not backwards compatible with v1, specifically with regards to the introduction
of the concept of JWT extractor functions. If you require the legacy behavior in v1 you can use
the extractor function ```versionOneCompatibility(options)```
Version 3.0.0 removes the `ExtractJwt.fromAuthHeader()` extractor function that would extract
JWT's from `Authorization` headers with the auth scheme 'jwt'. The default authorization scheme
of 'jwt' as the was not RFC 6750 compliant. The extractor was replaced with
`ExtractJwt.fromAuthHeaderAsBearerToken()`. The removal of `ExtractJwt.fromAuthHeader()` was done
to clearly change the API so any code relying on the old API would clearly break, hopefully saving
people some debugging time.
*options* is an object with any of the three custom JWT extraction options present in the v1
constructor:
* `tokenBodyField`: Field in a request body to search for the JWT.
Default is auth_token.
* `tokenQueryParameterName`: Query parameter name containing the token.
Default is auth_token.
* `authScheme`: Expected authorization scheme if token is submitted through
the HTTP Authorization header. Defaults to JWT
If you want to maintain the behavior of `ExtractJwt.fromAuthHeader()` when switching to v3.3.0, simply
replace it with `ExtractJwt.fromAuthHeaderWithScheme('jwt')` in your implementation.
If in v1 you constructed the strategy like this:
## Migrating from version 1.x.x to 2.x.x
See [the guide for migrating from v1 to v2](docs/migrating_v1_to_v2.md) for explanation of the major changes.
```js
var JwtStrategy = require('passport-jwt').Strategy;
var opts = {}
opts.tokenBodyField = "MY_CUSTOM_BODY_FIELD";
opts.secretOrKey = 'secret';
opts.issuer = "accounts.examplesoft.com";
opts.audience = "yoursite.net";
passport.use(new JwtStrategy(opts, verifyFunction));
```
Identical behavior can be achieved under v2 with the versionOneCompatibility extractor:
```js
var JwtStrategy = require('passport-jwt').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
var opts = {}
opts.jwtFromRequest = ExtractJwt.versionOneCompatibility({ tokenBodyField = "MY_CUSTOM_BODY_FIELD" });
opts.opts.secretOrKey = 'secret';
opts.issuer = "accounts.examplesoft.com";
opts.audience = "yoursite.net";
passport.use(new JwtStrategy(opts, verifyFunction));
```
## Tests

@@ -201,0 +182,0 @@

@@ -24,2 +24,6 @@ var auth_hdr = require('../lib/auth_header')

it('Should return null when the auth header is not a string', function() {
var res = auth_hdr.parse({});
expect(res).to.be.null;
});
});

@@ -133,2 +133,11 @@ var extract_jwt = require('../lib/extract_jwt'),

it('should perform a case-insensivite string comparison', function () {
var req = new Request()
req.headers['authorization'] = 'test_scheme abcd123';
var token = extractor(req);
expect(token).to.equal('abcd123');
});
});

@@ -139,7 +148,7 @@

var extractor = extract_jwt.fromAuthHeader();
var extractor = extract_jwt.fromAuthHeaderAsBearerToken();
it('should return the value from the authorization header with default JWT auth scheme', function() {
var req = new Request()
req.headers['authorization'] = "JWT abcd123";
req.headers['authorization'] = "bearer abcd123";

@@ -165,3 +174,3 @@ var token = extractor(req);

var extractor = extract_jwt.fromExtractors([extract_jwt.fromAuthHeader(), extract_jwt.fromHeader('authorization')]);
var extractor = extract_jwt.fromExtractors([extract_jwt.fromAuthHeaderAsBearerToken(), extract_jwt.fromHeader('authorization')]);

@@ -189,3 +198,3 @@ it('should return null when no extractor extracts token', function() {

var req = new Request()
req.headers['authorization'] = "JWT abcd123";
req.headers['authorization'] = "bearer abcd123";

@@ -192,0 +201,0 @@ var token = extractor(req);

@@ -18,3 +18,3 @@ var Strategy = require('../lib/strategy');

it('should throw if constructed without a secretOrKey arg', function() {
it('should throw if constructed neither a secretOrKey or a secretOrKeyProvider arg', function() {
expect(function() {

@@ -26,2 +26,13 @@ var s = new Strategy({jwtFromRequest: function(r) {}, secretOrKey: null}, function() {});

it('should throw if constructed with both a secretOrKey and a secretOrKeyProvider', function () {
expect(function() {
var s = new Strategy({
secretOrKey: 'secret',
secretOrKeyProvider: function(req, token, done) {},
jwtFromReqeust: function(r) {}
});
}).to.throw(TypeError);
});
it('should throw if constructed without a jwtFromRequest arg', function() {

@@ -28,0 +39,0 @@ expect(function() {

@@ -21,3 +21,7 @@ var Strategy = require('../lib/strategy')

options.ignoreExpiration = false;
options.jwtFromRequest = extract_jwt.fromAuthHeader();
options.jsonWebTokenOptions = {
clockTolerance: 10,
maxAge: "1h",
};
options.jwtFromRequest = extract_jwt.fromAuthHeaderAsBearerToken();
strategy = new Strategy(options, verifyStub);

@@ -33,3 +37,3 @@

.req(function(req) {
req.headers['authorization'] = "JWT " + test_data.valid_jwt.token;
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})

@@ -66,2 +70,12 @@ .authenticate();

it('should call with the right maxAge option', function() {
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
expect(Strategy.JwtVerifier.args[0][2].maxAge).to.equal('1h');
});
it('should call with the right clockTolerance option', function() {
expect(Strategy.JwtVerifier.args[0][2]).to.be.an.object;
expect(Strategy.JwtVerifier.args[0][2].clockTolerance).to.equal(10);
});
});

@@ -74,3 +88,3 @@

before(function(done) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeader(), secretOrKey: 'secret'}, function(jwt_payload, next) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_payload, next) {
payload = jwt_payload;

@@ -89,3 +103,3 @@ next(null, {}, {});

.req(function(req) {
req.headers['authorization'] = "JWT " + test_data.valid_jwt.token;
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})

@@ -110,3 +124,3 @@ .authenticate();

strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeader(), secretOrKey: 'secret'}, verify_spy);
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, verify_spy);

@@ -123,3 +137,3 @@ // Mock errored verification

.req(function(req) {
req.headers['authorization'] = "JWT " + test_data.valid_jwt.token;
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})

@@ -149,3 +163,3 @@ .authenticate();

strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeader(), secretOrKey: 'secret'}, verify_spy);
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, verify_spy);

@@ -152,0 +166,0 @@ chai.passport.use(strategy)

@@ -5,2 +5,3 @@ var chai = require('chai')

, sinon = require('sinon')
, verify = require('../lib/verify_jwt')
, extract_jwt = require('../lib/extract_jwt');

@@ -12,3 +13,3 @@

before(function() {
Strategy.JwtVerifier = sinon.stub();
Strategy.JwtVerifier = sinon.stub();
Strategy.JwtVerifier.callsArgWith(3, null, test_data.valid_jwt.payload);

@@ -19,6 +20,6 @@ });

var strategy, user, info;
var strategy, user, info;
before(function(done) {
strategy = new Strategy({jwtFromRequest:extract_jwt.fromAuthHeader(), secretOrKey: 'secret'}, function(jwt_paylod, next) {
strategy = new Strategy({jwtFromRequest:extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_paylod, next) {
return next(null, {user_id: 1234567890}, {foo:'bar'});

@@ -34,3 +35,3 @@ });

.req(function(req) {
req.headers['authorization'] = "JWT " + test_data.valid_jwt.token;
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})

@@ -61,3 +62,3 @@ .authenticate();

before(function(done) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeader(), secretOrKey: 'secret'}, function(jwt_payload, next) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_payload, next) {
return next(null, false, {message: 'invalid user'});

@@ -72,3 +73,3 @@ });

.req(function(req) {
req.headers['authorization'] = "JWT " + test_data.valid_jwt.token;
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})

@@ -83,3 +84,3 @@ .authenticate();

});
});

@@ -94,3 +95,3 @@

before(function(done) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeader(), secretOrKey: 'secrety'}, function(jwt_payload, next) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secrety'}, function(jwt_payload, next) {
return next(new Error("ERROR"), false, {message: 'invalid user'});

@@ -105,3 +106,3 @@ });

.req(function(req) {
req.headers['authorization'] = "JWT " + test_data.valid_jwt.token;
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})

@@ -125,3 +126,3 @@ .authenticate();

before(function(done) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeader(), secretOrKey: 'secret'}, function(jwt_payload, next) {
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_payload, next) {
throw new Error("EXCEPTION");

@@ -136,3 +137,3 @@ });

.req(function(req) {
req.headers['authorization'] = "JWT " + test_data.valid_jwt.token;
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
})

@@ -159,3 +160,3 @@ .authenticate();

opts.secretOrKey = 'secret';
opts.jwtFromRequest = extract_jwt.fromAuthHeader();
opts.jwtFromRequest = extract_jwt.fromAuthHeaderAsBearerToken();
strategy = new Strategy(opts, function(request, jwt_payload, next) {

@@ -172,3 +173,3 @@ // Capture the value passed in as the request argument

.req(function(req) {
req.headers['authorization'] = "JWT " + test_data.valid_jwt.token;
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
expected_request = req;

@@ -185,2 +186,74 @@ })

describe('handling a request when constructed with a secretOrKeyProvider function that succeeds', function() {
var strategy, fakeSecretOrKeyProvider, expectedReqeust;
before(function(done) {
fakeSecretOrKeyProvider = sinon.spy(function(request, token, done) {
done(null, 'secret from callback');
});
opts = {
secretOrKeyProvider: fakeSecretOrKeyProvider,
jwtFromRequest: function(request) {
return 'an undecoded jwt string';
}
}
strategy = new Strategy(opts, function(jwtPayload, next) {
return next(null, {user_id: 'dont care'}, {});
});
chai.passport.use(strategy)
.success(function(u, i) {
done();
})
.req(function(req) {
expectedReqeust = req;
})
.authenticate();
});
it('should call the fake secret or key provider with the reqeust', function() {
expect(fakeSecretOrKeyProvider.calledWith(expectedReqeust, sinon.match.any, sinon.match.any)).to.be.true;
});
it('should call the secretOrKeyProvider with the undecoded jwt', function() {
expect(fakeSecretOrKeyProvider.calledWith(sinon.match.any, 'an undecoded jwt string', sinon.match.any)).to.be.true;
});
it('should call JwtVerifier with the value returned from secretOrKeyProvider', function() {
expect(Strategy.JwtVerifier.calledWith(sinon.match.any, 'secret from callback', sinon.match.any, sinon.match.any)).to.be.true;
});
});
describe('handling a request when constructed with a secretOrKeyProvider function that errors', function() {
var errorMessage;
before(function(done) {
fakeSecretOrKeyProvider = sinon.spy(function(request, token, done) {
done('Error occurred looking for the secret');
});
opts = {
secretOrKeyProvider: fakeSecretOrKeyProvider,
jwtFromRequest: function(request) {
return 'an undecoded jwt string';
}
}
strategy = new Strategy(opts, function(jwtPayload, next) {
return next(null, {user_id: 'dont care'}, {});
});
chai.passport.use(strategy)
.fail(function(i) {
errorMessage = i;
done();
})
.authenticate();
});
it('should fail with the error message from the secretOrKeyProvider', function() {
expect(errorMessage).to.equal('Error occurred looking for the secret');
});
});
});

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc