UNPKG

2.71 kBJavaScriptView Raw
1const isObject = require('../help/is_object')
2const secs = require('../help/secs')
3const epoch = require('../help/epoch')
4const getKey = require('../help/get_key')
5const JWS = require('../jws')
6
7const isString = require('./shared_validations').isString.bind(undefined, TypeError)
8
9const validateOptions = (options) => {
10 if (typeof options.iat !== 'boolean') {
11 throw new TypeError('options.iat must be a boolean')
12 }
13
14 if (typeof options.kid !== 'boolean') {
15 throw new TypeError('options.kid must be a boolean')
16 }
17
18 isString(options.subject, 'options.subject')
19 isString(options.issuer, 'options.issuer')
20
21 if (
22 options.audience !== undefined &&
23 (
24 (typeof options.audience !== 'string' || !options.audience) &&
25 (!Array.isArray(options.audience) || options.audience.length === 0 || options.audience.some(a => !a || typeof a !== 'string'))
26 )
27 ) {
28 throw new TypeError('options.audience must be a string or an array of strings')
29 }
30
31 if (!isObject(options.header)) {
32 throw new TypeError('options.header must be an object')
33 }
34
35 isString(options.algorithm, 'options.algorithm')
36 isString(options.expiresIn, 'options.expiresIn')
37 isString(options.notBefore, 'options.notBefore')
38 isString(options.jti, 'options.jti')
39 isString(options.nonce, 'options.nonce')
40
41 if (options.now !== undefined && (!(options.now instanceof Date) || !options.now.getTime())) {
42 throw new TypeError('options.now must be a valid Date object')
43 }
44}
45
46module.exports = (payload, key, options = {}) => {
47 if (!isObject(options)) {
48 throw new TypeError('options must be an object')
49 }
50
51 const {
52 algorithm, audience, expiresIn, header = {}, iat = true,
53 issuer, jti, kid = true, nonce, notBefore, subject, now
54 } = options
55
56 validateOptions({
57 algorithm, audience, expiresIn, header, iat, issuer, jti, kid, nonce, notBefore, now, subject
58 })
59
60 if (!isObject(payload)) {
61 throw new TypeError('payload must be an object')
62 }
63
64 let unix
65 if (expiresIn || notBefore || iat) {
66 unix = epoch(now || new Date())
67 }
68
69 payload = {
70 ...payload,
71 sub: subject || payload.sub,
72 aud: audience || payload.aud,
73 iss: issuer || payload.iss,
74 jti: jti || payload.jti,
75 iat: iat ? unix : payload.iat,
76 nonce: nonce || payload.nonce,
77 exp: expiresIn ? unix + secs(expiresIn) : payload.exp,
78 nbf: notBefore ? unix + secs(notBefore) : payload.nbf
79 }
80
81 key = getKey(key)
82
83 let includeKid
84
85 if (typeof options.kid === 'boolean') {
86 includeKid = kid
87 } else {
88 includeKid = !key.secret
89 }
90
91 return JWS.sign(JSON.stringify(payload), key, {
92 ...header,
93 alg: algorithm || header.alg,
94 kid: includeKid ? key.kid : header.kid
95 })
96}