Skip to content
Effect 4.0 is here. One ecosystem. Zero dependencies.

Jwks unstable

JSON Web Key Sets and the Jwks service that resolves verification keys from them.

A key is selected by algorithm and optional kid. It must fit the algorithm's key family and curve, and its alg, use, and key_ops members must allow verification with that algorithm. No match fails with KeyNotFound and several matches with AmbiguousKey.

layerLocal serves a fixed key set. makeRemote and layerRemote fetch one from an HTTPS endpoint and cache it.

9 exports Since v4.1.1 Source

Constructors

makeLocal

unstable
Since v4.1.1

Builds a Jwks service for a fixed key set.

Signature

declare function makeLocal(keySet: {
readonly keys: readonly Array<{
readonly alg?: string;
readonly d?: undefined;
readonly dp?: undefined;
readonly dq?: undefined;
readonly e: string;
readonly k?: undefined;
readonly key_ops?: readonly Array<string>;
readonly kid?: string;
readonly kty: "RSA";
readonly n: string;
readonly oth?: undefined;
readonly p?: undefined;
readonly q?: undefined;
readonly qi?: undefined;
readonly use?: string;
} | {
readonly alg?: string;
readonly crv: "P-256" | "P-384" | "P-521";
readonly d?: undefined;
readonly dp?: undefined;
readonly dq?: undefined;
readonly k?: undefined;
readonly key_ops?: readonly Array<string>;
readonly kid?: string;
readonly kty: "EC";
readonly oth?: undefined;
readonly p?: undefined;
readonly q?: undefined;
readonly qi?: undefined;
readonly use?: string;
readonly x: string;
readonly y: string;
} | {
readonly alg?: string;
readonly crv: "Ed25519";
readonly d?: undefined;
readonly dp?: undefined;
readonly dq?: undefined;
readonly k?: undefined;
readonly key_ops?: readonly Array<string>;
readonly kid?: string;
readonly kty: "OKP";
readonly oth?: undefined;
readonly p?: undefined;
readonly q?: undefined;
readonly qi?: undefined;
readonly use?: string;
readonly x: string;
} | {
[key: string]: unknown;
readonly crv?: string;
readonly d?: undefined;
readonly dp?: undefined;
readonly dq?: undefined;
readonly k?: undefined;
readonly kty: string;
readonly oth?: undefined;
readonly p?: undefined;
readonly q?: undefined;
readonly qi?: undefined;
}>;
}): Effect<{
readonly resolve: (selection: Selection) => Effect<PublicKey, JoseError>;
}>

Example

import { Effect, Layer } from "effect"
import { SecureRandom, Signature } from "effect/crypto"
import { Jwk, Jwks } from "effect/jose"
const layer = Signature.layerWebCrypto.pipe(Layer.provide(SecureRandom.layerWebCrypto))
const kid = await Effect.runPromise(Effect.gen(function*() {
const pair = yield* Jwk.generateKeyPair({ algorithm: "ES256", kid: "signing-1" })
const jwks = yield* Jwks.makeLocal({ keys: [pair.publicKey] })
const key = yield* jwks.resolve({ algorithm: "ES256", kid: "signing-1" })
return key.kid
}).pipe(Effect.provide(layer)))
kid // => "signing-1"

makeRemote

unstable
Since v4.1.1

Builds a Jwks service for a remote key set, using the HttpClient service. Use it when the URL is only known at runtime, for example from OpenID Connect discovery.

Details

The key set is fetched on first use and reused until timeToLive passes. Concurrent callers share one request. A selection that finds no key fetches the set again, at most once per cooldown, so rotated keys are picked up without letting unknown kids drive a request per token. A failed fetch fails every caller until cooldown passes; there is no fallback to an expired set.

Only a 200 response from the configured URL is accepted, so a redirected key set is rejected. The check runs on the response, so it cannot stop a client from sending the redirected request.

Gotchas

Supply a client that does not follow redirects. FetchHttpClient follows them by default: provide FetchHttpClient.RequestInit with { redirect: "manual" } on its layer so a redirect fails before any further request. Clients wrapped with HttpClient.followRedirects also follow them.

Closing the scope interrupts any request in flight, and later resolutions fail with KeySetUnavailable.

Signature

declare const makeRemote: (...args: [options: RemoteOptions]) => Effect<{
readonly resolve: (selection: Selection) => Effect<PublicKey, JoseError>;
}, JoseError, Scope | HttpClient>

Layers

layerLocal

unstable
Since v4.1.1

Layer that provides Jwks for a fixed key set.

Signature

