thoughts/node_modules/jsonwebtoken/verify.js
node_modules/jsonwebtoken/verify.jsRaw
1var JsonWebTokenError = require('./lib/JsonWebTokenError');
2var NotBeforeError = require('./lib/NotBeforeError');
3var TokenExpiredError = require('./lib/TokenExpiredError');
4var decode = require('./decode');
5var jws = require('jws');
6var ms = require('ms');
7var xtend = require('xtend');
8
9module.exports = function (jwtString, secretOrPublicKey, options, callback) {
10 if ((typeof options === 'function') && !callback) {
11 callback = options;
12 options = {};
13 }
14
15 if (!options) {
16 options = {};
17 }
18
19 //clone this object since we are going to mutate it.
20 options = xtend(options);
21 var done;
22
23 if (callback) {
24 done = function() {
25 var args = Array.prototype.slice.call(arguments, 0);
26 return process.nextTick(function() {
27 callback.apply(null, args);
28 });
29 };
30 } else {
31 done = function(err, data) {
32 if (err) throw err;
33 return data;
34 };
35 }
36
37 if (!jwtString){
38 return done(new JsonWebTokenError('jwt must be provided'));
39 }
40
41 var parts = jwtString.split('.');
42
43 if (parts.length !== 3){
44 return done(new JsonWebTokenError('jwt malformed'));
45 }
46
47 var hasSignature = parts[2].trim() !== '';
48
49 if (!hasSignature && secretOrPublicKey){
50 return done(new JsonWebTokenError('jwt signature is required'));
51 }
52
53 if (hasSignature && !secretOrPublicKey) {
54 return done(new JsonWebTokenError('secret or public key must be provided'));
55 }
56
57 if (!hasSignature && !options.algorithms) {
58 options.algorithms = ['none'];
59 }
60
61 if (!options.algorithms) {
62 options.algorithms = ~secretOrPublicKey.toString().indexOf('BEGIN CERTIFICATE') ||
63 ~secretOrPublicKey.toString().indexOf('BEGIN PUBLIC KEY') ?
64 [ 'RS256','RS384','RS512','ES256','ES384','ES512' ] :
65 ~secretOrPublicKey.toString().indexOf('BEGIN RSA PUBLIC KEY') ?
66 [ 'RS256','RS384','RS512' ] :
67 [ 'HS256','HS384','HS512' ];
68
69 }
70
71 var decodedToken;
72 try {
73 decodedToken = jws.decode(jwtString);
74 } catch(err) {
75 return done(new JsonWebTokenError('invalid token'));
76 }
77
78 if (!decodedToken) {
79 return done(new JsonWebTokenError('invalid token'));
80 }
81
82 var header = decodedToken.header;
83
84 if (!~options.algorithms.indexOf(header.alg)) {
85 return done(new JsonWebTokenError('invalid algorithm'));
86 }
87
88 var valid;
89
90 try {
91 valid = jws.verify(jwtString, header.alg, secretOrPublicKey);
92 } catch (e) {
93 return done(e);
94 }
95
96 if (!valid)
97 return done(new JsonWebTokenError('invalid signature'));
98
99 var payload;
100
101 try {
102 payload = decode(jwtString);
103 } catch(err) {
104 return done(err);
105 }
106
107 if (typeof payload.nbf !== 'undefined' && !options.ignoreNotBefore) {
108 if (typeof payload.nbf !== 'number') {
109 return done(new JsonWebTokenError('invalid nbf value'));
110 }
111 if (payload.nbf > Math.floor(Date.now() / 1000) + (options.clockTolerance || 0)) {
112 return done(new NotBeforeError('jwt not active', new Date(payload.nbf * 1000)));
113 }
114 }
115
116 if (typeof payload.exp !== 'undefined' && !options.ignoreExpiration) {
117 if (typeof payload.exp !== 'number') {
118 return done(new JsonWebTokenError('invalid exp value'));
119 }
120 if (Math.floor(Date.now() / 1000) >= payload.exp + (options.clockTolerance || 0)) {
121 return done(new TokenExpiredError('jwt expired', new Date(payload.exp * 1000)));
122 }
123 }
124
125 if (options.audience) {
126 var audiences = Array.isArray(options.audience)? options.audience : [options.audience];
127 var target = Array.isArray(payload.aud) ? payload.aud : [payload.aud];
128
129 var match = target.some(function(aud) { return audiences.indexOf(aud) != -1; });
130
131 if (!match)
132 return done(new JsonWebTokenError('jwt audience invalid. expected: ' + audiences.join(' or ')));
133 }
134
135 if (options.issuer) {
136 var invalid_issuer =
137 (typeof options.issuer === 'string' && payload.iss !== options.issuer) ||
138 (Array.isArray(options.issuer) && options.issuer.indexOf(payload.iss) === -1);
139
140 if (invalid_issuer) {
141 return done(new JsonWebTokenError('jwt issuer invalid. expected: ' + options.issuer));
142 }
143 }
144
145 if (options.subject) {
146 if (payload.sub !== options.subject) {
147 return done(new JsonWebTokenError('jwt subject invalid. expected: ' + options.subject));
148 }
149 }
150
151 if (options.jwtid) {
152 if (payload.jti !== options.jwtid) {
153 return done(new JsonWebTokenError('jwt jwtid invalid. expected: ' + options.jwtid));
154 }
155 }
156
157 if (options.maxAge) {
158 var maxAge = ms(options.maxAge);
159 if (typeof payload.iat !== 'number') {
160 return done(new JsonWebTokenError('iat required when maxAge is specified'));
161 }
162 if (Date.now() - (payload.iat * 1000) > maxAge + (options.clockTolerance || 0) * 1000) {
163 return done(new TokenExpiredError('maxAge exceeded', new Date(payload.iat * 1000 + maxAge)));
164 }
165 }
166
167 return done(null, payload);
168};