jose/lib/jwt/sign.js
Filip Skokan 6c98b61597 feat: validate JWTs according to a JWT profile - ID Token
It is now possible to pass a profile to `JWT.verify` and have the JWT
validated according to it. This makes sure you pass all the right
options and that required claims are present, prohibited claims are
missing and that the right JWT typ is used.

More profiles will be added in the future.
2019-07-23 14:50:16 +02:00

82 lines
2.4 KiB
JavaScript

const isObject = require('../help/is_object')
const secs = require('../help/secs')
const epoch = require('../help/epoch')
const JWS = require('../jws')
const isString = require('./shared_validations').isString.bind(undefined, TypeError)
const validateOptions = (options) => {
if (typeof options.iat !== 'boolean') {
throw new TypeError('options.iat must be a boolean')
}
if (typeof options.kid !== 'boolean') {
throw new TypeError('options.kid must be a boolean')
}
isString(options.subject, 'options.subject')
isString(options.issuer, 'options.issuer')
if (
options.audience !== undefined &&
(
(typeof options.audience !== 'string' || !options.audience) &&
(!Array.isArray(options.audience) || options.audience.length === 0 || options.audience.some(a => !a || typeof a !== 'string'))
)
) {
throw new TypeError('options.audience must be a string or an array of strings')
}
if (options.header !== undefined && !isObject(options.header)) {
throw new TypeError('options.header must be an object')
}
isString(options.algorithm, 'options.algorithm')
isString(options.expiresIn, 'options.expiresIn')
isString(options.notBefore, 'options.notBefore')
isString(options.jti, 'options.jti')
isString(options.nonce, 'options.nonce')
if (!(options.now instanceof Date) || !options.now.getTime()) {
throw new TypeError('options.now must be a valid Date object')
}
}
module.exports = (payload, key, options = {}) => {
if (!isObject(options)) {
throw new TypeError('options must be an object')
}
const {
algorithm, audience, expiresIn, header = {}, iat = true,
issuer, jti, kid = true, nonce, notBefore, subject, now = new Date()
} = options
validateOptions({
algorithm, audience, expiresIn, header, iat, issuer, jti, kid, nonce, notBefore, now, subject
})
if (!isObject(payload)) {
throw new TypeError('payload must be an object')
}
const unix = epoch(now)
payload = {
...payload,
sub: subject || payload.sub,
aud: audience || payload.aud,
iss: issuer || payload.iss,
jti: jti || payload.jti,
iat: iat ? unix : payload.iat,
nonce: nonce || payload.nonce,
exp: expiresIn ? unix + secs(expiresIn) : payload.exp,
nbf: notBefore ? unix + secs(notBefore) : payload.nbf
}
return JWS.sign(payload, key, {
...header,
alg: algorithm || header.alg,
kid: kid ? key.kid : header.kid
})
}