A Passport strategy for authenticating with a JSON Web Token.
This module lets you authenticate endpoints using a JSON web token. It is intended to be used to secure RESTful endpoints without sessions.
Archived see the official package here for the progress of v5.
Now updated to version v5.x.x with support for typescript
, jose
and @nestjs/jwt
intergration.
If you want to quickly add secure token-based authentication to Node.js apps, feel free to check out Auth0's Node.js SDK and free plan at auth0.com/developers
npm install passport-jwt
# to test the new v5.x.x version
npm install https://github.com/Outternet/passport-jwt
npm install <mydriverpackage> // see drivers below for options
The JWT authentication strategy is constructed as follows:
new JwtStrategy(options, verify);
You can define the types for typescript
more strictly if you want, but these are all automatically implied from the options.
new JwtStrategy<MyPayloadType, MyKeyType, PassReqToVerify>(options, verify);
options
is an object literal containing options to control how the token is
extracted from the request or verified.
(LEGACY) options can only be used if the strategy is imported from passport-jwt/auto
.
(REQUIRED) options are required for the library to work correctly.
(MODERN) is the recommended way to use the library and required if the library is imported from the main import.
secretOrKey
is a string or buffer containing the secret (symmetric) or PEM-encoded public key (asymmetric) for verifying the token's signature. REQUIRED unlesssecretOrKeyProvider
is provided.secretOrKeyProvider
is a callback in the formatfunction secretOrKeyProvider(request, rawJwtToken, done)
, which should calldone
with a secret or PEM-encoded public key (asymmetric) for the given key and request combination.done
accepts arguments in the formatfunction done(err, secret)
or can be used with a promise like(request, rawJwtToken) => Promise<secretOrKey|null>
. Note it is up to the implementer to decode rawJwtToken. REQUIRED unlesssecretOrKey
is provided.secretOrKeyProviderTimeoutSeconds
: The amount of time in seconds to wait before the secretOrKeyProvider should callback or resolve, Can be set to -1 to disable checking if the provider works.jwtFromRequest
(REQUIRED) Function that accepts a request as the only parameter and returns either the JWT as a string or null. See Extracting the JWT from the request for more details.passReqToCallback
: If true the request will be passed to the verify callback. i.e. verify(request, jwt_payload, done_callback).issuer
: (LEGACY) If defined the token issuer (iss) will be verified against this value.audience
: (LEGACY) If defined, the token audience (aud) will be verified against this value.algorithms
: (LEGACY) List of strings with the names of the allowed algorithms. For instance, ["HS256", "HS384"].ignoreExpiration
: (LEGACY) if true do not validate the expiration of the token.jsonWebTokenOptions
: (LEGACY) passport-jwt is verifying the token using jsonwebtoken. Pass here an options object for any other option you can pass the jsonwebtoken verifier. (i.e maxAge)jwtDriver
: (MODERN) the driver object can be imported from the platforms, for more information about drivers look below. All LEGACY options above are reimplemented in the driver infrastructure.
verify
is a function with the parameters verify(jwt_payload, done)
jwt_payload
is an object literal containing the decoded JWT payload.done
is a passport error first callback accepting arguments done(error, user, info)
An example using legacy configuration which reads the JWT from the http Authorization header with the scheme 'bearer':
var JwtStrategy = require('passport-jwt/auto').Strategy,
ExtractJwt = require('passport-jwt').ExtractJwt;
var opts = {}
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
opts.secretOrKey = 'secret';
opts.issuer = 'accounts.examplesoft.com';
opts.audience = 'yoursite.net';
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
User.findOne({id: jwt_payload.sub}, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
// or you could create a new account
}
});
}));
A more modern variant of the above example using esm and driver options.
import {Strategy, ExtractJwt} from "passport-jwt";
import * as jose from "jose";
import {JoseDriver} from "passport-jwt/platform-jose";
const myValidator = (jwt_payload, done) => {
User.findOne({id: jwt_payload.sub}).then(user => {
if (user) {
return done(null, user);
} else {
return done(null, false);
// or you could create a new account
}
}).catch(err => done(err, false));
}
const strategy = new Strategy({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
jwtDriver: new JoseDriver(jose, {
issuer: 'accounts.examplesoft.com',
audience: 'yoursite.net'
}),
secretOrKey: 'secret'
}, myValidator);
passport.use(strategy);
To More strictly define the types you could use new Strategy<MyPayload, MyKey>
.
But as stated above this is optional because the key and validation type are already determined from the given options.
Drivers validate the jwt and return the payload to passport
.
They have a validation
method that receives a token and a key and returns a result message.
validate
is a method with the following signature validate(token, key)
and returns Promise<SuccesMessage>
.
token
is the token returned by the extractor.key
is the key parsed by the (internal) keyOrSecret provider.
SuccesMessage
is an object with the following properties {success, message, payload}
.
success
is a boolean indicating whether the token is valid.message
is a string containing the error message.payload
is an object containing the payload.
getOptions()
is a method that returns the options given to the constructor merged with the default options.
core
is a property which contains the provided core.
You can make custom drivers with the above signatures.
var jwtValid = require('jwt-validator');
var MyValidator = {validate: function(token, key) {
return Promise.resolve({
success: jwtValid(token, key, {issuer: "name"}),
payload: {user: "name"}
});
}}
// ...
jwtDriver: MyValidator,
// ...
Or in typescript
import {JwtDriver, JwtResult} from "passport-jwt";
import jwtValid from "jwt-validator";
type MyCore = typeof jwtValid;
type MyPayload = {user: string};
type MyKey = string;
type MyOptions = {issuer: string};
class MyDriver extends JwtDriver<MyCore, MyOptions, MyKey> {
public async validate(token /* :string */, key /* :MyKey */): Promise<JwtResult<MyPayload>> {
return {
success: this.core(token, key, this.getOptions()),
payload: {user: "name"}
};
}
}
// ...
jwtDriver: new MyDriver(jwtValid, {issuer: "sdf"}),
// ...
npm install jsonwebtoken
is the default library from auth0, although still supported it hasn't received an update in years.
import jsonwebtoken from "jsonwebtoken"; //requires EsModuleInterop: true
import {JsonWebTokenDriver} from "passport-jwt/platform-jsonwebtoken";
// ...
const jwt = new JsonWebTokenDriver(jsonwebtoken, {
// view the jsonwebtoken package for all options, legacy options can be used here.
});
// ...
jwtDriver = jwt,
// ...
npm install jose
is a modern everything json library, recommended to use over jsonwebtoken
.
import * as jose from "jose";
import {JoseDriver} from "passport-jwt/platform-jose";
//...
const jos = new JoseDriver(jose, {
// view the jose package for all options
});
// ...
jwtDriver: jos,
// ...
npm install @nestjs/jwt
uses jsonwebtoken
as core with some tweaks (mainly none
algorithms), it has a high integration with nestjs
but can be used independently.
import {JwtService} from "@nestjs/jwt";
import {NestJsJwtDriver} from "passport-jwt/platform-nestjsjwt";
// ...
const nest = new NestJsJwtDriver(JwtService, {
// view the @nestjs/jwt package for all options
// most options are configured by the module see nestjs documentation
});
// ...
jwtDriver: nest,
// ...
There are a number of ways the JWT may be included in a request. In order to remain as flexible as
possible the JWT is parsed from the request by a user-supplied callback passed in as the
jwtFromRequest
parameter. This callback, from now on referred to as an extractor,
accepts a request object as an argument and returns the encoded JWT string or null.
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 but your implementation somehow returns the token with a trailing comma. Then you could use the following function as the argument to the jwtFromRequest option:
var commaExtractor = function(req) {
var token = null;
if(req && req.cookies) {
token = req.cookies["jwt"];
if(token.endsWith(",")) {
token = token.slice(0, -1);
}
}
return token;
};
// ...
opts.jwtFromRequest = commaExtractor;
Or in typescript (only as of v5.x.x)
import {jwtFromRequestFunction} from "passport-jwt";
// can return a promise and therefore be async
export const commaExtractor: jwtFromRequestFunction = async (req /* :Request is implicitly added */) => {
let token = null;
if("jwt" in req.cookies && typeof req.cookies["jwt"] === "string") {
token = req.cookies["jwt"];
token = token.endsWith(",")
? await stripComma(token)
: token;
}
return token;
}
// ...
jwtFromRequest: commaExtractor
A number of extractor factory functions are provided in passport-jwt.ExtractJwt. These factory functions return a new extractor configured with the given parameters.
fromCookie(cookie_name)
Creates a new extractor that searches for the JWT in a given cookie.fromSignedCookie(cookie_name)
Creates a new extractor that searches for the JWT in a given signed cookie. encrypted cookies are encrypted and therefore cannot be read by the client. you need a third party implementation for this option.fromSessionKey(session_key)
creates a new extractor that looks for the JWT in the given http session.fromRequestProperty(req_property_key)
Creates a new extractor that looks for the JWT in the current request. This can be used if another middleware is extracting the JWT (e.g., from a websocket connection).fromHeader(header_name)
creates a new extractor that looks for the JWT in the given http header.fromBodyField(field_name)
creates a new extractor that looks for the JWT in the given body field. You must have a body parser configured in order to use this method.fromUrlQueryParameter(param_name)
creates a new extractor that looks for the JWT in the given URL query parameter.fromAuthHeaderWithScheme(auth_scheme)
creates a new extractor that looks for the JWT in the authorization header, expecting the scheme to match auth_scheme.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 extractors provided. Each extractor is attempted in order until one returns a token.
How to authenticate the request with passport
and passport-jwt
depends on your webframework.
See the passport documentation here for more information.
Use passport.authenticate()
specifying 'JWT'
as the strategy.
app.get('/profile', passport.authenticate('jwt', { session: false }),
(req, res) => {
res.send(req.user.profile);
}
);
Use the AuthGuard
from @nestjs/passport
and specifying 'JWT'
as the strategy.
@Get('profile')
@UseGuards(AuthGuard('jwt'))
public profile(@Req() req: Request) {
return req.user.profile;
}
The method of including a JWT in a request depends entirely on the extractor
function you choose. For example, if you use the fromAuthHeaderAsBearerToken
extractor, you would include an Authorization
header in your request with the
scheme set to bearer
. e.g.
Authorization: bearer JSON_WEB_TOKEN_STRING.....
Read the Migration Guide for help upgrading to the latest
major version of passport-jwt
.
Read the Typescript Guide for help upgrading to typescript
.
Read the NestJs Guide for more help in implementing passport-jwt
in nestjs
.
Read the Message Guide for more help on using failure messages and how not to use it.
npm install
npm run build
npm run test
To generate test-coverage reports:
npm install -g istanbul
npm run testcov
istanbul report
The MIT License
Copyright (c) 2015 Mike Nicholson (Original Implementation)
Copyright (c) 2022 Outernet (Typescript Rewrite)