UNPKG

@guarani/jose

Version:

Implementation of the RFCs of the JOSE Working Group.

144 lines (143 loc) 7.02 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JsonWebTokenClaims = void 0; const objects_1 = require("@guarani/objects"); const util_1 = require("util"); const expired_token_exception_1 = require("../exceptions/expired-token.exception"); const invalid_json_web_token_claim_exception_1 = require("../exceptions/invalid-json-web-token-claim.exception"); const invalid_json_web_token_exception_1 = require("../exceptions/invalid-json-web-token.exception"); const jose_exception_1 = require("../exceptions/jose.exception"); const token_not_valid_yet_exception_1 = require("../exceptions/token-not-valid-yet.exception"); /** * Implementation of {@link https://www.rfc-editor.org/rfc/rfc7519.html#section-4 RFC 7519 Section 4}. */ class JsonWebTokenClaims { /** * Instantiates a new JSON Web Token Claims for usage with JSON Web Tokens. * * @param claims Defines the claims of the JSON Web Token. * @param options Validation options for the claims. */ constructor(claims, options = {}) { if (claims instanceof JsonWebTokenClaims) { return claims; } this.validateDefaultClaims(claims); this.validateCustomClaims?.(claims); this.validateClaimsOptions(claims, options); Object.assign(this, (0, objects_1.removeNullishValues)(claims)); } /** * Parses the provided data into a JSON Web Token Claims object. * * @param data Encoded JSON Web Token Claims. * @param options Validation options for the claims. * @returns Parsed JSON Web Token Claims. */ static parse(data, options) { try { if (typeof data === 'string') { data = Buffer.from(data, 'base64url'); } const claims = JSON.parse(data.toString('utf8')); return new JsonWebTokenClaims(claims, options); } catch (exc) { if (exc instanceof jose_exception_1.JoseException) { throw exc; } throw new invalid_json_web_token_exception_1.InvalidJsonWebTokenException(); } } /** * Validates the Default JSON Web Token Claims based on the rules of * {@link https://www.rfc-editor.org/rfc/rfc7519.html#section-4 RFC 7519 Section 4}. * * @param claims JSON Web Token Claims. */ validateDefaultClaims(claims) { const now = Math.floor(Date.now() / 1000); if (claims.iss !== undefined && (typeof claims.iss !== 'string' || claims.iss.length === 0)) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException('Invalid claim "iss".'); } if (claims.sub !== undefined && (typeof claims.sub !== 'string' || claims.sub.length === 0)) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException('Invalid claim "sub".'); } if (claims.aud !== undefined) { if (typeof claims.aud !== 'string' && !Array.isArray(claims.aud)) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException('Invalid claim "aud".'); } if (Array.isArray(claims.aud) && claims.aud.some((aud) => typeof aud !== 'string' || aud.length === 0)) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException('Invalid claim "aud".'); } if (typeof claims.aud === 'string' && claims.aud.length === 0) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException('Invalid claim "aud".'); } } if (claims.exp !== undefined) { if (typeof claims.exp !== 'number') { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException('Invalid claim "exp".'); } if (now > claims.exp) { throw new expired_token_exception_1.ExpiredTokenException(); } } if (claims.nbf !== undefined) { if (typeof claims.nbf !== 'number') { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException('Invalid claim "nbf".'); } if (now < claims.nbf) { throw new token_not_valid_yet_exception_1.TokenNotValidYetException(); } } if (claims.iat !== undefined && typeof claims.iat !== 'number') { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException('Invalid claim "iat".'); } if (claims.jti !== undefined && (typeof claims.jti !== 'string' || claims.jti.length === 0)) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException('Invalid claim "jti".'); } } /** * Validates the provided JSON Web Token Claims based on the provided Options. * * @param claims JSON Web Token Claims. * @param options Dictionary used to validate the provided JSON Web Token Claims. */ validateClaimsOptions(claims, options) { Object.entries(options).forEach(([claim, option]) => { const claimValue = claims[claim]; if (option.essential === true && claimValue === undefined) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException(`Missing required claim "${claim}".`); } if (option.value !== undefined && !(0, util_1.isDeepStrictEqual)(claimValue, option.value)) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException(`Mismatching expected value for claim "${claim}".`); } if (option.values !== undefined) { if (!Array.isArray(option.values)) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException('Expected an array for the option "values".'); } if (option.values.length === 0) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException(`Mismatching expected value for claim "${claim}".`); } option.values.forEach((value) => { if (!(0, util_1.isDeepStrictEqual)(value, claimValue)) { throw new invalid_json_web_token_claim_exception_1.InvalidJsonWebTokenClaimException(`Mismatching expected value for claim "${claim}". Received "${claimValue}".`); } }); } }); } /** * Returns the JSON Encoded String of the JSON Web Token Claims. */ toString() { return JSON.stringify(this); } /** * Returns the Buffer representation of the JSON Encoded String of the JSON Web Token Claims. */ toBuffer() { return Buffer.from(this.toString(), 'utf8'); } } exports.JsonWebTokenClaims = JsonWebTokenClaims;