ts-jwt-decode
Version:
A TypeScript based JWT Token decoder with token verification
117 lines • 4.04 kB
JavaScript
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