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

Jwt unstable

Signed or encrypted compact JSON Web Tokens whose claims are encoded and decoded with a Schema.

Verification and decryption authenticate the token first, then check the registered claims and the validation policy, and only then decode the application claims. exp and nbf are checked whenever they are present; require them with requiredClaims.

Bound untrusted token length before verification, decryption, or unverified decoding; this module does not impose a token-size limit.

14 exports Since v4.1.1 Source

Cryptography

decrypt

unstable
Since v4.1.1

Decrypts a compact dir/A256GCM JWT, checks its claims against the policy, and decodes the claims with a schema.

Details

Accepts a key or an effectful resolver for key rotation. The same claim policy as verify is applied after authenticated decryption and before the application schema is decoded.

Gotchas

The resolver receives an unauthenticated header and must use it only for key selection.

See

Signature

declare const decrypt: <S extends Constraint, E = never, R = never>(...args: [schema: S, token: string | Redacted<string>, key: SecretKey<"dir"> | (header: {
[key: string]: Json;
readonly alg: "dir";
readonly cty?: string;
readonly enc: "A256GCM";
readonly kid?: string;
readonly typ?: string;
}) => Effect<SecretKey<"dir">, E, R>, options?: VerifyOptions]) => Effect<Decrypted<S["Type"]>, JwtError | E, Aead | R | S["DecodingServices"]>

encrypt

unstable
Since v4.1.1

Encodes claims with a schema and encrypts them as a compact dir/A256GCM JWT.

Details

The encoded claims must be a JSON object whose registered claims match RegisteredClaims.

See

Signature

declare function encrypt<S extends Constraint, H extends object & { [P in string | number | symbol]: Json | undefined } = Header>(schema: S, claims: S["Type"], key: SecretKey<"dir">, header?: Header & H): Effect<Redacted<string>, JwtError, Aead | SecureRandom | S["EncodingServices"]>

Example Encrypting and validating application claims

import { Effect, Layer, Redacted, Schema } from "effect"
import { Aead, SecureRandom } from "effect/crypto"
import { Jwk, Jwt } from "effect/jose"
const layer = Aead.layerWebCrypto.pipe(Layer.provideMerge(SecureRandom.layerWebCrypto))
const Claims = Schema.Struct({ sub: Schema.String })
const claims = await Effect.runPromise(Effect.gen(function*() {
// Fixed public example material; generate application secrets securely.
const key = yield* Jwk.importSecret(
Redacted.make({ kty: "oct", k: "BwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwc" } as const),
"dir"
)
const token = yield* Jwt.encrypt(Claims, { sub: "user-123" }, key, { typ: "session+jwt" })
const decrypted = yield* Jwt.decrypt(Claims, token, key, { typ: "session+jwt" })
return decrypted.claims
}).pipe(Effect.provide(layer)))
claims // => ({ sub: "user-123" })

sign

unstable
Since v4.1.1

Encodes claims with a schema and signs them as a compact JWT.

Details

The encoded claims must be a JSON object whose registered claims match RegisteredClaims.

See

Signature

declare function sign<S extends Constraint, K extends SigningKey, H extends object & { [P in string | number | symbol]: Json | undefined } = Header>(schema: S, claims: S["Type"], key: K, header?: Header & H): Effect<Redacted<string>, JwtError, S["EncodingServices"] | KeyRequirements<K>>

verify

unstable
Since v4.1.1

Verifies a compact JWT with a key, checks its claims against the policy, and decodes the claims with a schema.

See

Signature

declare const verify: <S extends Schema.Constraint, K extends VerificationKey>(schema: S, token: string | Redacted.Redacted<string>, key: K, options?: VerifyOptions) => Effect.Effect<Verified<S["Type"]>, JwtError, S["DecodingServices"] | Jws.KeyRequirements<K>>

Example Verifying a token

