UNPKG

13.1 kBPlain TextView Raw
1/* eslint-disable @typescript-eslint/ban-ts-comment */
2import * as jwt from 'jsonwebtoken';
3import * as express from 'express';
4import { expressjwt, UnauthorizedError, ExpressJwtRequest, GetVerificationKey } from '../src';
5import assert from 'assert';
6
7
8describe('failure tests', function () {
9 const req = {} as express.Request;
10 const res = {} as express.Response;
11
12 it('should throw if options not sent', function () {
13 try {
14 // @ts-ignore
15 expressjwt();
16 } catch (e) {
17 assert.ok(e);
18 assert.equal(e.message, "express-jwt: `secret` is a required option");
19 }
20 });
21
22 it('should throw if algorithms is not sent', function () {
23 try {
24 // @ts-ignore
25 expressjwt({ secret: 'shhhh' });
26 } catch (e) {
27 assert.ok(e);
28 assert.equal(e.message, 'express-jwt: `algorithms` is a required option');
29 }
30 });
31
32 it('should throw if algorithms is not an array', function () {
33 try {
34 // @ts-ignore
35 expressjwt({ secret: 'shhhh', algorithms: 'foo' });
36 } catch (e) {
37 assert.ok(e);
38 assert.equal(e.message, 'express-jwt: `algorithms` must be an array');
39 }
40 });
41
42 it('should throw if no authorization header and credentials are required', function (done) {
43 expressjwt({ secret: 'shhhh', credentialsRequired: true, algorithms: ['HS256'] })(req, res, function (err) {
44 assert.ok(err);
45 assert.equal(err.code, 'credentials_required');
46 done();
47 });
48 });
49
50 it('support unless skip', function (done) {
51 req.originalUrl = '/index.html';
52 expressjwt({ secret: 'shhhh', algorithms: ['HS256'] }).unless({ path: '/index.html' })(req, res, function (err) {
53 assert.ok(!err);
54 done();
55 });
56 });
57
58 it('should skip on CORS preflight', function (done) {
59 const corsReq = {} as express.Request;
60 corsReq.method = 'OPTIONS';
61 corsReq.headers = {
62 'access-control-request-headers': 'sasa, sras, authorization'
63 };
64 expressjwt({ secret: 'shhhh', algorithms: ['HS256'] })(corsReq, res, function (err) {
65 assert.ok(!err);
66 done();
67 });
68 });
69
70 it('should throw if authorization header is malformed', function (done) {
71 req.headers = {};
72 req.headers.authorization = 'wrong';
73 expressjwt({ secret: 'shhhh', algorithms: ['HS256'] })(req, res, function (err) {
74 assert.ok(err);
75 assert.equal(err.code, 'credentials_bad_format');
76 done();
77 });
78 });
79
80 it('should throw if authorization header is not Bearer', function () {
81 req.headers = {};
82 req.headers.authorization = 'Basic foobar';
83 expressjwt({ secret: 'shhhh', algorithms: ['HS256'] })(req, res, function (err) {
84 assert.ok(err);
85 assert.equal(err.code, 'credentials_bad_scheme');
86 });
87 });
88
89 it('should next if authorization header is not Bearer and credentialsRequired is false', function (done) {
90 req.headers = {};
91 req.headers.authorization = 'Basic foobar';
92 expressjwt({ secret: 'shhhh', algorithms: ['HS256'], credentialsRequired: false })(req, res, function (err) {
93 assert.ok(typeof err === 'undefined');
94 done();
95 });
96 });
97
98 it('should throw if authorization header is not well-formatted jwt', function (done) {
99 req.headers = {};
100 req.headers.authorization = 'Bearer wrongjwt';
101 expressjwt({ secret: 'shhhh', algorithms: ['HS256'] })(req, res, function (err) {
102 assert.ok(err);
103 assert.equal(err.code, 'invalid_token');
104 done();
105 });
106 });
107
108 it('should throw if jwt is an invalid json', function (done) {
109 req.headers = {};
110 req.headers.authorization = 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.yJ1c2VybmFtZSI6InNhZ3VpYXIiLCJpYXQiOjE0NzEwMTg2MzUsImV4cCI6MTQ3MzYxMDYzNX0.foo';
111 expressjwt({ secret: 'shhhh', algorithms: ['HS256'] })(req, res, function (err) {
112 assert.ok(err);
113 assert.equal(err.code, 'invalid_token');
114 done();
115 });
116 });
117
118 it('should throw if authorization header is not valid jwt', function (done) {
119 const secret = 'shhhhhh';
120 const token = jwt.sign({ foo: 'bar' }, secret);
121
122 req.headers = {};
123 req.headers.authorization = 'Bearer ' + token;
124 expressjwt({ secret: 'different-shhhh', algorithms: ['HS256'] })(req, res, function (err) {
125 assert.ok(err);
126 assert.equal(err.code, 'invalid_token');
127 assert.equal(err.message, 'invalid signature');
128 done()
129 });
130 });
131
132 it('should throw if audience is not expected', function (done) {
133 const secret = 'shhhhhh';
134 const token = jwt.sign({ foo: 'bar', aud: 'expected-audience' }, secret, { expiresIn: 500 });
135
136 req.headers = {};
137 req.headers.authorization = 'Bearer ' + token;
138 expressjwt({ secret: 'shhhhhh', algorithms: ['HS256'], audience: 'not-expected-audience' })(req, res, function (err) {
139 assert.ok(err);
140 assert.equal(err.code, 'invalid_token');
141 assert.equal(err.message, 'jwt audience invalid. expected: not-expected-audience');
142 done();
143 });
144 });
145
146 it('should throw if token is expired', function (done) {
147 const secret = 'shhhhhh';
148 const token = jwt.sign({ foo: 'bar', exp: 1382412921 }, secret);
149
150 req.headers = {};
151 req.headers.authorization = 'Bearer ' + token;
152 expressjwt({ secret: 'shhhhhh', algorithms: ['HS256'] })(req, res, function (err) {
153 assert.ok(err);
154 assert.equal(err.code, 'invalid_token');
155 assert.equal(err.inner.name, 'TokenExpiredError');
156 assert.equal(err.message, 'jwt expired');
157 done();
158 });
159 });
160
161 it('should throw if token issuer is wrong', function (done) {
162 const secret = 'shhhhhh';
163 const token = jwt.sign({ foo: 'bar', iss: 'http://foo' }, secret);
164
165 req.headers = {};
166 req.headers.authorization = 'Bearer ' + token;
167 expressjwt({ secret: 'shhhhhh', algorithms: ['HS256'], issuer: 'http://wrong' })(req, res, function (err) {
168 assert.ok(err);
169 assert.equal(err.code, 'invalid_token');
170 assert.equal(err.message, 'jwt issuer invalid. expected: http://wrong');
171 done();
172 });
173 });
174
175 it('should use errors thrown from custom getToken function', function (done) {
176 expressjwt({
177 secret: 'shhhhhh', algorithms: ['HS256'],
178 getToken: () => { throw new UnauthorizedError('invalid_token', { message: 'Invalid token!' }); }
179 })(req, res, function (err) {
180 assert.ok(err);
181 assert.equal(err.code, 'invalid_token');
182 assert.equal(err.message, 'Invalid token!');
183 done();
184 });
185 });
186
187 it('should throw error when signature is wrong', function (done) {
188 const secret = "shhh";
189 const token = jwt.sign({ foo: 'bar', iss: 'http://www' }, secret);
190 // manipulate the token
191 const newContent = Buffer.from("{foo: 'bar', edg: 'ar'}").toString('base64');
192 const splitetToken = token.split(".");
193 splitetToken[1] = newContent;
194 const newToken = splitetToken.join(".");
195 // build request
196 // @ts-ignore
197 req.headers = [];
198 req.headers.authorization = 'Bearer ' + newToken;
199 expressjwt({ secret: secret, algorithms: ['HS256'] })(req, res, function (err) {
200 assert.ok(err);
201 assert.equal(err.code, 'invalid_token');
202 assert.equal(err.message, 'invalid token');
203 done();
204 });
205 });
206
207 it('should throw error if token is expired even with when credentials are not required', function (done) {
208 const secret = 'shhhhhh';
209 const token = jwt.sign({ foo: 'bar', exp: 1382412921 }, secret);
210
211 req.headers = {};
212 req.headers.authorization = 'Bearer ' + token;
213 expressjwt({ secret: secret, credentialsRequired: false, algorithms: ['HS256'] })(req, res, function (err) {
214 assert.ok(err);
215 assert.equal(err.code, 'invalid_token');
216 assert.equal(err.message, 'jwt expired');
217 done();
218 });
219 });
220
221 it('should throw error if token is invalid even with when credentials are not required', function (done) {
222 const secret = 'shhhhhh';
223 const token = jwt.sign({ foo: 'bar', exp: 1382412921 }, secret);
224
225 req.headers = {};
226 req.headers.authorization = 'Bearer ' + token;
227 expressjwt({ secret: "not the secret", algorithms: ['HS256'], credentialsRequired: false })(req, res, function (err) {
228 assert.ok(err);
229 assert.equal(err.code, 'invalid_token');
230 assert.equal(err.message, 'invalid signature');
231 done();
232 });
233 });
234
235});
236
237describe('work tests', function () {
238 // var req = {} as express.Request;
239 // var res = {} as express.Response;
240
241 it('should work if authorization header is valid jwt', function (done) {
242 const secret = 'shhhhhh';
243 const token = jwt.sign({ foo: 'bar' }, secret);
244 const req = {} as ExpressJwtRequest;
245 const res = {} as express.Response;
246 req.headers = {};
247 req.headers.authorization = 'Bearer ' + token;
248 expressjwt({ secret: secret, algorithms: ['HS256'] })(req, res, function () {
249 assert.equal(req.auth.foo, 'bar');
250 done();
251 });
252 });
253
254 it('should work if authorization header is valid with a buffer secret', function (done) {
255 const secret = Buffer.from('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'base64');
256 const token = jwt.sign({ foo: 'bar' }, secret);
257 const req = {} as ExpressJwtRequest;
258 const res = {} as express.Response;
259
260 req.headers = {};
261 req.headers.authorization = 'Bearer ' + token;
262 expressjwt({ secret: secret, algorithms: ['HS256'] })(req, res, function () {
263 assert.equal(req.auth.foo, 'bar');
264 done();
265 });
266 });
267
268 it('should work if Authorization header is capitalized (lambda environment)', function (done) {
269 const secret = Buffer.from('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'base64');
270 const token = jwt.sign({ foo: 'bar' }, secret);
271 const req = {} as ExpressJwtRequest;
272 const res = {} as express.Response;
273
274 req.headers = {};
275 req.headers.Authorization = 'Bearer ' + token;
276 expressjwt({ secret: secret, algorithms: ['HS256'] })(req, res, function (err) {
277 if (err) { return done(err); }
278 assert.equal(req.auth.foo, 'bar');
279 done();
280 });
281 });
282
283 it('should work if no authorization header and credentials are not required', function (done) {
284 const req = {} as express.Request;
285 const res = {} as express.Response;
286 expressjwt({ secret: 'shhhh', algorithms: ['HS256'], credentialsRequired: false })(req, res, done);
287 });
288
289 it('should not work if no authorization header', function (done) {
290 const req = {} as express.Request;
291 const res = {} as express.Response;
292 expressjwt({ secret: 'shhhh', algorithms: ['HS256'] })(req, res, function (err) {
293 assert(typeof err !== 'undefined');
294 done();
295 });
296 });
297
298 it('should produce a stack trace that includes the failure reason', function (done) {
299 const req = {} as express.Request;
300 const res = {} as express.Response;
301 const token = jwt.sign({ foo: 'bar' }, 'secretA');
302 req.headers = {};
303 req.headers.authorization = 'Bearer ' + token;
304
305 expressjwt({ secret: 'secretB', algorithms: ['HS256'] })(req, res, function (err) {
306 const index = err.stack.indexOf('UnauthorizedError: invalid signature')
307 assert.equal(index, 0, "Stack trace didn't include 'invalid signature' message.")
308 done();
309 });
310
311 });
312
313 it('should work with a custom getToken function', function (done) {
314 const req = {} as ExpressJwtRequest;
315 const res = {} as express.Response;
316 const secret = 'shhhhhh';
317 const token = jwt.sign({ foo: 'bar' }, secret);
318
319 req.headers = {};
320 req.query = {};
321 req.query.token = token;
322
323 function getTokenFromQuery(req) {
324 return req.query.token;
325 }
326
327 expressjwt({
328 secret: secret,
329 algorithms: ['HS256'],
330 getToken: getTokenFromQuery
331 })(req, res, function () {
332 assert.equal(req.auth.foo, 'bar');
333 done();
334 });
335 });
336
337 it('should work with an async getToken function', function (done) {
338 const req = {} as ExpressJwtRequest;
339 const res = {} as express.Response;
340 const secret = 'shhhhhh';
341 const token = jwt.sign({ foo: 'bar' }, secret);
342
343 req.headers = {};
344 req.query = {};
345 req.query.token = token;
346
347 function getTokenFromQuery(req) {
348 return Promise.resolve(req.query.token);
349 }
350
351 expressjwt({
352 secret: secret,
353 algorithms: ['HS256'],
354 getToken: getTokenFromQuery
355 })(req, res, function () {
356 assert.equal(req.auth.foo, 'bar');
357 done();
358 });
359 });
360
361 it('should work with a secretCallback function that accepts header argument', function (done) {
362 const req = {} as ExpressJwtRequest;
363 const res = {} as express.Response;
364 const secret = 'shhhhhh';
365 const getSecret: GetVerificationKey = async (req, token) => {
366 assert.equal(token.header.alg, 'HS256');
367 // @ts-ignore
368 assert.equal(token.payload.foo, 'bar');
369 return secret;
370 };
371
372 const token = jwt.sign({ foo: 'bar' }, secret);
373
374 req.headers = {};
375 req.headers.authorization = 'Bearer ' + token;
376 expressjwt({ secret: getSecret, algorithms: ['HS256'] })(req, res, function () {
377 assert.equal(req.auth.foo, 'bar');
378 done();
379 });
380 });
381});