UNPKG

14.7 kBMarkdownView Raw
1# jsonwebtoken
2
3| **Build** | **Dependency** |
4|-----------|---------------|
5| [![Build Status](https://secure.travis-ci.org/auth0/node-jsonwebtoken.svg?branch=master)](http://travis-ci.org/auth0/node-jsonwebtoken) | [![Dependency Status](https://david-dm.org/auth0/node-jsonwebtoken.svg)](https://david-dm.org/auth0/node-jsonwebtoken) |
6
7
8An implementation of [JSON Web Tokens](https://tools.ietf.org/html/rfc7519).
9
10This was developed against `draft-ietf-oauth-json-web-token-08`. It makes use of [node-jws](https://github.com/brianloveswords/node-jws)
11
12# Install
13
14```bash
15$ npm install jsonwebtoken
16```
17
18# Migration notes
19
20* [From v7 to v8](https://github.com/auth0/node-jsonwebtoken/wiki/Migration-Notes:-v7-to-v8)
21
22# Usage
23
24### jwt.sign(payload, secretOrPrivateKey, [options, callback])
25
26(Asynchronous) If a callback is supplied, the callback is called with the `err` or the JWT.
27
28(Synchronous) Returns the JsonWebToken as string
29
30`payload` could be an object literal, buffer or string representing valid JSON.
31> **Please _note_ that** `exp` or any other claim is only set if the payload is an object literal. Buffer or string payloads are not checked for JSON validity.
32
33> If `payload` is not a buffer or a string, it will be coerced into a string using `JSON.stringify`.
34
35`secretOrPrivateKey` is a string, buffer, or object containing either the secret for HMAC algorithms or the PEM
36encoded private key for RSA and ECDSA. In case of a private key with passphrase an object `{ key, passphrase }` can be used (based on [crypto documentation](https://nodejs.org/api/crypto.html#crypto_sign_sign_private_key_output_format)), in this case be sure you pass the `algorithm` option.
37
38`options`:
39
40* `algorithm` (default: `HS256`)
41* `expiresIn`: expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms).
42 > Eg: `60`, `"2 days"`, `"10h"`, `"7d"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`"120"` is equal to `"120ms"`).
43* `notBefore`: expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms).
44 > Eg: `60`, `"2 days"`, `"10h"`, `"7d"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`"120"` is equal to `"120ms"`).
45* `audience`
46* `issuer`
47* `jwtid`
48* `subject`
49* `noTimestamp`
50* `header`
51* `keyid`
52* `mutatePayload`: if true, the sign function will modify the payload object directly. This is useful if you need a raw reference to the payload after claims have been applied to it but before it has been encoded into a token.
53
54
55
56> There are no default values for `expiresIn`, `notBefore`, `audience`, `subject`, `issuer`. These claims can also be provided in the payload directly with `exp`, `nbf`, `aud`, `sub` and `iss` respectively, but you **_can't_** include in both places.
57
58Remember that `exp`, `nbf` and `iat` are **NumericDate**, see related [Token Expiration (exp claim)](#token-expiration-exp-claim)
59
60
61The header can be customized via the `options.header` object.
62
63Generated jwts will include an `iat` (issued at) claim by default unless `noTimestamp` is specified. If `iat` is inserted in the payload, it will be used instead of the real timestamp for calculating other things like `exp` given a timespan in `options.expiresIn`.
64
65Synchronous Sign with default (HMAC SHA256)
66
67```js
68var jwt = require('jsonwebtoken');
69var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
70```
71
72Synchronous Sign with RSA SHA256
73```js
74// sign with RSA SHA256
75var privateKey = fs.readFileSync('private.key');
76var token = jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256'});
77```
78
79Sign asynchronously
80```js
81jwt.sign({ foo: 'bar' }, privateKey, { algorithm: 'RS256' }, function(err, token) {
82 console.log(token);
83});
84```
85
86Backdate a jwt 30 seconds
87```js
88var older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh');
89```
90
91#### Token Expiration (exp claim)
92
93The standard for JWT defines an `exp` claim for expiration. The expiration is represented as a **NumericDate**:
94
95> A JSON numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds. This is equivalent to the IEEE Std 1003.1, 2013 Edition [POSIX.1] definition "Seconds Since the Epoch", in which each day is accounted for by exactly 86400 seconds, other than that non-integer values can be represented. See RFC 3339 [RFC3339] for details regarding date/times in general and UTC in particular.
96
97This means that the `exp` field should contain the number of seconds since the epoch.
98
99Signing a token with 1 hour of expiration:
100
101```javascript
102jwt.sign({
103 exp: Math.floor(Date.now() / 1000) + (60 * 60),
104 data: 'foobar'
105}, 'secret');
106```
107
108Another way to generate a token like this with this library is:
109
110```javascript
111jwt.sign({
112 data: 'foobar'
113}, 'secret', { expiresIn: 60 * 60 });
114
115//or even better:
116
117jwt.sign({
118 data: 'foobar'
119}, 'secret', { expiresIn: '1h' });
120```
121
122### jwt.verify(token, secretOrPublicKey, [options, callback])
123
124(Asynchronous) If a callback is supplied, function acts asynchronously. The callback is called with the decoded payload if the signature is valid and optional expiration, audience, or issuer are valid. If not, it will be called with the error.
125
126(Synchronous) If a callback is not supplied, function acts synchronously. Returns the payload decoded if the signature is valid and optional expiration, audience, or issuer are valid. If not, it will throw the error.
127
128`token` is the JsonWebToken string
129
130`secretOrPublicKey` is a string or buffer containing either the secret for HMAC algorithms, or the PEM
131encoded public key for RSA and ECDSA.
132If `jwt.verify` is called asynchronous, `secretOrPublicKey` can be a function that should fetch the secret or public key. See below for a detailed example
133
134As mentioned in [this comment](https://github.com/auth0/node-jsonwebtoken/issues/208#issuecomment-231861138), there are other libraries that expect base64 encoded secrets (random bytes encoded using base64), if that is your case you can pass `Buffer.from(secret, 'base64')`, by doing this the secret will be decoded using base64 and the token verification will use the original random bytes.
135
136`options`
137
138* `algorithms`: List of strings with the names of the allowed algorithms. For instance, `["HS256", "HS384"]`.
139* `audience`: if you want to check audience (`aud`), provide a value here. The audience can be checked against a string, a regular expression or a list of strings and/or regular expressions.
140 > Eg: `"urn:foo"`, `/urn:f[o]{2}/`, `[/urn:f[o]{2}/, "urn:bar"]`
141* `complete`: return an object with the decoded `{ payload, header, signature }` instead of only the usual content of the payload.
142* `issuer` (optional): string or array of strings of valid values for the `iss` field.
143* `ignoreExpiration`: if `true` do not validate the expiration of the token.
144* `ignoreNotBefore`...
145* `subject`: if you want to check subject (`sub`), provide a value here
146* `clockTolerance`: number of seconds to tolerate when checking the `nbf` and `exp` claims, to deal with small clock differences among different servers
147* `maxAge`: the maximum allowed age for tokens to still be valid. It is expressed in seconds or a string describing a time span [zeit/ms](https://github.com/zeit/ms).
148 > Eg: `1000`, `"2 days"`, `"10h"`, `"7d"`. A numeric value is interpreted as a seconds count. If you use a string be sure you provide the time units (days, hours, etc), otherwise milliseconds unit is used by default (`"120"` is equal to `"120ms"`).
149* `clockTimestamp`: the time in seconds that should be used as the current time for all necessary comparisons.
150* `nonce`: if you want to check `nonce` claim, provide a string value here. It is used on Open ID for the ID Tokens. ([Open ID implementation notes](https://openid.net/specs/openid-connect-core-1_0.html#NonceNotes))
151
152
153```js
154// verify a token symmetric - synchronous
155var decoded = jwt.verify(token, 'shhhhh');
156console.log(decoded.foo) // bar
157
158// verify a token symmetric
159jwt.verify(token, 'shhhhh', function(err, decoded) {
160 console.log(decoded.foo) // bar
161});
162
163// invalid token - synchronous
164try {
165 var decoded = jwt.verify(token, 'wrong-secret');
166} catch(err) {
167 // err
168}
169
170// invalid token
171jwt.verify(token, 'wrong-secret', function(err, decoded) {
172 // err
173 // decoded undefined
174});
175
176// verify a token asymmetric
177var cert = fs.readFileSync('public.pem'); // get public key
178jwt.verify(token, cert, function(err, decoded) {
179 console.log(decoded.foo) // bar
180});
181
182// verify audience
183var cert = fs.readFileSync('public.pem'); // get public key
184jwt.verify(token, cert, { audience: 'urn:foo' }, function(err, decoded) {
185 // if audience mismatch, err == invalid audience
186});
187
188// verify issuer
189var cert = fs.readFileSync('public.pem'); // get public key
190jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer' }, function(err, decoded) {
191 // if issuer mismatch, err == invalid issuer
192});
193
194// verify jwt id
195var cert = fs.readFileSync('public.pem'); // get public key
196jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid' }, function(err, decoded) {
197 // if jwt id mismatch, err == invalid jwt id
198});
199
200// verify subject
201var cert = fs.readFileSync('public.pem'); // get public key
202jwt.verify(token, cert, { audience: 'urn:foo', issuer: 'urn:issuer', jwtid: 'jwtid', subject: 'subject' }, function(err, decoded) {
203 // if subject mismatch, err == invalid subject
204});
205
206// alg mismatch
207var cert = fs.readFileSync('public.pem'); // get public key
208jwt.verify(token, cert, { algorithms: ['RS256'] }, function (err, payload) {
209 // if token alg != RS256, err == invalid signature
210});
211
212// Verify using getKey callback
213// Example uses https://github.com/auth0/node-jwks-rsa as a way to fetch the keys.
214var jwksClient = require('jwks-rsa');
215var client = jwksClient({
216 jwksUri: 'https://sandrino.auth0.com/.well-known/jwks.json'
217});
218function getKey(header, callback){
219 client.getSigningKey(header.kid, function(err, key) {
220 var signingKey = key.publicKey || key.rsaPublicKey;
221 callback(null, signingKey);
222 });
223}
224
225jwt.verify(token, getKey, options, function(err, decoded) {
226 console.log(decoded.foo) // bar
227});
228
229```
230
231### jwt.decode(token [, options])
232
233(Synchronous) Returns the decoded payload without verifying if the signature is valid.
234
235> __Warning:__ This will __not__ verify whether the signature is valid. You should __not__ use this for untrusted messages. You most likely want to use `jwt.verify` instead.
236
237`token` is the JsonWebToken string
238
239`options`:
240
241* `json`: force JSON.parse on the payload even if the header doesn't contain `"typ":"JWT"`.
242* `complete`: return an object with the decoded payload and header.
243
244Example
245
246```js
247// get the decoded payload ignoring signature, no secretOrPrivateKey needed
248var decoded = jwt.decode(token);
249
250// get the decoded payload and header
251var decoded = jwt.decode(token, {complete: true});
252console.log(decoded.header);
253console.log(decoded.payload)
254```
255
256## Errors & Codes
257Possible thrown errors during verification.
258Error is the first argument of the verification callback.
259
260### TokenExpiredError
261
262Thrown error if the token is expired.
263
264Error object:
265
266* name: 'TokenExpiredError'
267* message: 'jwt expired'
268* expiredAt: [ExpDate]
269
270```js
271jwt.verify(token, 'shhhhh', function(err, decoded) {
272 if (err) {
273 /*
274 err = {
275 name: 'TokenExpiredError',
276 message: 'jwt expired',
277 expiredAt: 1408621000
278 }
279 */
280 }
281});
282```
283
284### JsonWebTokenError
285Error object:
286
287* name: 'JsonWebTokenError'
288* message:
289 * 'jwt malformed'
290 * 'jwt signature is required'
291 * 'invalid signature'
292 * 'jwt audience invalid. expected: [OPTIONS AUDIENCE]'
293 * 'jwt issuer invalid. expected: [OPTIONS ISSUER]'
294 * 'jwt id invalid. expected: [OPTIONS JWT ID]'
295 * 'jwt subject invalid. expected: [OPTIONS SUBJECT]'
296
297```js
298jwt.verify(token, 'shhhhh', function(err, decoded) {
299 if (err) {
300 /*
301 err = {
302 name: 'JsonWebTokenError',
303 message: 'jwt malformed'
304 }
305 */
306 }
307});
308```
309
310### NotBeforeError
311Thrown if current time is before the nbf claim.
312
313Error object:
314
315* name: 'NotBeforeError'
316* message: 'jwt not active'
317* date: 2018-10-04T16:10:44.000Z
318
319```js
320jwt.verify(token, 'shhhhh', function(err, decoded) {
321 if (err) {
322 /*
323 err = {
324 name: 'NotBeforeError',
325 message: 'jwt not active',
326 date: 2018-10-04T16:10:44.000Z
327 }
328 */
329 }
330});
331```
332
333
334## Algorithms supported
335
336Array of supported algorithms. The following algorithms are currently supported.
337
338alg Parameter Value | Digital Signature or MAC Algorithm
339----------------|----------------------------
340HS256 | HMAC using SHA-256 hash algorithm
341HS384 | HMAC using SHA-384 hash algorithm
342HS512 | HMAC using SHA-512 hash algorithm
343RS256 | RSASSA-PKCS1-v1_5 using SHA-256 hash algorithm
344RS384 | RSASSA-PKCS1-v1_5 using SHA-384 hash algorithm
345RS512 | RSASSA-PKCS1-v1_5 using SHA-512 hash algorithm
346PS256 | RSASSA-PSS using SHA-256 hash algorithm (only node ^6.12.0 OR >=8.0.0)
347PS384 | RSASSA-PSS using SHA-384 hash algorithm (only node ^6.12.0 OR >=8.0.0)
348PS512 | RSASSA-PSS using SHA-512 hash algorithm (only node ^6.12.0 OR >=8.0.0)
349ES256 | ECDSA using P-256 curve and SHA-256 hash algorithm
350ES384 | ECDSA using P-384 curve and SHA-384 hash algorithm
351ES512 | ECDSA using P-521 curve and SHA-512 hash algorithm
352none | No digital signature or MAC value included
353
354## Refreshing JWTs
355
356First of all, we recommend you to think carefully if auto-refreshing a JWT will not introduce any vulnerability in your system.
357
358We are not comfortable including this as part of the library, however, you can take a look at [this example](https://gist.github.com/ziluvatar/a3feb505c4c0ec37059054537b38fc48) to show how this could be accomplished.
359Apart from that example there are [an issue](https://github.com/auth0/node-jsonwebtoken/issues/122) and [a pull request](https://github.com/auth0/node-jsonwebtoken/pull/172) to get more knowledge about this topic.
360
361# TODO
362
363* X.509 certificate chain is not checked
364
365## Issue Reporting
366
367If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.
368
369## Author
370
371[Auth0](https://auth0.com)
372
373## License
374
375This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info.