Versions

  • v30

    3/7/2024
    Open: Version
    Changes from v29 to v30
    +3
    -0
    ⦚ 59 unchanged lines ⦚
    throw new Error("issuer does not match the format `@handle/name`");
    }
    const url = getValEndpointFromName(`@${author}/jwks`);
    const method = createVerifyMethod(() => {
    return fetch(url)
    ⦚ 82 unchanged lines ⦚
    ⦚ 59 unchanged lines ⦚
    throw new Error("issuer does not match the format `@handle/name`");
    }
    if (payload.exp && payload.exp < (new Date().getTime() / 1000)) {
    throw new Error("token has expired");
    }
    const url = getValEndpointFromName(`@${author}/jwks`);
    const method = createVerifyMethod(() => {
    return fetch(url)
    ⦚ 82 unchanged lines ⦚
  • v29

    3/5/2024
    Open: Version
    Changes from v28 to v29
    +6
    -6
    ⦚ 7 unchanged lines ⦚

    export type JWTVerifyOptions = jose.JWTVerifyOptions & {
    verifyCustomClaims?: Record<string, unknown> | ((payload: jose.JWTPayload) => MaybePromise<Record<string, any>>);
    customClaimVerifiers?: Record<string, JWTCustomClaimVerifier>;
    };
    ⦚ 8 unchanged lines ⦚
    const publicKey = await jose.importJWK((await keys())[0]);
    const { payload } = await jose.jwtVerify(token, publicKey, options);
    const customClaims = options.verifyCustomClaims && (
    options.verifyCustomClaims instanceof Function
    ? await options.verifyCustomClaims(payload)
    : options.verifyCustomClaims
    );
    await verifyCustomClaims(payload, customClaims || {}, options.customClaimVerifiers ?? defaultCustomClaimVerifiers);
    ⦚ 61 unchanged lines ⦚
    async maxUses(payload, claimValue) {
    if (typeof claimValue !== "number") {
    throw new Error("option verifyCustomClaims.maxUses must be a number");
    }
    if (!payload.jti) {
    ⦚ 52 unchanged lines ⦚
    ⦚ 7 unchanged lines ⦚

    export type JWTVerifyOptions = jose.JWTVerifyOptions & {
    custom?: Record<string, unknown> | ((payload: jose.JWTPayload) => MaybePromise<Record<string, any>>);
    customClaimVerifiers?: Record<string, JWTCustomClaimVerifier>;
    };
    ⦚ 8 unchanged lines ⦚
    const publicKey = await jose.importJWK((await keys())[0]);
    const { payload } = await jose.jwtVerify(token, publicKey, options);
    const customClaims = options.custom && (
    options.custom instanceof Function
    ? await options.custom(payload)
    : options.custom
    );
    await verifyCustomClaims(payload, customClaims || {}, options.customClaimVerifiers ?? defaultCustomClaimVerifiers);
    ⦚ 61 unchanged lines ⦚
    async maxUses(payload, claimValue) {
    if (typeof claimValue !== "number") {
    throw new Error("option custom.maxUses must be a number");
    }
    if (!payload.jti) {
    ⦚ 52 unchanged lines ⦚
  • v28

    3/3/2024
    Open: Version
    Changes from v27 to v28
    +1
    -1
    ⦚ 36 unchanged lines ⦚

    let jwt = new jose.SignJWT({
    jit: crypto.randomUUID(),
    ...payload,
    })
    ⦚ 105 unchanged lines ⦚
    ⦚ 36 unchanged lines ⦚

    let jwt = new jose.SignJWT({
    jti: crypto.randomUUID(),
    ...payload,
    })
    ⦚ 105 unchanged lines ⦚
  • v27

    3/3/2024
    Open: Version
    Changes from v26 to v27
    +4
    -1
    ⦚ 35 unchanged lines ⦚
    const privateKey = await jose.importJWK(_keys[0]);

    let jwt = new jose.SignJWT(payload)
    .setProtectedHeader({ alg: _keys[0].alg })
    .setIssuedAt();
    ⦚ 103 unchanged lines ⦚
    ⦚ 35 unchanged lines ⦚
    const privateKey = await jose.importJWK(_keys[0]);

    let jwt = new jose.SignJWT({
    jit: crypto.randomUUID(),
    ...payload,
    })
    .setProtectedHeader({ alg: _keys[0].alg })
    .setIssuedAt();
    ⦚ 103 unchanged lines ⦚
  • v26

    3/3/2024
    Open: Version
    Changes from v25 to v26
    +3
    -3
    ⦚ 7 unchanged lines ⦚

    export type JWTVerifyOptions = jose.JWTVerifyOptions & {
    verifyCustomClaims?: Record<string, any> | ((payload: jose.JWTPayload) => MaybePromise<Record<string, any>>);
    customClaimVerifiers?: Record<string, JWTCustomClaimVerifier>;
    };
    ⦚ 10 unchanged lines ⦚
    const customClaims = options.verifyCustomClaims && (
    options.verifyCustomClaims instanceof Function
    ? options.verifyCustomClaims(payload)
    : options.verifyCustomClaims
    );
    ⦚ 84 unchanged lines ⦚
    export async function verifyCustomClaims(
    payload,
    customClaims: Record<string, any>,
    customClaimVerifiers = defaultCustomClaimVerifiers,
    ) {
    ⦚ 27 unchanged lines ⦚
    ⦚ 7 unchanged lines ⦚

    export type JWTVerifyOptions = jose.JWTVerifyOptions & {
    verifyCustomClaims?: Record<string, unknown> | ((payload: jose.JWTPayload) => MaybePromise<Record<string, any>>);
    customClaimVerifiers?: Record<string, JWTCustomClaimVerifier>;
    };
    ⦚ 10 unchanged lines ⦚
    const customClaims = options.verifyCustomClaims && (
    options.verifyCustomClaims instanceof Function
    ? await options.verifyCustomClaims(payload)
    : options.verifyCustomClaims
    );
    ⦚ 84 unchanged lines ⦚
    export async function verifyCustomClaims(
    payload,
    customClaims: Record<string, unknown>,
    customClaimVerifiers = defaultCustomClaimVerifiers,
    ) {
    ⦚ 27 unchanged lines ⦚
  • v25

    3/3/2024
    Open: Version
    Changes from v24 to v25
    +1
    -1
    ⦚ 126 unchanged lines ⦚
    const res = await customClaimVerifiers[key](payload, value);
    if (!res) {
    failures[key] = `custom claim "${key}" verification failed`;
    }
    return res;
    ⦚ 12 unchanged lines ⦚
    ⦚ 126 unchanged lines ⦚
    const res = await customClaimVerifiers[key](payload, value);
    if (!res) {
    failures[key] = `custom claim "${key}" verification failed for an undisclosed reason`;
    }
    return res;
    ⦚ 12 unchanged lines ⦚
  • v24

    3/3/2024
    Open: Version
    Changes from v23 to v24
    +24
    -8
    import * as jose from "https://deno.land/x/jose@v5.2.2/index.ts";
    import type { MaybePromise } from "https://esm.town/v/postpostscript/typeUtils";
    export type { JWK, JWTPayload } from "https://deno.land/x/jose@v5.2.2/index.ts";
    import { getValEndpointFromName, getValNameFromUrl } from "https://esm.town/v/postpostscript/meta";

    export type JWTCustomClaims = Record<string, any>;

    export type JWTVerifyOptions = jose.JWTVerifyOptions & {
    verifyCustomClaims?: Record<string, any> | ((payload: jose.JWTPayload) => MaybePromise<Record<string, any>>);
    };

    export type JWTCustomClaimVerifier = (payload: jose.JWTPayload, claim: unknown) => boolean;

    export function createVerifyMethod(keys: () => MaybePromise<jose.JWK[]>) {
    return async function verify(
    token: string,
    options: JWTVerifyOptions,
    customClaimVerifiers = defaultCustomClaimVerifiers,
    ) {
    const publicKey = await jose.importJWK((await keys())[0]);
    ⦚ 4 unchanged lines ⦚
    : options.verifyCustomClaims
    );
    await verifyCustomClaims(payload, customClaims || {}, customClaimVerifiers);
    return payload;
    };
    ⦚ 40 unchanged lines ⦚

    export const defaultCustomClaimVerifiers: Record<string, JWTCustomClaimVerifier> = {
    scope(payload, claim) {
    const scopes = claim instanceof Array
    ? claim
    : [claim];
    const payloadScopes = typeof payload.scope === "string"
    import * as jose from "https://deno.land/x/jose@v5.2.2/index.ts";
    import type { MaybePromise } from "https://esm.town/v/postpostscript/typeUtils";
    export type { JWK, JWTPayload } from "https://deno.land/x/jose@v5.2.2/index.ts";
    import { getValEndpointFromName, getValNameFromUrl } from "https://esm.town/v/postpostscript/meta";
    import { trackUse } from "https://esm.town/v/postpostscript/trackUse";

    export type JWTCustomClaims = Record<string, any>;

    export type JWTVerifyOptions = jose.JWTVerifyOptions & {
    verifyCustomClaims?: Record<string, any> | ((payload: jose.JWTPayload) => MaybePromise<Record<string, any>>);
    customClaimVerifiers?: Record<string, JWTCustomClaimVerifier>;
    };

    export type JWTCustomClaimVerifier = (payload: jose.JWTPayload, claim: unknown) => MaybePromise<boolean>;

    export function createVerifyMethod(keys: () => MaybePromise<jose.JWK[]>) {
    return async function verify(
    token: string,
    options: JWTVerifyOptions,
    ) {
    const publicKey = await jose.importJWK((await keys())[0]);
    ⦚ 4 unchanged lines ⦚
    : options.verifyCustomClaims
    );
    await verifyCustomClaims(payload, customClaims || {}, options.customClaimVerifiers ?? defaultCustomClaimVerifiers);
    return payload;
    };
    ⦚ 40 unchanged lines ⦚

    export const defaultCustomClaimVerifiers: Record<string, JWTCustomClaimVerifier> = {
    scope(payload, claimValue) {
    const scopes = claimValue instanceof Array
    ? claimValue
    : [claimValue];
  • v23

    3/3/2024
    Open: Version
    Changes from v22 to v23
    +38
    -3
    ⦚ 24 unchanged lines ⦚
    : options.verifyCustomClaims
    );
    await verifyCustomClaims(payload, customClaims || {});
    return payload;
    };
    ⦚ 55 unchanged lines ⦚
    };

    export async function verifyCustomClaims(payload, customClaims: Record<string, any>) {
    const results = await Promise.all(
    Object.entries(customClaims).map(([key, value]) => {
    }),
    );
    }
    ⦚ 24 unchanged lines ⦚
    : options.verifyCustomClaims
    );
    await verifyCustomClaims(payload, customClaims || {}, customClaimVerifiers);
    return payload;
    };
    ⦚ 55 unchanged lines ⦚
    };

    class JWTCustomClaimVerificationFailed extends Error {
    failures: Record<string, string | Error | undefined>;

    constructor(message: string, failures: Record<string, string | Error | undefined>, options: ErrorOptions = {}) {
    super(message, options);
    this.failures = failures;
    }
    }

    export async function verifyCustomClaims(
    payload,
    customClaims: Record<string, any>,
    customClaimVerifiers = defaultCustomClaimVerifiers,
    ) {
    const failures: {
    [key in keyof typeof customClaims]: string | Error | undefined;
    } = {};
    const results = await Promise.all(
    Object.entries(customClaims).map(async ([key, value]) => {
    if (!(key in customClaimVerifiers)) {
    failures[key] = `custom claim "${key}" does not have a verifier defined`;
    return false;
    }
    try {
    const res = await customClaimVerifiers[key](payload, value);
  • v22

    3/3/2024
    Open: Version
    +92
    -0

    import * as jose from "https://deno.land/x/jose@v5.2.2/index.ts";
    import type { MaybePromise } from "https://esm.town/v/postpostscript/typeUtils";
    export type { JWK, JWTPayload } from "https://deno.land/x/jose@v5.2.2/index.ts";
    import { getValEndpointFromName, getValNameFromUrl } from "https://esm.town/v/postpostscript/meta";

    export type JWTCustomClaims = Record<string, any>;

    export type JWTVerifyOptions = jose.JWTVerifyOptions & {
    verifyCustomClaims?: Record<string, any> | ((payload: jose.JWTPayload) => MaybePromise<Record<string, any>>);
    };

    export type JWTCustomClaimVerifier = (payload: jose.JWTPayload, claim: unknown) => boolean;

    export function createVerifyMethod(keys: () => MaybePromise<jose.JWK[]>) {
    return async function verify(
    token: string,
    options: JWTVerifyOptions,
    customClaimVerifiers = defaultCustomClaimVerifiers,
    ) {
    const publicKey = await jose.importJWK((await keys())[0]);
    const { payload } = await jose.jwtVerify(token, publicKey, options);
    const customClaims = options.verifyCustomClaims && (
    options.verifyCustomClaims instanceof Function
    ? options.verifyCustomClaims(payload)
    : options.verifyCustomClaims
    );
    await verifyCustomClaims(payload, customClaims || {});
    return payload;
    };
    }

    export function createGenerateMethod(keys: () => MaybePromise<jose.JWK[]>) {
    return async function generate(payload: any, exp?: string | number | Date) {
    const _keys = await keys();
    const privateKey = await jose.importJWK(_keys[0]);

Updated: March 7, 2024