UNPKG

ts-jwt-decode

Version:

A TypeScript based JWT Token decoder with token verification

117 lines 4.04 kB
import JwtToken, { Algorithm, Type } from './JwtToken'; import JwtVerifier from './JwtVerifier'; function hasOwnProperty(obj, prop) { return obj.hasOwnProperty(prop); } function isJwtHeaderDto(dto) { if (!(dto instanceof Object)) { return false; } if (hasOwnProperty(dto, 'alg')) { if (!(typeof dto.alg === 'string' && dto.alg in Algorithm)) { return false; } } else { return false; } if (hasOwnProperty(dto, 'typ')) { return typeof dto.typ === 'string' && dto.typ in Type; } return true; } function isJwtHeader(header) { // As far as I know there is currently no (easy) way to verify that the header meets the schema // definition of H simply by knowing the interface is H. // // So be warned! This forces the header into the correct typing, but runtime errors may occur if you stuff // headers not matching your schema into the token! return header instanceof Object; } function isJwtPayloadDto(dto) { if (!(dto instanceof Object)) { return false; } if (hasOwnProperty(dto, 'iat')) { if (typeof dto.iat !== 'number') { return false; } } else { return false; } if (hasOwnProperty(dto, 'exp')) { if (typeof dto.exp !== 'number') { return false; } } else { return false; } return true; } function isJwtPayload(payload) { // As far as I know there is currently no (easy) way to verify that the payload meets the schema // definition of P simply by knowing the interface is P. // // So be warned! This forces the payload into the correct typing, but runtime errors may occur if you stuff // payloads not matching your schema into the token! return payload instanceof Object; } export class JwtParseError extends Error { constructor(message, previousError) { super(message); this.previousError = previousError; } } export default class JwtParser { static parse(tokenString) { const segments = tokenString.split('.'); if (segments.length != 3) { throw new JwtParseError(`Malformed JWT Token - ${segments.length}/3 segments`); } const [headerSegment, payloadSegment] = segments; const headerRaw = JSON.parse(window.atob(headerSegment)); const payloadRaw = JSON.parse(window.atob(payloadSegment)); if (!isJwtHeaderDto(headerRaw)) { throw new JwtParseError('Unable to parse header segment - header does not contain required attributes'); } if (!isJwtPayloadDto(payloadRaw)) { throw new JwtParseError('Unable to parse payload segment - header does not contain required attributes'); } const header = this.transformHeaderDto(headerRaw); const payload = this.transformPayloadDto(payloadRaw); return new JwtToken(header, payload, tokenString); } static transformHeaderDto(dto) { const algorithm = dto.alg; const type = dto.typ; const raw = dto; delete raw['alg']; delete raw['typ']; const header = Object.assign({ algorithm, type }, raw); if (!isJwtHeader(header)) { throw new JwtParseError('Unable to parse header segment - header does not match schema'); } return header; } static transformPayloadDto(dto) { const issuedAt = dto.iat; const expiresAt = dto.exp; const raw = dto; delete raw['iat']; delete raw['exp']; const payload = Object.assign({ issuedAt, expiresAt }, raw); if (!isJwtPayload(payload)) { throw new JwtParseError('Unable to parse payload segment - payload does not match schema'); } return payload; } static verify(token, key, verifyAt) { const verifier = new JwtVerifier(key); return verifier.verify(token, verifyAt); } } //# sourceMappingURL=JwtParser.js.map