declare function layerLocal(keySet: {
readonly keys: readonly Array<{
readonly alg?: string;
readonly d?: undefined;
readonly dp?: undefined;
readonly dq?: undefined;
readonly e: string;
readonly k?: undefined;
readonly key_ops?: readonly Array<string>;
readonly kid?: string;
readonly kty: "RSA";
readonly n: string;
readonly oth?: undefined;
readonly p?: undefined;
readonly q?: undefined;
readonly qi?: undefined;
readonly use?: string;
} | {
readonly alg?: string;
readonly crv: "P-256" | "P-384" | "P-521";
readonly d?: undefined;
readonly dp?: undefined;
readonly dq?: undefined;
readonly k?: undefined;
readonly key_ops?: readonly Array<string>;
readonly kid?: string;
readonly kty: "EC";
readonly oth?: undefined;
readonly p?: undefined;
readonly q?: undefined;
readonly qi?: undefined;
readonly use?: string;
readonly x: string;
readonly y: string;
} | {
readonly alg?: string;
readonly crv: "Ed25519";
readonly d?: undefined;
readonly dp?: undefined;
readonly dq?: undefined;
readonly k?: undefined;
readonly key_ops?: readonly Array<string>;
readonly kid?: string;
readonly kty: "OKP";
readonly oth?: undefined;
readonly p?: undefined;
readonly q?: undefined;
readonly qi?: undefined;
readonly use?: string;
readonly x: string;
} | {
[key: string]: unknown;
readonly crv?: string;
readonly d?: undefined;
readonly dp?: undefined;
readonly dq?: undefined;
readonly k?: undefined;
readonly kty: string;
readonly oth?: undefined;
readonly p?: undefined;
readonly q?: undefined;
readonly qi?: undefined;
}>;
}): Layer<Jwks>

layerRemote

unstable
Since v4.1.1

Layer that provides Jwks from a remote key set built by makeRemote. Closing the layer interrupts any request in flight.

Signature

declare function layerRemote(options: RemoteOptions): Layer<Jwks, JoseError, HttpClient>

Models

KeySet

type unstable
Since v4.1.1

A set of public JWKs.

Signature

type KeySet = typeof KeySet.Type

RemoteOptions

interface unstable
Since v4.1.1

Options for makeRemote and layerRemote.

Signature

interface RemoteOptions {
readonly cooldown?: Input;
readonly maxKeys?: number;
readonly maxResponseBytes?: number;
readonly timeout?: Input;
readonly timeToLive?: Input;
readonly url: string;
}

Selection

interface unstable
Since v4.1.1

The algorithm, and optionally the key id, of the key to resolve.

Signature

interface Selection {
readonly algorithm: "RS256" | "RS384" | "RS512" | "PS256" | "PS384" | "PS512" | "ES256" | "ES384" | "ES512" | "EdDSA";
readonly kid?: string;
readonly protectedHeader?: {
[key: string]: Json;
readonly alg: "RS256" | "RS384" | "RS512" | "PS256" | "PS384" | "PS512" | "ES256" | "ES384" | "ES512" | "EdDSA" | "HS256" | "HS384" | "HS512";
readonly cty?: string;
readonly kid?: string;
readonly typ?: string;
};
}

Schemas

KeySet

unstable
Since v4.1.1

Schema for a set of public JWKs.

Details

Keys of other families or curves are kept but never selected. Private or symmetric members anywhere in the set fail decoding.

Signature

declare const KeySet: Struct<{
readonly keys: $Array<Union<readonly [Union<readonly [Struct<{
readonly alg: optionalKey<String>;
readonly d: optionalKey<Never>;
readonly dp: optionalKey<Never>;
readonly dq: optionalKey<Never>;
readonly e: String;
readonly k: optionalKey<Never>;
readonly key_ops: optionalKey<$Array<...>>;
readonly kid: optionalKey<String>;
readonly kty: Literal<"RSA">;
readonly n: String;
readonly oth: optionalKey<Never>;
readonly p: optionalKey<Never>;
readonly q: optionalKey<Never>;
readonly qi: optionalKey<Never>;
readonly use: optionalKey<String>;
}>, Struct<{
readonly alg: optionalKey<String>;
readonly crv: Literals<readonly [..., ..., ...]>;
readonly d: optionalKey<Never>;
readonly dp: optionalKey<Never>;
readonly dq: optionalKey<Never>;
readonly k: optionalKey<Never>;
readonly key_ops: optionalKey<$Array<...>>;
readonly kid: optionalKey<String>;
readonly kty: Literal<"EC">;
readonly oth: optionalKey<Never>;
readonly p: optionalKey<Never>;
readonly q: optionalKey<Never>;
readonly qi: optionalKey<Never>;
readonly use: optionalKey<String>;
readonly x: String;
readonly y: String;
}>, Struct<{
readonly alg: optionalKey<String>;
readonly crv: Literal<"Ed25519">;
readonly d: optionalKey<Never>;
readonly dp: optionalKey<Never>;
readonly dq: optionalKey<Never>;
readonly k: optionalKey<Never>;
readonly key_ops: optionalKey<$Array<...>>;
readonly kid: optionalKey<String>;
readonly kty: Literal<"OKP">;
readonly oth: optionalKey<Never>;
readonly p: optionalKey<Never>;
readonly q: optionalKey<Never>;
readonly qi: optionalKey<Never>;
readonly use: optionalKey<String>;
readonly x: String;
}>]>, StructWithRest<Struct<{
readonly crv: optionalKey<String>;
readonly d: optionalKey<Never>;
readonly dp: optionalKey<Never>;
readonly dq: optionalKey<Never>;
readonly k: optionalKey<Never>;
readonly kty: String;
readonly oth: optionalKey<Never>;
readonly p: optionalKey<Never>;
readonly q: optionalKey<Never>;
readonly qi: optionalKey<Never>;
}>, readonly [$Record<String, Unknown>]>]>>;
}>

Services

Jwks

unstable
Since v4.1.1

Service that resolves the verification key for a selection.

Signature

declare class Jwks extends Shape<"effect/jose/Jwks", {
readonly resolve: (selection: Selection) => Effect<PublicKey, JoseError>;
}, this> {
constructor(_: never);
}