download
raw
10.6 kB
import { decodeBase64, decodeBase64urlIgnorePadding, encodeBase64urlNoPadding } from "@oslojs/encoding";
export function parseJWT(jwt) {
const parts = jwt.split(".");
if (parts.length !== 3) {
throw new Error("Invalid JWT");
}
let jsonHeader;
let jsonPayload;
let signature;
try {
jsonHeader = new TextDecoder().decode(decodeBase64urlIgnorePadding(parts[0]));
jsonPayload = new TextDecoder().decode(decodeBase64urlIgnorePadding(parts[1]));
signature = decodeBase64urlIgnorePadding(parts[2]);
}
catch {
throw new Error("Invalid JWT: Invalid base64url encoding");
}
let header;
let payload;
try {
header = JSON.parse(jsonHeader);
payload = JSON.parse(jsonPayload);
}
catch {
throw new Error("Invalid JWT: Invalid JSON encoding");
}
if (typeof header !== "object" || header === null) {
throw new Error("Invalid JWT: Invalid header");
}
if (typeof payload !== "object" || payload === null) {
throw new Error("Invalid JWT: Invalid payload");
}
const signatureMessage = new TextEncoder().encode(parts[0] + "." + parts[1]);
return [header, payload, signature, signatureMessage];
}
export function decodeJWT(jwt) {
const parts = jwt.split(".");
if (parts.length !== 3) {
throw new Error("Invalid JWT");
}
let jsonPayload;
try {
jsonPayload = new TextDecoder().decode(decodeBase64urlIgnorePadding(parts[1]));
}
catch {
throw new Error("Invalid JWT: Invalid base64url encoding");
}
let payload;
try {
payload = JSON.parse(jsonPayload);
}
catch {
throw new Error("Invalid JWT: Invalid JSON encoding");
}
if (typeof payload !== "object" || payload === null) {
throw new Error("Invalid JWT: Invalid payload");
}
return payload;
}
export function encodeJWT(headerJSON, payloadJSON, signature) {
const encodedHeader = encodeBase64urlNoPadding(new TextEncoder().encode(headerJSON));
const encodedPayload = encodeBase64urlNoPadding(new TextEncoder().encode(payloadJSON));
const encodedSignature = encodeBase64urlNoPadding(signature);
const jwt = encodedHeader + "." + encodedPayload + "." + encodedSignature;
return jwt;
}
export function createJWTSignatureMessage(headerJSON, payloadJSON) {
const encodedHeader = encodeBase64urlNoPadding(new TextEncoder().encode(headerJSON));
const encodedPayload = encodeBase64urlNoPadding(new TextEncoder().encode(payloadJSON));
const message = encodedHeader + "." + encodedPayload;
return new TextEncoder().encode(message);
}
export class JWTClaims {
target;
constructor(target) {
this.target = target;
}
hasIssuer() {
return "iss" in this.target;
}
issuer() {
if ("iss" in this.target && typeof this.target.iss === "string") {
return this.target.iss;
}
throw new Error("Invalid or missing 'iss' claim");
}
hasSubject() {
return "sub" in this.target;
}
subject() {
if ("sub" in this.target && typeof this.target.sub === "string") {
return this.target.sub;
}
throw new Error("Invalid or missing 'sub' claim");
}
hasAudiences() {
return "aud" in this.target;
}
audiences() {
if ("aud" in this.target && typeof this.target.aud === "string") {
const audiences = [this.target.aud];
return audiences;
}
if ("aud" in this.target && Array.isArray(this.target.aud)) {
for (const audience in this.target.aud) {
if (typeof audience !== "string") {
throw new Error("Invalid or missing 'aud' claim");
}
}
return this.target.aud;
}
throw new Error("Invalid or missing 'aud' claim");
}
hasExpiration() {
return "exp" in this.target;
}
expiration() {
if ("exp" in this.target &&
typeof this.target.exp === "number" &&
this.target.exp >= 0 &&
Number.isInteger(this.target.exp)) {
return new Date(this.target.exp * 1000);
}
throw new Error("Invalid or missing 'exp' claim");
}
verifyExpiration() {
if ("exp" in this.target &&
typeof this.target.exp === "number" &&
this.target.exp >= 0 &&
Number.isInteger(this.target.exp)) {
return Date.now() < this.target.exp * 1000;
}
throw new Error("Invalid or missing 'exp' claim");
}
hasNotBefore() {
return "nbf" in this.target;
}
notBefore() {
if ("nbf" in this.target &&
typeof this.target.nbf === "number" &&
this.target.nbf >= 0 &&
Number.isInteger(this.target.nbf)) {
return new Date(this.target.nbf * 1000);
}
throw new Error("Invalid or missing 'nbf' claim");
}
verifyNotBefore() {
if ("nbf" in this.target &&
typeof this.target.nbf === "number" &&
this.target.nbf >= 0 &&
Number.isInteger(this.target.nbf)) {
return Date.now() >= this.target.nbf * 1000;
}
throw new Error("Invalid or missing 'nbf' claim");
}
hasIssuedAt() {
return "iat" in this.target;
}
issuedAt() {
if ("iat" in this.target &&
typeof this.target.iat === "number" &&
this.target.iat >= 0 &&
Number.isInteger(this.target.iat)) {
return new Date(this.target.iat * 1000);
}
throw new Error("Invalid or missing 'iat' claim");
}
hasJWTId() {
return "jti" in this.target;
}
jwtId() {
if ("jti" in this.target && typeof this.target.jti === "string") {
return this.target.jti;
}
throw new Error("Invalid or missing 'jti' claim");
}
}
export class JWSRegisteredHeaders {
target;
constructor(target) {
this.target = target;
}
hasAlgorithm() {
return "alg" in this.target;
}
algorithm() {
if ("alg" in this.target && typeof this.target.alg === "string") {
return this.target.alg;
}
throw new Error("Invalid or missing 'alg' claim");
}
hasJWKSetURL() {
return "jku" in this.target;
}
jwkSetURL() {
if ("jku" in this.target && typeof this.target.jku === "string") {
return this.target.jku;
}
throw new Error("Invalid or missing 'jku' claim");
}
hasJWK() {
return "jwk" in this.target;
}
jwk() {
if ("jwk" in this.target && typeof this.target.jwk === "string") {
return this.target.jwk;
}
throw new Error("Invalid or missing 'jwk' claim");
}
hasKeyId() {
return "kid" in this.target;
}
keyId() {
if ("kid" in this.target && typeof this.target.kid === "string") {
return this.target.kid;
}
throw new Error("Invalid or missing 'kid' claim");
}
hasX509URL() {
return "x5u" in this.target;
}
x509URL() {
if ("x5u" in this.target && typeof this.target.x5u === "string") {
return this.target.x5u;
}
throw new Error("Invalid or missing 'x5u' claim");
}
hasX509CertificateChain() {
return "x5c" in this.target;
}
x509CertificateChain() {
if ("x5c" in this.target && Array.isArray(this.target.x5c)) {
if (this.target.x5c.length === 0) {
throw new Error("Invalid or missing 'x5c' claim");
}
const chain = [];
for (const encoded of this.target.x5c) {
if (typeof encoded !== "string") {
throw new Error("Invalid or missing 'x5c' claim");
}
try {
chain.push(decodeBase64(encoded));
}
catch {
throw new Error("Invalid or missing 'x5c' claim");
}
}
return chain;
}
throw new Error("Invalid or missing 'x5c' claim");
}
hasX509CertificateSHA1Thumbprint() {
return "x5t" in this.target;
}
x509CertificateSHA1Thumbprint() {
if ("x5t" in this.target && typeof this.target.x5t === "string") {
try {
const thumbprint = decodeBase64urlIgnorePadding(this.target.x5t);
return thumbprint;
}
catch {
throw new Error("Invalid or missing 'x5t' claim");
}
}
throw new Error("Invalid or missing 'x5t' claim");
}
hasX509CertificateSHA256Thumbprint() {
return "x5t#S256" in this.target;
}
x509CertificateSHA256Thumbprint() {
if ("x5t#S256" in this.target && typeof this.target["x5t#S256"] === "string") {
try {
const thumbprint = decodeBase64urlIgnorePadding(this.target["x5t#S256"]);
return thumbprint;
}
catch {
throw new Error("Invalid or missing 'x5t#S256' claim");
}
}
throw new Error("Invalid or missing 'x5t#S256' claim");
}
hasType() {
return "typ" in this.target;
}
type() {
if ("typ" in this.target && typeof this.target.typ === "string") {
return this.target.typ;
}
throw new Error("Invalid or missing 'typ' claim");
}
hasContentType() {
return "cty" in this.target;
}
contentType() {
if ("cty" in this.target && typeof this.target.cty === "string") {
return this.target.cty;
}
throw new Error("Invalid or missing 'cty' claim");
}
hasCritical() {
return "crit" in this.target;
}
critical() {
if ("crit" in this.target && Array.isArray(this.target.crit)) {
if (this.target.crit.length === 0) {
throw new Error("Invalid or missing 'crit' claim");
}
for (const audience in this.target.crit) {
if (typeof audience !== "string") {
throw new Error("Invalid or missing 'crit' claim");
}
}
return this.target.crit;
}
throw new Error("Invalid or missing 'crit' claim");
}
}
export const joseAlgorithmHS256 = "HS256";
export const joseAlgorithmES256 = "ES256";
export const joseAlgorithmRS256 = "RS256";

Xet Storage Details

Size:
10.6 kB
·
Xet hash:
890735031fc0af9da7560225fa0759e1ce09a960bd048c84cfc28acb507377db

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.