import { Effect, Layer, Redacted, Schema } from "effect"
import { Mac, SecureRandom, Signature } from "effect/crypto"
import { Jwk, Jwt } from "effect/jose"
const layer = Layer.mergeAll(Mac.layerWebCrypto, Signature.layerWebCrypto).pipe(
Layer.provide(SecureRandom.layerWebCrypto)
)
const Claims = Schema.Struct({ sub: Schema.String, iss: Schema.String })
const claims = await Effect.runPromise(Effect.gen(function*() {
// Fixed public example material; generate application secrets securely.
const key = yield* Jwk.importSecret(
Redacted.make({ kty: "oct", k: "BwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwcHBwc" } as const),
"HS256"
)
const token = yield* Jwt.sign(Claims, { sub: "user-123", iss: "example" }, key)
const verified = yield* Jwt.verify(Claims, token, key, { issuer: "example", requiredClaims: ["sub"] })
return verified.claims
}).pipe(Effect.provide(layer)))
claims // => ({ sub: "user-123", iss: "example" })
Since v4.1.1

Verifies a compact JWT with a public key resolved from the Jwks service, checks its claims against the policy, and decodes the claims with a schema.

See

  • verify for verifying with a known key

Signature

declare const verifyWithKeySet: <S extends Schema.Constraint>(schema: S, token: string | Redacted.Redacted<string>, options: VerifyWithKeySetOptions) => Effect.Effect<Verified<S["Type"]> & {
readonly key: PublicKey;
}, JwtError, S["DecodingServices"] | Jwks | Signature.Signature>

Decoding

Since v4.1.1

Reads the protected header and claims of a signed JWT without verifying it.

Gotchas

Nothing returned here is authenticated. Use it only to choose how to verify, never to authorize.

See

Signature

declare const decodeUnverified: (...args: [token: string | Redacted<string>]) => Effect<Unverified, JoseError, never>

Errors

JwtError

type unstable
Since v4.1.1

Failures of JWT operations: JOSE failures, and schema failures while encoding or decoding the application claims.

Signature

type JwtError = JoseError.JoseError | Schema.SchemaError

Models

Decrypted

interface unstable
Since v4.1.1

A decrypted and validated JWT, with its protected header and decryption key.

Signature

interface Decrypted<A> extends Verified<A, Jwe.ProtectedHeader> {
readonly key: SecretKey<"dir">;
}

RegisteredClaims

type unstable
Since v4.1.1

The registered claims of a JWT.

Signature

type RegisteredClaims = typeof RegisteredClaims.Type

Unverified

interface unstable
Since v4.1.1

The protected header and claims of a signed JWT that has not been verified.

Signature

interface Unverified {
readonly claims: Readonly<Record<string, Schema.Json>>;
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;
};
}

Verified

interface unstable
Since v4.1.1

A verified JWT: decoded application claims, its registered claims, and the authenticated protected header.

Signature

interface Verified<A, H = Jws.ProtectedHeader> {
readonly claims: A;
readonly protectedHeader: H;
readonly registeredClaims: {
readonly aud?: string | readonly Array<string>;
readonly exp?: number;
readonly iat?: number;
readonly iss?: string;
readonly jti?: string;
readonly nbf?: number;
readonly sub?: string;
};
}

VerifyOptions

interface unstable
Since v4.1.1

The claim validation policy for a signed or encrypted JWT.

Signature

interface VerifyOptions {
readonly audience?: string | readonly Array<string>;
readonly clockTolerance?: Input;
readonly issuer?: string | readonly Array<string>;
readonly maxTokenAge?: Input;
readonly requiredClaims?: readonly Array<TypeOptionalKeys<{
readonly aud: optionalKey<Union<readonly [String, $Array<String>]>>;
readonly exp: optionalKey<Finite>;
readonly iat: optionalKey<Finite>;
readonly iss: optionalKey<String>;
readonly jti: optionalKey<String>;
readonly nbf: optionalKey<Finite>;
readonly sub: optionalKey<String>;
}>>;
readonly subject?: string;
readonly typ?: string;
}

VerifyWithKeySetOptions

interface unstable
Since v4.1.1

Options for verifyWithKeySet: the verification policy and the accepted algorithms.

Signature

interface VerifyWithKeySetOptions extends VerifyOptions, VerifyWithKeySetOptions {}

Schemas

Since v4.1.1

Schema for the registered claims: string iss, sub, and jti, a string or string array aud, and finite NumericDate exp, nbf, and iat.

Signature

declare const RegisteredClaims: Struct<{
readonly aud: optionalKey<Union<readonly [String, $Array<String>]>>;
readonly exp: optionalKey<Finite>;
readonly iat: optionalKey<Finite>;
readonly iss: optionalKey<String>;
readonly jti: optionalKey<String>;
readonly nbf: optionalKey<Finite>;
readonly sub: optionalKey<String>;
}>