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

Jwe unstable

Compact JSON Web Encryption with a shared key: dir key management and A256GCM content encryption.

The protected header is authenticated as additional data, so changing it fails decryption. Headers with crit or zip are rejected.

Bound untrusted token length before decryption; this module does not impose a token-size limit.

6 exports Since v4.1.1 Source

Cryptography

decrypt

unstable
Since v4.1.1

Decrypts a compact dir/A256GCM JWE and authenticates its protected header.

Details

Accepts a key or an effectful resolver for key rotation. The token's structure and supported header parameters are checked before the resolver runs. Resolver failures and service requirements are preserved.

Gotchas

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

See

Signature

declare const decrypt: <E = never, R = never>(...args: [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>]) => Effect<Decrypted, JoseError | E, Aead | R>

encrypt

unstable
Since v4.1.1

Encrypts plaintext as a compact JWE with a random 96-bit IV.

See

Signature

declare const encrypt: <H extends object & { [P in string | number | symbol]: Json | undefined } = Header>(...args: [plaintext: Uint8Array<ArrayBufferLike>, key: SecretKey<"dir">, header?: Header & H]) => Effect<Redacted<string>, JoseError, Aead | SecureRandom>

Example Encrypting and decrypting a message

import { Effect, Layer, Redacted } from "effect"
import { Aead, SecureRandom } from "effect/crypto"
import { Jwe, Jwk } from "effect/jose"
const layer = Aead.layerWebCrypto.pipe(Layer.provideMerge(SecureRandom.layerWebCrypto))
const plaintext = 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* Jwe.encrypt(new TextEncoder().encode("private message"), key)
const decrypted = yield* Jwe.decrypt(token, key)
return new TextDecoder().decode(decrypted.plaintext)
}).pipe(Effect.provide(layer)))
plaintext // => "private message"

Models

Decrypted

interface unstable
Since v4.1.1

The protected header, plaintext, and key used to decrypt a JWE.

Signature

interface Decrypted {
readonly key: SecretKey<"dir">;
readonly plaintext: Uint8Array;
readonly protectedHeader: {
[key: string]: Json;
readonly alg: "dir";
readonly cty?: string;
readonly enc: "A256GCM";
readonly kid?: string;
readonly typ?: string;
};
}

ProtectedHeader

type unstable
Since v4.1.1

A JWE protected header. It is authenticated only after decryption succeeds.

Signature

type ProtectedHeader = typeof ProtectedHeader.Type

Schemas

Since v4.1.1

Schema for a JWE protected header, including additional JSON-valued parameters.

Signature

declare const ProtectedHeader: StructWithRest<Struct<{
readonly alg: Literal<"dir">;
readonly cty: optionalKey<String>;
readonly enc: Literal<"A256GCM">;
readonly kid: optionalKey<String>;
readonly typ: optionalKey<String>;
}>, readonly [$Record<String, Codec<Json, Json, never, never>>]>