1 | import * as jwt from 'jsonwebtoken';
|
2 | import * as express from 'express';
|
3 | import expressUnless from 'express-unless';
|
4 | import { UnauthorizedError } from './errors/UnauthorizedError';
|
5 |
|
6 | export type GetVerificationKey = (req: express.Request, token: jwt.Jwt | undefined) => Promise<jwt.Secret>;
|
7 | export type IsRevoked = (req: express.Request, token: jwt.Jwt | undefined) => Promise<boolean>;
|
8 |
|
9 | type TokenGetter = (req: express.Request) => string | Promise<string> | undefined;
|
10 |
|
11 | type Params = {
|
12 | secret: jwt.Secret | GetVerificationKey,
|
13 | getToken?: TokenGetter,
|
14 | isRevoked?: IsRevoked,
|
15 | credentialsRequired?: boolean,
|
16 | } & jwt.VerifyOptions;
|
17 |
|
18 | export { UnauthorizedError } from './errors/UnauthorizedError';
|
19 |
|
20 | export type ExpressJwtRequest<T = jwt.JwtPayload> =
|
21 | express.Request & { auth: T }
|
22 |
|
23 |
|
24 | export const expressjwt = (options: Params) => {
|
25 | if (!options?.secret) throw new RangeError('express-jwt: `secret` is a required option');
|
26 | if (!options.algorithms) throw new RangeError('express-jwt: `algorithms` is a required option');
|
27 | if (!Array.isArray(options.algorithms)) throw new RangeError('express-jwt: `algorithms` must be an array');
|
28 |
|
29 | const getVerificationKey: GetVerificationKey =
|
30 | typeof options.secret === 'function' ?
|
31 | options.secret :
|
32 | async () => options.secret as jwt.Secret;
|
33 |
|
34 | const credentialsRequired = typeof options.credentialsRequired === 'undefined' ? true : options.credentialsRequired;
|
35 |
|
36 |
|
37 | const middleware = async function (req: express.Request, res: express.Response, next: express.NextFunction) {
|
38 | let token: string;
|
39 | try {
|
40 | if (req.method === 'OPTIONS' && 'access-control-request-headers' in req.headers) {
|
41 | const hasAuthInAccessControl = req.headers['access-control-request-headers']
|
42 | .split(',')
|
43 | .map(header => header.trim())
|
44 | .includes('authorization');
|
45 | if (hasAuthInAccessControl) {
|
46 | return next();
|
47 | }
|
48 | }
|
49 |
|
50 | if (options.getToken && typeof options.getToken === 'function') {
|
51 | token = await options.getToken(req);
|
52 | } else if (req.headers && req.headers.authorization) {
|
53 | const parts = req.headers.authorization.split(' ');
|
54 | if (parts.length == 2) {
|
55 | const scheme = parts[0];
|
56 | const credentials = parts[1];
|
57 |
|
58 | if (/^Bearer$/i.test(scheme)) {
|
59 | token = credentials;
|
60 | } else {
|
61 | if (credentialsRequired) {
|
62 | throw new UnauthorizedError('credentials_bad_scheme', { message: 'Format is Authorization: Bearer [token]' });
|
63 | } else {
|
64 | return next();
|
65 | }
|
66 | }
|
67 | } else {
|
68 | throw new UnauthorizedError('credentials_bad_format', { message: 'Format is Authorization: Bearer [token]' });
|
69 | }
|
70 | }
|
71 |
|
72 | if (!token) {
|
73 | if (credentialsRequired) {
|
74 | throw new UnauthorizedError('credentials_required', { message: 'No authorization token was found' });
|
75 | } else {
|
76 | return next();
|
77 | }
|
78 | }
|
79 |
|
80 | let decodedToken: jwt.Jwt;
|
81 |
|
82 | try {
|
83 | decodedToken = jwt.decode(token, { complete: true });
|
84 | } catch (err) {
|
85 | throw new UnauthorizedError('invalid_token', err);
|
86 | }
|
87 |
|
88 | const key = await getVerificationKey(req, decodedToken);
|
89 |
|
90 | try {
|
91 | jwt.verify(token, key, options);
|
92 | } catch (err) {
|
93 | throw new UnauthorizedError('invalid_token', err);
|
94 | }
|
95 |
|
96 | const isRevoked = options.isRevoked && await options.isRevoked(req, decodedToken) || false;
|
97 | if (isRevoked) {
|
98 | throw new UnauthorizedError('revoked_token', { message: 'The token has been revoked.' });
|
99 | }
|
100 |
|
101 | const request = req as ExpressJwtRequest<jwt.JwtPayload | string>;
|
102 | request.auth = decodedToken.payload;
|
103 | next();
|
104 | } catch (err) {
|
105 | return next(err);
|
106 | }
|
107 | };
|
108 |
|
109 | middleware.unless = expressUnless;
|
110 |
|
111 | return middleware;
|
112 | }
|
113 |
|
114 |
|