passport-jwt-v2 4.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +20 -0
- package/.travis.yml +11 -0
- package/LICENSE +22 -0
- package/README.md +169 -0
- package/docs/migrating.md +70 -0
- package/lib/auth_header.js +19 -0
- package/lib/extract_jwt.js +134 -0
- package/lib/helpers/assign.js +24 -0
- package/lib/index.js +10 -0
- package/lib/strategy.js +139 -0
- package/lib/verify_jwt.js +5 -0
- package/package.json +44 -0
- package/test/auth_header-test.js +28 -0
- package/test/bootstrap.js +3 -0
- package/test/extractors-test.js +287 -0
- package/test/mock_request.js +10 -0
- package/test/strategy-init-test.js +41 -0
- package/test/strategy-requests-test.js +124 -0
- package/test/strategy-validation-test.js +182 -0
- package/test/strategy-verify-test.js +245 -0
- package/test/testdata.js +14 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
name: Node.js CI
|
|
2
|
+
|
|
3
|
+
on: push
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
strategy:
|
|
9
|
+
matrix:
|
|
10
|
+
node-version: [10.x, 11.x, 12.x, 13.x, 14.x, 15.x, 16.x, 17.x]
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v2
|
|
13
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
14
|
+
uses: actions/setup-node@v2
|
|
15
|
+
with:
|
|
16
|
+
node-version: ${{ matrix.node-version }}
|
|
17
|
+
- name: Install dependencies
|
|
18
|
+
run: npm ci
|
|
19
|
+
- run: npm run build --if-present
|
|
20
|
+
- run: npm test
|
package/.travis.yml
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2014 themikenicholson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# passport-jwt
|
|
2
|
+
|
|
3
|
+
[](https://travis-ci.org/mikenicholson/passport-jwt)
|
|
4
|
+
[](https://codeclimate.com/github/mikenicholson/passport-jwt)
|
|
5
|
+
|
|
6
|
+
A [Passport](http://passportjs.org/) strategy for authenticating with a
|
|
7
|
+
[JSON Web Token](http://jwt.io).
|
|
8
|
+
|
|
9
|
+
This module lets you authenticate endpoints using a JSON web token. It is
|
|
10
|
+
intended to be used to secure RESTful endpoints without sessions.
|
|
11
|
+
|
|
12
|
+
## Supported By
|
|
13
|
+
|
|
14
|
+
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](https://auth0.com/developers?utm_source=GHsponsor&utm_medium=GHsponsor&utm_campaign=passport-jwt&utm_content=auth) <img alt='Auth0 Logo' src='https://s3.amazonaws.com/passport-jwt-img/Auth0+logo.svg'/>
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
npm install passport-jwt
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Configure Strategy
|
|
23
|
+
|
|
24
|
+
The JWT authentication strategy is constructed as follows:
|
|
25
|
+
|
|
26
|
+
new JwtStrategy(options, verify)
|
|
27
|
+
|
|
28
|
+
`options` is an object literal containing options to control how the token is
|
|
29
|
+
extracted from the request or verified.
|
|
30
|
+
|
|
31
|
+
* `secretOrKey` is a string or buffer containing the secret
|
|
32
|
+
(symmetric) or PEM-encoded public key (asymmetric) for verifying the token's
|
|
33
|
+
signature. REQUIRED unless `secretOrKeyProvider` is provided.
|
|
34
|
+
* `secretOrKeyProvider` is a callback in the format `function secretOrKeyProvider(request, rawJwtToken, done)`,
|
|
35
|
+
which should call `done` with a secret or PEM-encoded public key (asymmetric) for the given key and request combination.
|
|
36
|
+
`done` accepts arguments in the format `function done(err, secret)`. Note it is up to the implementer to decode rawJwtToken.
|
|
37
|
+
REQUIRED unless `secretOrKey` is provided.
|
|
38
|
+
* `jwtFromRequest` (REQUIRED) Function that accepts a request as the only
|
|
39
|
+
parameter and returns either the JWT as a string or *null*. See
|
|
40
|
+
[Extracting the JWT from the request](#extracting-the-jwt-from-the-request) for
|
|
41
|
+
more details.
|
|
42
|
+
* `issuer`: If defined the token issuer (iss) will be verified against this
|
|
43
|
+
value.
|
|
44
|
+
* `audience`: If defined, the token audience (aud) will be verified against
|
|
45
|
+
this value.
|
|
46
|
+
* `algorithms`: List of strings with the names of the allowed algorithms. For instance, ["HS256", "HS384"].
|
|
47
|
+
* `ignoreExpiration`: if true do not validate the expiration of the token.
|
|
48
|
+
* `passReqToCallback`: If true the request will be passed to the verify
|
|
49
|
+
callback. i.e. verify(request, jwt_payload, done_callback).
|
|
50
|
+
* `jsonWebTokenOptions`: passport-jwt is verifying the token using [jsonwebtoken](https://github.com/auth0/node-jsonwebtoken).
|
|
51
|
+
Pass here an options object for any other option you can pass the jsonwebtoken verifier. (i.e maxAge)
|
|
52
|
+
|
|
53
|
+
`verify` is a function with the parameters `verify(jwt_payload, done)`
|
|
54
|
+
|
|
55
|
+
* `jwt_payload` is an object literal containing the decoded JWT payload.
|
|
56
|
+
* `done` is a passport error first callback accepting arguments
|
|
57
|
+
done(error, user, info)
|
|
58
|
+
|
|
59
|
+
An example configuration which reads the JWT from the http
|
|
60
|
+
Authorization header with the scheme 'bearer':
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
var JwtStrategy = require('passport-jwt').Strategy,
|
|
64
|
+
ExtractJwt = require('passport-jwt').ExtractJwt;
|
|
65
|
+
var opts = {}
|
|
66
|
+
opts.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken();
|
|
67
|
+
opts.secretOrKey = 'secret';
|
|
68
|
+
opts.issuer = 'accounts.examplesoft.com';
|
|
69
|
+
opts.audience = 'yoursite.net';
|
|
70
|
+
passport.use(new JwtStrategy(opts, function(jwt_payload, done) {
|
|
71
|
+
User.findOne({id: jwt_payload.sub}, function(err, user) {
|
|
72
|
+
if (err) {
|
|
73
|
+
return done(err, false);
|
|
74
|
+
}
|
|
75
|
+
if (user) {
|
|
76
|
+
return done(null, user);
|
|
77
|
+
} else {
|
|
78
|
+
return done(null, false);
|
|
79
|
+
// or you could create a new account
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}));
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Extracting the JWT from the request
|
|
86
|
+
|
|
87
|
+
There are a number of ways the JWT may be included in a request. In order to remain as flexible as
|
|
88
|
+
possible the JWT is parsed from the request by a user-supplied callback passed in as the
|
|
89
|
+
`jwtFromRequest` parameter. This callback, from now on referred to as an extractor,
|
|
90
|
+
accepts a request object as an argument and returns the encoded JWT string or *null*.
|
|
91
|
+
|
|
92
|
+
#### Included extractors
|
|
93
|
+
|
|
94
|
+
A number of extractor factory functions are provided in passport-jwt.ExtractJwt. These factory
|
|
95
|
+
functions return a new extractor configured with the given parameters.
|
|
96
|
+
|
|
97
|
+
* ```fromHeader(header_name)``` creates a new extractor that looks for the JWT in the given http
|
|
98
|
+
header
|
|
99
|
+
* ```fromBodyField(field_name)``` creates a new extractor that looks for the JWT in the given body
|
|
100
|
+
field. You must have a body parser configured in order to use this method.
|
|
101
|
+
* ```fromUrlQueryParameter(param_name)``` creates a new extractor that looks for the JWT in the given
|
|
102
|
+
URL query parameter.
|
|
103
|
+
* ```fromAuthHeaderWithScheme(auth_scheme)``` creates a new extractor that looks for the JWT in the
|
|
104
|
+
authorization header, expecting the scheme to match auth_scheme.
|
|
105
|
+
* ```fromAuthHeaderAsBearerToken()``` creates a new extractor that looks for the JWT in the authorization header
|
|
106
|
+
with the scheme 'bearer'
|
|
107
|
+
* ```fromExtractors([array of extractor functions])``` creates a new extractor using an array of
|
|
108
|
+
extractors provided. Each extractor is attempted in order until one returns a token.
|
|
109
|
+
|
|
110
|
+
### Writing a custom extractor function
|
|
111
|
+
|
|
112
|
+
If the supplied extractors don't meet your needs you can easily provide your own callback. For
|
|
113
|
+
example, if you are using the cookie-parser middleware and want to extract the JWT in a cookie
|
|
114
|
+
you could use the following function as the argument to the jwtFromRequest option:
|
|
115
|
+
|
|
116
|
+
```js
|
|
117
|
+
var cookieExtractor = function(req) {
|
|
118
|
+
var token = null;
|
|
119
|
+
if (req && req.cookies) {
|
|
120
|
+
token = req.cookies['jwt'];
|
|
121
|
+
}
|
|
122
|
+
return token;
|
|
123
|
+
};
|
|
124
|
+
// ...
|
|
125
|
+
opts.jwtFromRequest = cookieExtractor;
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Authenticate requests
|
|
129
|
+
|
|
130
|
+
Use `passport.authenticate()` specifying `'JWT'` as the strategy.
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
app.post('/profile', passport.authenticate('jwt', { session: false }),
|
|
134
|
+
function(req, res) {
|
|
135
|
+
res.send(req.user.profile);
|
|
136
|
+
}
|
|
137
|
+
);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Include the JWT in requests
|
|
141
|
+
|
|
142
|
+
The method of including a JWT in a request depends entirely on the extractor
|
|
143
|
+
function you choose. For example, if you use the `fromAuthHeaderAsBearerToken`
|
|
144
|
+
extractor, you would include an `Authorization` header in your request with the
|
|
145
|
+
scheme set to `bearer`. e.g.
|
|
146
|
+
|
|
147
|
+
Authorization: bearer JSON_WEB_TOKEN_STRING.....
|
|
148
|
+
|
|
149
|
+
## Migrating
|
|
150
|
+
|
|
151
|
+
Read the [Migration Guide](docs/migrating.md) for help upgrading to the latest
|
|
152
|
+
major version of passport-jwt.
|
|
153
|
+
|
|
154
|
+
## Tests
|
|
155
|
+
|
|
156
|
+
npm install
|
|
157
|
+
npm test
|
|
158
|
+
|
|
159
|
+
To generate test-coverage reports:
|
|
160
|
+
|
|
161
|
+
npm install -g istanbul
|
|
162
|
+
npm run-script testcov
|
|
163
|
+
istanbul report
|
|
164
|
+
|
|
165
|
+
## License
|
|
166
|
+
|
|
167
|
+
The [MIT License](http://opensource.org/licenses/MIT)
|
|
168
|
+
|
|
169
|
+
Copyright (c) 2015 Mike Nicholson
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Migration Guide
|
|
2
|
+
|
|
3
|
+
The following instructions should help in migrating to a new major version of
|
|
4
|
+
passport-jwt.
|
|
5
|
+
|
|
6
|
+
## Migrating from 3.x.x to 4.x.x
|
|
7
|
+
|
|
8
|
+
Version 4.0.0 was released to update [jsonwebtoken's](https://github.com/auth0/node-jsonwebtoken)
|
|
9
|
+
major version from v7 to v8 in order to fix a security issue (see
|
|
10
|
+
[#147](https://github.com/mikenicholson/passport-jwt/issues/147)).
|
|
11
|
+
|
|
12
|
+
Users of `passport-jwt` are exposed to the API of `jsonwebtoken` through the `jsonWebTokenOptions`
|
|
13
|
+
constructor option. Therefore, a major version rev of `jsonwebtoken` triggered a major version rev
|
|
14
|
+
of `passport-jwt`.
|
|
15
|
+
|
|
16
|
+
See the
|
|
17
|
+
[jsonwebtoken v7-v8 Migration Notes](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8)
|
|
18
|
+
for the full details. The change in units for the `maxAge` attribute of `jsonWebTokenOptions` is
|
|
19
|
+
likely to impact the greatest number of `passport-jwt` users.
|
|
20
|
+
|
|
21
|
+
## Migrating from 2.x.x to 3.x.x
|
|
22
|
+
|
|
23
|
+
Version 3.0.0 removes the `ExtractJwt.fromAuthHeader()` extractor function that would extract
|
|
24
|
+
JWT's from `Authorization` headers with the auth scheme 'jwt'. The default authorization scheme
|
|
25
|
+
of 'jwt' as the was not RFC 6750 compliant. The extractor was replaced with
|
|
26
|
+
`ExtractJwt.fromAuthHeaderAsBearerToken()`. The removal of `ExtractJwt.fromAuthHeader()` was done
|
|
27
|
+
to clearly change the API so any code relying on the old API would clearly break, hopefully saving
|
|
28
|
+
people some debugging time.
|
|
29
|
+
|
|
30
|
+
If you want to maintain the behavior of `ExtractJwt.fromAuthHeader()` when switching to v3.3.0, simply
|
|
31
|
+
replace it with `ExtractJwt.fromAuthHeaderWithScheme('jwt')` in your implementation.
|
|
32
|
+
|
|
33
|
+
## Migrating from version 1.x.x to 2.x.x
|
|
34
|
+
|
|
35
|
+
The v2 API is not backwards compatible with v1, specifically with regards to the introduction
|
|
36
|
+
of the concept of JWT extractor functions. If you require the legacy behavior in v1 you can use
|
|
37
|
+
the extractor function ```versionOneCompatibility(options)```
|
|
38
|
+
|
|
39
|
+
*options* is an object with any of the three custom JWT extraction options present in the v1
|
|
40
|
+
constructor:
|
|
41
|
+
* `tokenBodyField`: Field in a request body to search for the JWT.
|
|
42
|
+
Default is auth_token.
|
|
43
|
+
* `tokenQueryParameterName`: Query parameter name containing the token.
|
|
44
|
+
Default is auth_token.
|
|
45
|
+
* `authScheme`: Expected authorization scheme if token is submitted through
|
|
46
|
+
the HTTP Authorization header. Defaults to JWT
|
|
47
|
+
If in v1 you constructed the strategy like this:
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
var JwtStrategy = require('passport-jwt').Strategy;
|
|
51
|
+
var opts = {}
|
|
52
|
+
opts.tokenBodyField = 'MY_CUSTOM_BODY_FIELD';
|
|
53
|
+
opts.secretOrKey = 'secret';
|
|
54
|
+
opts.issuer = 'accounts.examplesoft.com';
|
|
55
|
+
opts.audience = 'yoursite.net';
|
|
56
|
+
passport.use(new JwtStrategy(opts, verifyFunction));
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Identical behavior can be achieved under v2 with the versionOneCompatibility extractor:
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
var JwtStrategy = require('passport-jwt').Strategy,
|
|
63
|
+
ExtractJwt = require('passport-jwt').ExtractJwt;
|
|
64
|
+
var opts = {}
|
|
65
|
+
opts.jwtFromRequest = ExtractJwt.versionOneCompatibility({ tokenBodyField = 'MY_CUSTOM_BODY_FIELD' });
|
|
66
|
+
opts.opts.secretOrKey = 'secret';
|
|
67
|
+
opts.issuer = 'accounts.examplesoft.com';
|
|
68
|
+
opts.audience = 'yoursite.net';
|
|
69
|
+
passport.use(new JwtStrategy(opts, verifyFunction));
|
|
70
|
+
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var re = /(\S+)\s+(\S+)/;
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
function parseAuthHeader(hdrValue) {
|
|
8
|
+
if (typeof hdrValue !== 'string') {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
var matches = hdrValue.match(re);
|
|
12
|
+
return matches && { scheme: matches[1], value: matches[2] };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
parse: parseAuthHeader
|
|
19
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var url = require('url'),
|
|
4
|
+
auth_hdr = require('./auth_header');
|
|
5
|
+
|
|
6
|
+
// Note: express http converts all headers
|
|
7
|
+
// to lower case.
|
|
8
|
+
var AUTH_HEADER = "authorization",
|
|
9
|
+
LEGACY_AUTH_SCHEME = "JWT",
|
|
10
|
+
BEARER_AUTH_SCHEME = 'bearer';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
var extractors = {};
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
extractors.fromHeader = function (header_name) {
|
|
17
|
+
return function (request) {
|
|
18
|
+
var token = null;
|
|
19
|
+
if (request.headers[header_name]) {
|
|
20
|
+
token = request.headers[header_name];
|
|
21
|
+
}
|
|
22
|
+
return token;
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
extractors.fromBodyField = function (field_name) {
|
|
29
|
+
return function (request) {
|
|
30
|
+
var token = null;
|
|
31
|
+
if (request.body && Object.prototype.hasOwnProperty.call(request.body, field_name)) {
|
|
32
|
+
token = request.body[field_name];
|
|
33
|
+
}
|
|
34
|
+
return token;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
extractors.fromUrlQueryParameter = function (param_name) {
|
|
41
|
+
return function (request) {
|
|
42
|
+
var token = null,
|
|
43
|
+
parsed_url = url.parse(request.url, true);
|
|
44
|
+
if (parsed_url.query && Object.prototype.hasOwnProperty.call(parsed_url.query, param_name)) {
|
|
45
|
+
token = parsed_url.query[param_name];
|
|
46
|
+
}
|
|
47
|
+
return token;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
extractors.fromAuthHeaderWithScheme = function (auth_scheme) {
|
|
54
|
+
var auth_scheme_lower = auth_scheme.toLowerCase();
|
|
55
|
+
return function (request) {
|
|
56
|
+
|
|
57
|
+
var token = null;
|
|
58
|
+
if (request.headers[AUTH_HEADER]) {
|
|
59
|
+
var auth_params = auth_hdr.parse(request.headers[AUTH_HEADER]);
|
|
60
|
+
if (auth_params && auth_scheme_lower === auth_params.scheme.toLowerCase()) {
|
|
61
|
+
token = auth_params.value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return token;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
extractors.fromAuthHeaderAsBearerToken = function () {
|
|
71
|
+
return extractors.fromAuthHeaderWithScheme(BEARER_AUTH_SCHEME);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
extractors.fromExtractors = function(extractors) {
|
|
76
|
+
if (!Array.isArray(extractors)) {
|
|
77
|
+
throw new TypeError('extractors.fromExtractors expects an array')
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return function (request) {
|
|
81
|
+
var token = null;
|
|
82
|
+
var index = 0;
|
|
83
|
+
while(!token && index < extractors.length) {
|
|
84
|
+
token = extractors[index].call(this, request);
|
|
85
|
+
index ++;
|
|
86
|
+
}
|
|
87
|
+
return token;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* This extractor mimics the behavior of the v1.*.* extraction logic.
|
|
94
|
+
*
|
|
95
|
+
* This extractor exists only to provide an easy transition from the v1.*.* API to the v2.0.0
|
|
96
|
+
* API.
|
|
97
|
+
*
|
|
98
|
+
* This extractor first checks the auth header, if it doesn't find a token there then it checks the
|
|
99
|
+
* specified body field and finally the url query parameters.
|
|
100
|
+
*
|
|
101
|
+
* @param options
|
|
102
|
+
* authScheme: Expected scheme when JWT can be found in HTTP Authorize header. Default is JWT.
|
|
103
|
+
* tokenBodyField: Field in request body containing token. Default is auth_token.
|
|
104
|
+
* tokenQueryParameterName: Query parameter name containing the token. Default is auth_token.
|
|
105
|
+
*/
|
|
106
|
+
extractors.versionOneCompatibility = function (options) {
|
|
107
|
+
var authScheme = options.authScheme || LEGACY_AUTH_SCHEME,
|
|
108
|
+
bodyField = options.tokenBodyField || 'auth_token',
|
|
109
|
+
queryParam = options.tokenQueryParameterName || 'auth_token';
|
|
110
|
+
|
|
111
|
+
return function (request) {
|
|
112
|
+
var authHeaderExtractor = extractors.fromAuthHeaderWithScheme(authScheme);
|
|
113
|
+
var token = authHeaderExtractor(request);
|
|
114
|
+
|
|
115
|
+
if (!token) {
|
|
116
|
+
var bodyExtractor = extractors.fromBodyField(bodyField);
|
|
117
|
+
token = bodyExtractor(request);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (!token) {
|
|
121
|
+
var queryExtractor = extractors.fromUrlQueryParameter(queryParam);
|
|
122
|
+
token = queryExtractor(request);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return token;
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Export the Jwt extraction functions
|
|
133
|
+
*/
|
|
134
|
+
module.exports = extractors;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// note: This is a polyfill to Object.assign to support old nodejs versions (0.10 / 0.12) where
|
|
2
|
+
// Object.assign doesn't exist.
|
|
3
|
+
// Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
|
|
4
|
+
module.exports = function(target, varArgs) {
|
|
5
|
+
if (target == null) { // TypeError if undefined or null
|
|
6
|
+
throw new TypeError('Cannot convert undefined or null to object');
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
var to = Object(target);
|
|
10
|
+
|
|
11
|
+
for (var index = 1; index < arguments.length; index++) {
|
|
12
|
+
var nextSource = arguments[index];
|
|
13
|
+
|
|
14
|
+
if (nextSource != null) { // Skip over if undefined or null
|
|
15
|
+
for (var nextKey in nextSource) {
|
|
16
|
+
// Avoid bugs when hasOwnProperty is shadowed
|
|
17
|
+
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
|
|
18
|
+
to[nextKey] = nextSource[nextKey];
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return to;
|
|
24
|
+
};
|
package/lib/index.js
ADDED
package/lib/strategy.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
var passport = require('passport-strategy')
|
|
2
|
+
, auth_hdr = require('./auth_header')
|
|
3
|
+
, util = require('util')
|
|
4
|
+
, url = require('url')
|
|
5
|
+
, assign = require('./helpers/assign.js');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Strategy constructor
|
|
11
|
+
*
|
|
12
|
+
* @param options
|
|
13
|
+
* secretOrKey: String or buffer containing the secret or PEM-encoded public key. Required unless secretOrKeyProvider is provided.
|
|
14
|
+
* secretOrKeyProvider: callback in the format secretOrKeyProvider(request, rawJwtToken, done)`,
|
|
15
|
+
* which should call done with a secret or PEM-encoded public key
|
|
16
|
+
* (asymmetric) for the given undecoded jwt token string and request
|
|
17
|
+
* combination. done has the signature function done(err, secret).
|
|
18
|
+
* REQUIRED unless `secretOrKey` is provided.
|
|
19
|
+
* jwtFromRequest: (REQUIRED) Function that accepts a request as the only parameter and returns the either JWT as a string or null
|
|
20
|
+
* issuer: If defined issuer will be verified against this value
|
|
21
|
+
* audience: If defined audience will be verified against this value
|
|
22
|
+
* algorithms: List of strings with the names of the allowed algorithms. For instance, ["HS256", "HS384"].
|
|
23
|
+
* ignoreExpiration: if true do not validate the expiration of the token.
|
|
24
|
+
* passReqToCallback: If true the verify callback will be called with args (request, jwt_payload, done_callback).
|
|
25
|
+
* @param verify - Verify callback with args (jwt_payload, done_callback) if passReqToCallback is false,
|
|
26
|
+
* (request, jwt_payload, done_callback) if true.
|
|
27
|
+
*/
|
|
28
|
+
function JwtStrategy(options, verify) {
|
|
29
|
+
|
|
30
|
+
passport.Strategy.call(this);
|
|
31
|
+
this.name = 'jwt';
|
|
32
|
+
|
|
33
|
+
this._secretOrKeyProvider = options.secretOrKeyProvider;
|
|
34
|
+
|
|
35
|
+
if (options.secretOrKey) {
|
|
36
|
+
if (this._secretOrKeyProvider) {
|
|
37
|
+
throw new TypeError('JwtStrategy has been given both a secretOrKey and a secretOrKeyProvider');
|
|
38
|
+
}
|
|
39
|
+
this._secretOrKeyProvider = function (request, rawJwtToken, done) {
|
|
40
|
+
done(null, options.secretOrKey)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (!this._secretOrKeyProvider) {
|
|
45
|
+
throw new TypeError('JwtStrategy requires a secret or key');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
this._verify = verify;
|
|
49
|
+
if (!this._verify) {
|
|
50
|
+
throw new TypeError('JwtStrategy requires a verify callback');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
this._jwtFromRequest = options.jwtFromRequest;
|
|
54
|
+
if (!this._jwtFromRequest) {
|
|
55
|
+
throw new TypeError('JwtStrategy requires a function to retrieve jwt from requests (see option jwtFromRequest)');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this._passReqToCallback = options.passReqToCallback;
|
|
59
|
+
var jsonWebTokenOptions = options.jsonWebTokenOptions || {};
|
|
60
|
+
//for backwards compatibility, still allowing you to pass
|
|
61
|
+
//audience / issuer / algorithms / ignoreExpiration
|
|
62
|
+
//on the options.
|
|
63
|
+
this._verifOpts = assign({}, jsonWebTokenOptions, {
|
|
64
|
+
audience: options.audience,
|
|
65
|
+
issuer: options.issuer,
|
|
66
|
+
algorithms: options.algorithms,
|
|
67
|
+
ignoreExpiration: !!options.ignoreExpiration
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
}
|
|
71
|
+
util.inherits(JwtStrategy, passport.Strategy);
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Allow for injection of JWT Verifier.
|
|
77
|
+
*
|
|
78
|
+
* This improves testability by allowing tests to cleanly isolate failures in the JWT Verification
|
|
79
|
+
* process from failures in the passport related mechanics of authentication.
|
|
80
|
+
*
|
|
81
|
+
* Note that this should only be replaced in tests.
|
|
82
|
+
*/
|
|
83
|
+
JwtStrategy.JwtVerifier = require('./verify_jwt');
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Authenticate request based on JWT obtained from header or post body
|
|
89
|
+
*/
|
|
90
|
+
JwtStrategy.prototype.authenticate = function(req, options) {
|
|
91
|
+
var self = this;
|
|
92
|
+
|
|
93
|
+
var token = self._jwtFromRequest(req);
|
|
94
|
+
|
|
95
|
+
if (!token) {
|
|
96
|
+
return self.fail(new Error("No auth token"));
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this._secretOrKeyProvider(req, token, function(secretOrKeyError, secretOrKey) {
|
|
100
|
+
if (secretOrKeyError) {
|
|
101
|
+
self.fail(secretOrKeyError)
|
|
102
|
+
} else {
|
|
103
|
+
// Verify the JWT
|
|
104
|
+
JwtStrategy.JwtVerifier(token, secretOrKey, self._verifOpts, function(jwt_err, payload) {
|
|
105
|
+
if (jwt_err) {
|
|
106
|
+
return self.fail(jwt_err);
|
|
107
|
+
} else {
|
|
108
|
+
// Pass the parsed token to the user
|
|
109
|
+
var verified = function(err, user, info) {
|
|
110
|
+
if(err) {
|
|
111
|
+
return self.error(err);
|
|
112
|
+
} else if (!user) {
|
|
113
|
+
return self.fail(info);
|
|
114
|
+
} else {
|
|
115
|
+
return self.success(user, info);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
if (self._passReqToCallback) {
|
|
121
|
+
self._verify(req, payload, verified);
|
|
122
|
+
} else {
|
|
123
|
+
self._verify(payload, verified);
|
|
124
|
+
}
|
|
125
|
+
} catch(ex) {
|
|
126
|
+
self.error(ex);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Export the Jwt Strategy
|
|
138
|
+
*/
|
|
139
|
+
module.exports = JwtStrategy;
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "passport-jwt-v2",
|
|
3
|
+
"version": "4.0.2",
|
|
4
|
+
"description": "Passport authentication strategy using JSON Web Tokens",
|
|
5
|
+
"main": "./lib",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "mocha --reporter spec --require test/bootstrap test/*test.js",
|
|
8
|
+
"testcov": "nyc npm run test"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/JonaMX/passport-jwt-v2.git"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"Passport",
|
|
16
|
+
"Strategy",
|
|
17
|
+
"JSON",
|
|
18
|
+
"Web",
|
|
19
|
+
"Token",
|
|
20
|
+
"JWT"
|
|
21
|
+
],
|
|
22
|
+
"author": "Jonatan Juarez",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/JonaMX/passport-jwt-v2/issues"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/JonaMX/passport-jwt-v2",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"chai": "^3.0.0",
|
|
30
|
+
"chai-passport-strategy": "^1.0.0",
|
|
31
|
+
"mocha": "^9.2.1",
|
|
32
|
+
"nyc": "^15.1.0",
|
|
33
|
+
"sinon": "^1.0.0"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"jsonwebtoken": "^9.0.3",
|
|
37
|
+
"passport-strategy": "^1.0.0"
|
|
38
|
+
},
|
|
39
|
+
"directories": {
|
|
40
|
+
"doc": "docs",
|
|
41
|
+
"lib": "lib",
|
|
42
|
+
"test": "test"
|
|
43
|
+
}
|
|
44
|
+
}
|