Socket
Socket
Sign inDemoInstall

jose

Package Overview
Dependencies
Maintainers
1
Versions
210
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

jose - npm Package Compare versions

Comparing version 1.18.0 to 1.18.1

9

CHANGELOG.md

@@ -5,2 +5,11 @@ # Change Log

## [1.18.1](https://github.com/panva/jose/compare/v1.18.0...v1.18.1) (2020-01-01)
### Bug Fixes
* force iat past check when maxTokenAge option is used + JWT refactor ([828ad5a](https://github.com/panva/jose/commit/828ad5a33dc0cc0049923b69f43f97463295456e))
# [1.18.0](https://github.com/panva/jose/compare/v1.17.2...v1.18.0) (2019-12-31)

@@ -7,0 +16,0 @@

154

lib/jwt/verify.js

@@ -41,57 +41,61 @@ const isObject = require('../help/is_object')

const validateOptions = (options) => {
isOptionString(options.profile, 'options.profile')
const validateOptions = ({
algorithms, audience, clockTolerance, complete = false, crit, ignoreExp = false,
ignoreIat = false, ignoreNbf = false, issuer, jti, maxAuthAge, maxTokenAge, nonce, now = new Date(),
profile, subject
}) => {
isOptionString(profile, 'options.profile')
if (typeof options.complete !== 'boolean') {
if (typeof complete !== 'boolean') {
throw new TypeError('options.complete must be a boolean')
}
if (typeof options.ignoreExp !== 'boolean') {
if (typeof ignoreExp !== 'boolean') {
throw new TypeError('options.ignoreExp must be a boolean')
}
if (typeof options.ignoreNbf !== 'boolean') {
if (typeof ignoreNbf !== 'boolean') {
throw new TypeError('options.ignoreNbf must be a boolean')
}
if (typeof options.ignoreIat !== 'boolean') {
if (typeof ignoreIat !== 'boolean') {
throw new TypeError('options.ignoreIat must be a boolean')
}
isOptionString(options.maxTokenAge, 'options.maxTokenAge')
isOptionString(options.subject, 'options.subject')
isOptionString(options.issuer, 'options.issuer')
isOptionString(options.maxAuthAge, 'options.maxAuthAge')
isOptionString(options.jti, 'options.jti')
isOptionString(options.clockTolerance, 'options.clockTolerance')
isOptionString(maxTokenAge, 'options.maxTokenAge')
isOptionString(subject, 'options.subject')
isOptionString(issuer, 'options.issuer')
isOptionString(maxAuthAge, 'options.maxAuthAge')
isOptionString(jti, 'options.jti')
isOptionString(clockTolerance, 'options.clockTolerance')
if (options.audience !== undefined && (isNotString(options.audience) && isNotArrayOfStrings(options.audience))) {
if (audience !== undefined && (isNotString(audience) && isNotArrayOfStrings(audience))) {
throw new TypeError('options.audience must be a string or an array of strings')
}
if (options.algorithms !== undefined && isNotArrayOfStrings(options.algorithms)) {
if (algorithms !== undefined && isNotArrayOfStrings(algorithms)) {
throw new TypeError('options.algorithms must be an array of strings')
}
isOptionString(options.nonce, 'options.nonce')
isOptionString(nonce, 'options.nonce')
if (!(options.now instanceof Date) || !options.now.getTime()) {
if (!(now instanceof Date) || !now.getTime()) {
throw new TypeError('options.now must be a valid Date object')
}
if (options.ignoreIat && options.maxTokenAge !== undefined) {
if (ignoreIat && maxTokenAge !== undefined) {
throw new TypeError('options.ignoreIat and options.maxTokenAge cannot used together')
}
if (options.crit !== undefined && isNotArrayOfStrings(options.crit)) {
if (crit !== undefined && isNotArrayOfStrings(crit)) {
throw new TypeError('options.crit must be an array of strings')
}
switch (options.profile) {
switch (profile) {
case IDTOKEN:
if (!options.issuer) {
if (!issuer) {
throw new TypeError('"issuer" option is required to validate an ID Token')
}
if (!options.audience) {
if (!audience) {
throw new TypeError('"audience" option is required to validate an ID Token')

@@ -102,7 +106,7 @@ }

case ATJWT:
if (!options.issuer) {
if (!issuer) {
throw new TypeError('"issuer" option is required to validate a JWT Access Token')
}
if (!options.audience) {
if (!audience) {
throw new TypeError('"audience" option is required to validate a JWT Access Token')

@@ -113,7 +117,7 @@ }

case LOGOUTTOKEN:
if (!options.issuer) {
if (!issuer) {
throw new TypeError('"issuer" option is required to validate a Logout Token')
}
if (!options.audience) {
if (!audience) {
throw new TypeError('"audience" option is required to validate a Logout Token')

@@ -126,19 +130,38 @@ }

default:
throw new TypeError(`unsupported options.profile value "${options.profile}"`)
throw new TypeError(`unsupported options.profile value "${profile}"`)
}
return {
algorithms,
audience,
clockTolerance,
complete,
crit,
ignoreExp,
ignoreIat,
ignoreNbf,
issuer,
jti,
maxAuthAge,
maxTokenAge,
nonce,
now,
profile,
subject
}
}
const validateTypes = ({ header, payload }, profile) => {
const validateTypes = ({ header, payload }, profile, options) => {
isPayloadString(header.alg, '"alg" header parameter', true)
isTimestamp(payload.iat, 'iat', profile === IDTOKEN || profile === LOGOUTTOKEN)
isTimestamp(payload.iat, 'iat', profile === IDTOKEN || profile === LOGOUTTOKEN || !!options.maxTokenAge)
isTimestamp(payload.exp, 'exp', profile === IDTOKEN || profile === ATJWT)
isTimestamp(payload.auth_time, 'auth_time')
isTimestamp(payload.auth_time, 'auth_time', !!options.maxAuthAge)
isTimestamp(payload.nbf, 'nbf')
isPayloadString(payload.jti, '"jti" claim', profile === LOGOUTTOKEN)
isPayloadString(payload.jti, '"jti" claim', profile === LOGOUTTOKEN || !!options.jti)
isPayloadString(payload.acr, '"acr" claim')
isPayloadString(payload.nonce, '"nonce" claim')
isPayloadString(payload.iss, '"iss" claim', profile === IDTOKEN || profile === ATJWT || profile === LOGOUTTOKEN)
isPayloadString(payload.sub, '"sub" claim', profile === IDTOKEN || profile === ATJWT)
isStringOrArrayOfStrings(payload.aud, 'aud', profile === IDTOKEN || profile === ATJWT || profile === LOGOUTTOKEN)
isPayloadString(payload.nonce, '"nonce" claim', !!options.nonce)
isPayloadString(payload.iss, '"iss" claim', profile === IDTOKEN || profile === ATJWT || profile === LOGOUTTOKEN || !!options.issuer)
isPayloadString(payload.sub, '"sub" claim', profile === IDTOKEN || profile === ATJWT || !!options.subject)
isStringOrArrayOfStrings(payload.aud, 'aud', profile === IDTOKEN || profile === ATJWT || profile === LOGOUTTOKEN || !!options.audience)
isPayloadString(payload.azp, '"azp" claim', profile === IDTOKEN && Array.isArray(payload.aud) && payload.aud.length > 1)

@@ -205,49 +228,29 @@ isStringOrArrayOfStrings(payload.amr, 'amr')

const {
algorithms, audience, clockTolerance, complete = false, crit, ignoreExp = false,
ignoreIat = false, ignoreNbf = false, issuer, jti, maxAuthAge, maxTokenAge, nonce, now = new Date(),
subject, profile
} = options
algorithms, audience, clockTolerance, complete, crit, ignoreExp, ignoreIat, ignoreNbf, issuer,
jti, maxAuthAge, maxTokenAge, nonce, now, profile, subject
} = options = validateOptions(options)
validateOptions({
algorithms,
audience,
clockTolerance,
complete,
crit,
ignoreExp,
ignoreIat,
ignoreNbf,
issuer,
jti,
maxAuthAge,
maxTokenAge,
nonce,
now,
profile,
subject
})
const unix = epoch(now)
const decoded = decode(token, { complete: true })
validateTypes(decoded, profile)
validateTypes(decoded, profile, options)
if (issuer && decoded.payload.iss !== issuer) {
throw new JWTClaimInvalid('issuer mismatch')
throw new JWTClaimInvalid('unexpected "iss" claim value')
}
if (nonce && decoded.payload.nonce !== nonce) {
throw new JWTClaimInvalid('nonce mismatch')
throw new JWTClaimInvalid('unexpected "nonce" claim value')
}
if (subject && decoded.payload.sub !== subject) {
throw new JWTClaimInvalid('subject mismatch')
throw new JWTClaimInvalid('unexpected "sub" claim value')
}
if (jti && decoded.payload.jti !== jti) {
throw new JWTClaimInvalid('jti mismatch')
throw new JWTClaimInvalid('unexpected "jti" claim value')
}
if (audience && !checkAudiencePresence(decoded.payload.aud, typeof audience === 'string' ? [audience] : audience, profile)) {
throw new JWTClaimInvalid('audience mismatch')
throw new JWTClaimInvalid('unexpected "aud" claim value')
}

@@ -258,9 +261,5 @@

if (maxAuthAge) {
if (!('auth_time' in decoded.payload)) {
throw new JWTClaimInvalid('missing auth_time')
}
const maxAuthAgeSeconds = secs(maxAuthAge)
if (decoded.payload.auth_time + maxAuthAgeSeconds < unix - tolerance) {
throw new JWTClaimInvalid('too much time has elapsed since the last End-User authentication')
throw new JWTClaimInvalid('"auth_time" claim timestamp check failed (too much time has elapsed since the last End-User authentication)')
}

@@ -270,20 +269,23 @@ }

if (!ignoreIat && !('exp' in decoded.payload) && 'iat' in decoded.payload && decoded.payload.iat > unix + tolerance) {
throw new JWTClaimInvalid('token issued in the future')
throw new JWTClaimInvalid('"iat" claim timestamp check failed (it should be in the past)')
}
if (!ignoreNbf && 'nbf' in decoded.payload && decoded.payload.nbf > unix + tolerance) {
throw new JWTClaimInvalid('token is not active yet')
throw new JWTClaimInvalid('"nbf" claim timestamp check failed')
}
if (!ignoreExp && 'exp' in decoded.payload && decoded.payload.exp <= unix - tolerance) {
throw new JWTClaimInvalid('token is expired')
throw new JWTClaimInvalid('"exp" claim timestamp check failed')
}
if (maxTokenAge) {
if (!('iat' in decoded.payload)) {
throw new JWTClaimInvalid('missing iat claim')
const age = unix - decoded.payload.iat
const max = secs(maxTokenAge)
if (age - tolerance > max) {
throw new JWTClaimInvalid('"iat" claim timestamp check failed (too far in the past)')
}
if (decoded.payload.iat + secs(maxTokenAge) < unix + tolerance) {
throw new JWTClaimInvalid('maxTokenAge exceeded')
if (age - tolerance > max || age < 0 - tolerance) {
throw new JWTClaimInvalid('"iat" claim timestamp check failed (it should be in the past)')
}

@@ -293,3 +295,3 @@ }

if (profile === IDTOKEN && Array.isArray(decoded.payload.aud) && decoded.payload.aud.length > 1 && decoded.payload.azp !== audience) {
throw new JWTClaimInvalid('azp mismatch')
throw new JWTClaimInvalid('unexpected "azp" claim value')
}

@@ -296,0 +298,0 @@

{
"name": "jose",
"version": "1.18.0",
"version": "1.18.1",
"description": "JSON Web Almost Everything - JWA, JWS, JWE, JWK, JWT, JWKS for Node.js with minimal dependencies",

@@ -5,0 +5,0 @@ "keywords": [

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc