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,245 @@
|
|
|
1
|
+
var chai = require('chai')
|
|
2
|
+
, Strategy = require('../lib/strategy')
|
|
3
|
+
, test_data = require('./testdata')
|
|
4
|
+
, sinon = require('sinon')
|
|
5
|
+
, verify = require('../lib/verify_jwt')
|
|
6
|
+
, extract_jwt = require('../lib/extract_jwt');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
describe('Strategy', function() {
|
|
10
|
+
|
|
11
|
+
before(function() {
|
|
12
|
+
Strategy.JwtVerifier = sinon.stub();
|
|
13
|
+
Strategy.JwtVerifier.callsArgWith(3, null, test_data.valid_jwt.payload);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('Handling a request with a valid JWT and succesful verification', function() {
|
|
17
|
+
|
|
18
|
+
var strategy, user, info;
|
|
19
|
+
|
|
20
|
+
before(function(done) {
|
|
21
|
+
strategy = new Strategy({jwtFromRequest:extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_paylod, next) {
|
|
22
|
+
return next(null, {user_id: 1234567890}, {foo:'bar'});
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
chai.passport.use(strategy)
|
|
26
|
+
.success(function(u, i) {
|
|
27
|
+
user = u;
|
|
28
|
+
info = i;
|
|
29
|
+
done();
|
|
30
|
+
})
|
|
31
|
+
.req(function(req) {
|
|
32
|
+
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
|
|
33
|
+
})
|
|
34
|
+
.authenticate();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
it('should provide a user', function() {
|
|
39
|
+
expect(user).to.be.an.object;
|
|
40
|
+
expect(user.user_id).to.equal(1234567890);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
it('should forward info', function() {
|
|
45
|
+
expect(info).to.be.an.object;
|
|
46
|
+
expect(info.foo).to.equal('bar');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
describe('handling a request with valid jwt and failed verification', function() {
|
|
54
|
+
|
|
55
|
+
var strategy, info;
|
|
56
|
+
|
|
57
|
+
before(function(done) {
|
|
58
|
+
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_payload, next) {
|
|
59
|
+
return next(null, false, {message: 'invalid user'});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
chai.passport.use(strategy)
|
|
63
|
+
.fail(function(i) {
|
|
64
|
+
info = i;
|
|
65
|
+
done();
|
|
66
|
+
})
|
|
67
|
+
.req(function(req) {
|
|
68
|
+
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
|
|
69
|
+
})
|
|
70
|
+
.authenticate();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
it('should fail with info', function() {
|
|
75
|
+
expect(info).to.be.an.object;
|
|
76
|
+
expect(info.message).to.equal('invalid user');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
describe('handling a request with a valid jwt and an error during verification', function() {
|
|
84
|
+
|
|
85
|
+
var strategy, err;
|
|
86
|
+
|
|
87
|
+
before(function(done) {
|
|
88
|
+
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secrety'}, function(jwt_payload, next) {
|
|
89
|
+
return next(new Error("ERROR"), false, {message: 'invalid user'});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
chai.passport.use(strategy)
|
|
93
|
+
.error(function(e) {
|
|
94
|
+
err = e;
|
|
95
|
+
done();
|
|
96
|
+
})
|
|
97
|
+
.req(function(req) {
|
|
98
|
+
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
|
|
99
|
+
})
|
|
100
|
+
.authenticate();
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
it('should error', function() {
|
|
105
|
+
expect(err).to.be.an.instanceof(Error);
|
|
106
|
+
expect(err.message).to.equal('ERROR');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
describe('handling a request with a valid jwt and an exception during verification', function() {
|
|
114
|
+
var strategy, err;
|
|
115
|
+
|
|
116
|
+
before(function(done) {
|
|
117
|
+
strategy = new Strategy({jwtFromRequest: extract_jwt.fromAuthHeaderAsBearerToken(), secretOrKey: 'secret'}, function(jwt_payload, next) {
|
|
118
|
+
throw new Error("EXCEPTION");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
chai.passport.use(strategy)
|
|
122
|
+
.error(function(e) {
|
|
123
|
+
err = e;
|
|
124
|
+
done();
|
|
125
|
+
})
|
|
126
|
+
.req(function(req) {
|
|
127
|
+
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
|
|
128
|
+
})
|
|
129
|
+
.authenticate();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
it('should error', function() {
|
|
134
|
+
expect(err).to.be.an.instanceof(Error);
|
|
135
|
+
expect(err.message).to.equal('EXCEPTION');
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
describe('handling a request with a valid jwt and option passReqToCallback is true', function() {
|
|
143
|
+
|
|
144
|
+
var strategy, expected_request, request_arg;
|
|
145
|
+
|
|
146
|
+
before(function(done) {
|
|
147
|
+
opts = { passReqToCallback: true };
|
|
148
|
+
opts.secretOrKey = 'secret';
|
|
149
|
+
opts.jwtFromRequest = extract_jwt.fromAuthHeaderAsBearerToken();
|
|
150
|
+
strategy = new Strategy(opts, function(request, jwt_payload, next) {
|
|
151
|
+
// Capture the value passed in as the request argument
|
|
152
|
+
request_arg = request;
|
|
153
|
+
return next(null, {user_id: 1234567890}, {foo:'bar'});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
chai.passport.use(strategy)
|
|
157
|
+
.success(function(u, i) {
|
|
158
|
+
done();
|
|
159
|
+
})
|
|
160
|
+
.req(function(req) {
|
|
161
|
+
req.headers['authorization'] = "bearer " + test_data.valid_jwt.token;
|
|
162
|
+
expected_request = req;
|
|
163
|
+
})
|
|
164
|
+
.authenticate();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('will call verify with request as the first argument', function() {
|
|
168
|
+
expect(expected_request).to.equal(request_arg);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
describe('handling a request when constructed with a secretOrKeyProvider function that succeeds', function() {
|
|
175
|
+
|
|
176
|
+
var strategy, fakeSecretOrKeyProvider, expectedReqeust;
|
|
177
|
+
|
|
178
|
+
before(function(done) {
|
|
179
|
+
fakeSecretOrKeyProvider = sinon.spy(function(request, token, done) {
|
|
180
|
+
done(null, 'secret from callback');
|
|
181
|
+
});
|
|
182
|
+
opts = {
|
|
183
|
+
secretOrKeyProvider: fakeSecretOrKeyProvider,
|
|
184
|
+
jwtFromRequest: function(request) {
|
|
185
|
+
return 'an undecoded jwt string';
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
strategy = new Strategy(opts, function(jwtPayload, next) {
|
|
189
|
+
return next(null, {user_id: 'dont care'}, {});
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
chai.passport.use(strategy)
|
|
193
|
+
.success(function(u, i) {
|
|
194
|
+
done();
|
|
195
|
+
})
|
|
196
|
+
.req(function(req) {
|
|
197
|
+
expectedReqeust = req;
|
|
198
|
+
})
|
|
199
|
+
.authenticate();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should call the fake secret or key provider with the reqeust', function() {
|
|
203
|
+
expect(fakeSecretOrKeyProvider.calledWith(expectedReqeust, sinon.match.any, sinon.match.any)).to.be.true;
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it('should call the secretOrKeyProvider with the undecoded jwt', function() {
|
|
207
|
+
expect(fakeSecretOrKeyProvider.calledWith(sinon.match.any, 'an undecoded jwt string', sinon.match.any)).to.be.true;
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should call JwtVerifier with the value returned from secretOrKeyProvider', function() {
|
|
211
|
+
expect(Strategy.JwtVerifier.calledWith(sinon.match.any, 'secret from callback', sinon.match.any, sinon.match.any)).to.be.true;
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
describe('handling a request when constructed with a secretOrKeyProvider function that errors', function() {
|
|
217
|
+
var errorMessage;
|
|
218
|
+
|
|
219
|
+
before(function(done) {
|
|
220
|
+
fakeSecretOrKeyProvider = sinon.spy(function(request, token, done) {
|
|
221
|
+
done('Error occurred looking for the secret');
|
|
222
|
+
});
|
|
223
|
+
opts = {
|
|
224
|
+
secretOrKeyProvider: fakeSecretOrKeyProvider,
|
|
225
|
+
jwtFromRequest: function(request) {
|
|
226
|
+
return 'an undecoded jwt string';
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
strategy = new Strategy(opts, function(jwtPayload, next) {
|
|
230
|
+
return next(null, {user_id: 'dont care'}, {});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
chai.passport.use(strategy)
|
|
234
|
+
.fail(function(i) {
|
|
235
|
+
errorMessage = i;
|
|
236
|
+
done();
|
|
237
|
+
})
|
|
238
|
+
.authenticate();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should fail with the error message from the secretOrKeyProvider', function() {
|
|
242
|
+
expect(errorMessage).to.equal('Error occurred looking for the secret');
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
});
|
package/test/testdata.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
// Note, this JWT will expire sometime in 2286. If unit tests are failing around this time try
|
|
3
|
+
// generating a new, valid token :)
|
|
4
|
+
valid_jwt : {
|
|
5
|
+
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjEyMzQ1Njc4OTAsIm5hbWUiOiJKb2huIERvZSIsImlzcyI6ImV4YW1wbGVzb2Z0LmNvbSIsImV4cCI6Ijk5OTk5OTk5OTkifQ.CbpI0TNI-FYXe6p3PgM__jwlz6aCT1qpUBsTVCfWuBM",
|
|
6
|
+
payload : {
|
|
7
|
+
"sub": "1234567890",
|
|
8
|
+
"name": "John Doe",
|
|
9
|
+
"iss": "examplesoft.com",
|
|
10
|
+
"exp": "9999999999"
|
|
11
|
+
},
|
|
12
|
+
secret: 'secret'
|
|
13
|
+
}
|
|
14
|
+
};
|