@yielded/jose 0.1.0-beta.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel van der Merwe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # @yielded/jose
2
+
3
+ JOSE for Effect: JWK import/export, public key sets, compact signatures and
4
+ encryption, and JWTs whose claims are encoded and decoded by your Effect Schema.
5
+ Your application owns keys, accepted algorithms, issuers, audiences and token
6
+ purpose. This package depends on `@yielded/crypto` and Effect, independently of Auth.
7
+
8
+ ```sh
9
+ bun add @yielded/jose@beta @yielded/crypto@beta effect
10
+ ```
11
+
12
+ Import `Jwk`, `Jwks`, `Jws`, `Jwt`, and `Jwe` from the root. Supply cryptographic
13
+ services through an explicit crypto backend Layer. Local verification needs no
14
+ HTTP; remote JWKS use an application-configured HTTPS URL and an Effect HttpClient,
15
+ with a bounded cache and refresh lifetime owned by the Layer's Scope.
16
+
17
+ Tokens, private keys, symmetric keys and decrypted bytes use `Redacted`. JWT
18
+ verification checks the signature and registered claims before decoding your
19
+ application Schema. Schema encoding/decoding failures and services remain in
20
+ `E` and `R`; custom Schema diagnostics remain application-owned.
21
+ `Jwt.decodeUnverified` only parses and never establishes trust.
22
+
23
+ The initial profile is compact JWS/JWT with HS256, RS256, PS256, ES256 and EdDSA
24
+ (Ed25519), and compact JWE with `dir` / `A256GCM`. Other algorithms, JSON
25
+ serialization, unencoded/detached payloads, critical extensions and compression
26
+ are unsupported. OAuth, discovery, sessions and account authority belong to
27
+ other layers.
28
+
29
+ See the [usage and profile reference](../../docs/src/content/docs/reference/jose.mdx)
30
+ and the [shipped third-party notices](THIRD_PARTY_NOTICES.md).
@@ -0,0 +1,53 @@
1
+ # Third-party notices
2
+
3
+ Selected public contract tests and the P-256 fixture in `test/` are adapted from
4
+ [panva/jose](https://github.com/panva/jose/tree/505a55b8f73536082367b2614cb77e927ba96ec1),
5
+ v6.2.12, commit `505a55b8f73536082367b2614cb77e927ba96ec1` (Filip Skokan).
6
+ The selected source contracts are adapted to the supported profile:
7
+
8
+ | Upstream tests | Local tests |
9
+ | -------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
10
+ | `test/jws/compact.verify.test.ts`, `test/jws/flattened.verify.test.ts`, `test/jws/crit.test.ts`, `test/jws/restrictions.test.ts` | `test/protocols.test.ts`, `test/compact-validation.test.ts`, `test/key-policy.test.ts` |
11
+ | `test/jwk/jwk2key.test.ts`, `test/jwk/key_input.test.ts` | `test/key-policy.test.ts`, `test/protocols.test.ts` |
12
+ | `test/jwt/verify.test.ts` | `test/claims.test.ts`, `test/jwt-verification.test.ts` |
13
+ | `test/jwks/local.test.ts`, `test/jwks/remote.test.ts` | `test/jwks.test.ts`, `test/jwks-recovery.test.ts`, `test/fixtures.ts` |
14
+ | `test/jwe/compact.encrypt.test.ts`, `test/jwe/compact.decrypt.test.ts`, `test/jwe/flattened.decrypt.test.ts` | `test/protocols.test.ts`, `test/compact-validation.test.ts` |
15
+
16
+ Only applicable public behavior is adapted; flattened-format tests supply shared
17
+ header and authentication-tag validation, not JSON serialization support. Tests
18
+ use independent interoperation against that release, plus Effect-specific
19
+ policy capture, scoped cancellation and bounded-waiter regressions. This is not
20
+ a full upstream suite port or a claim of full upstream compatibility.
21
+
22
+ The source implementation informs claim validation, protected-header policy, and
23
+ key selection in `src/Jwt.ts`, `src/Jws.ts`, `src/Jwk.ts`, `src/Jwks.ts`, and
24
+ `src/Jwe.ts`; these implementations are written for Effect services and Schema.
25
+ No panva/jose runtime implementation is bundled or required.
26
+
27
+ The wire formats follow RFC 7515, RFC 7516, RFC 7517, RFC 7518, RFC 7519,
28
+ and RFC 8037; policy follows RFC 8725. No RFC code or example vectors are copied.
29
+ Cryptographic primitives are supplied by `@yielded/crypto`, which ships its own notices.
30
+
31
+ ## panva/jose — MIT
32
+
33
+ The MIT License (MIT)
34
+
35
+ Copyright (c) 2018 Filip Skokan
36
+
37
+ Permission is hereby granted, free of charge, to any person obtaining a copy
38
+ of this software and associated documentation files (the "Software"), to deal
39
+ in the Software without restriction, including without limitation the rights
40
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
41
+ copies of the Software, and to permit persons to whom the Software is
42
+ furnished to do so, subject to the following conditions:
43
+
44
+ The above copyright notice and this permission notice shall be included in all
45
+ copies or substantial portions of the Software.
46
+
47
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
48
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
49
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
50
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
51
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
52
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
53
+ SOFTWARE.
@@ -0,0 +1,33 @@
1
+ import { Schema } from "effect";
2
+ import { OperationError } from "@yielded/crypto/Errors";
3
+ //#region src/Errors.d.ts
4
+ declare const InvalidToken_base: Schema.Class<InvalidToken, Schema.TaggedStruct<"JoseInvalidToken", {
5
+ readonly reason: Schema.Literals<readonly ["serialization", "header", "payload", "parameters"]>;
6
+ }>, import("effect/Cause").YieldableError>;
7
+ /** Fixed diagnostics never include a token, claims, key, URL, or native cause. */
8
+ export declare class InvalidToken extends InvalidToken_base {}
9
+ declare const AlgorithmNotAllowed_base: Schema.Class<AlgorithmNotAllowed, Schema.TaggedStruct<"JoseAlgorithmNotAllowed", {}>, import("effect/Cause").YieldableError>;
10
+ export declare class AlgorithmNotAllowed extends AlgorithmNotAllowed_base {}
11
+ declare const InvalidKey_base: Schema.Class<InvalidKey, Schema.TaggedStruct<"JoseInvalidKey", {}>, import("effect/Cause").YieldableError>;
12
+ export declare class InvalidKey extends InvalidKey_base {}
13
+ declare const SignatureVerificationFailed_base: Schema.Class<SignatureVerificationFailed, Schema.TaggedStruct<"JoseSignatureVerificationFailed", {}>, import("effect/Cause").YieldableError>;
14
+ export declare class SignatureVerificationFailed extends SignatureVerificationFailed_base {}
15
+ declare const DecryptionFailed_base: Schema.Class<DecryptionFailed, Schema.TaggedStruct<"JoseDecryptionFailed", {}>, import("effect/Cause").YieldableError>;
16
+ export declare class DecryptionFailed extends DecryptionFailed_base {}
17
+ declare const KeyNotFound_base: Schema.Class<KeyNotFound, Schema.TaggedStruct<"JoseKeyNotFound", {}>, import("effect/Cause").YieldableError>;
18
+ export declare class KeyNotFound extends KeyNotFound_base {}
19
+ declare const AmbiguousKey_base: Schema.Class<AmbiguousKey, Schema.TaggedStruct<"JoseAmbiguousKey", {}>, import("effect/Cause").YieldableError>;
20
+ export declare class AmbiguousKey extends AmbiguousKey_base {}
21
+ declare const JwksUnavailable_base: Schema.Class<JwksUnavailable, Schema.TaggedStruct<"JoseJwksUnavailable", {
22
+ readonly reason: Schema.Literals<readonly ["configuration", "transport", "response", "cooldown", "busy", "closed"]>;
23
+ }>, import("effect/Cause").YieldableError>;
24
+ export declare class JwksUnavailable extends JwksUnavailable_base {}
25
+ declare const ClaimValidationFailed_base: Schema.Class<ClaimValidationFailed, Schema.TaggedStruct<"JoseClaimValidationFailed", {
26
+ readonly claim: Schema.Literals<readonly ["registered", "iss", "sub", "aud", "exp", "nbf", "iat", "jti", "typ"]>;
27
+ readonly reason: Schema.Literals<readonly ["invalid", "missing", "mismatch", "expired", "notYetValid", "tooOld", "future"]>;
28
+ }>, import("effect/Cause").YieldableError>;
29
+ export declare class ClaimValidationFailed extends ClaimValidationFailed_base {}
30
+ export type KeyError = InvalidKey | KeyNotFound | AmbiguousKey | JwksUnavailable | OperationError;
31
+ export type VerifyError = KeyError | InvalidToken | AlgorithmNotAllowed | SignatureVerificationFailed;
32
+ //#endregion
33
+ //# sourceMappingURL=Errors.d.mts.map
@@ -0,0 +1,49 @@
1
+ import { Schema } from "effect";
2
+ //#region src/Errors.ts
3
+ /** Fixed diagnostics never include a token, claims, key, URL, or native cause. */
4
+ var InvalidToken = class extends Schema.TaggedError()("JoseInvalidToken", { reason: Schema.Literals([
5
+ "serialization",
6
+ "header",
7
+ "payload",
8
+ "parameters"
9
+ ]) }) {};
10
+ var AlgorithmNotAllowed = class extends Schema.TaggedError()("JoseAlgorithmNotAllowed", {}) {};
11
+ var InvalidKey = class extends Schema.TaggedError()("JoseInvalidKey", {}) {};
12
+ var SignatureVerificationFailed = class extends Schema.TaggedError()("JoseSignatureVerificationFailed", {}) {};
13
+ var DecryptionFailed = class extends Schema.TaggedError()("JoseDecryptionFailed", {}) {};
14
+ var KeyNotFound = class extends Schema.TaggedError()("JoseKeyNotFound", {}) {};
15
+ var AmbiguousKey = class extends Schema.TaggedError()("JoseAmbiguousKey", {}) {};
16
+ var JwksUnavailable = class extends Schema.TaggedError()("JoseJwksUnavailable", { reason: Schema.Literals([
17
+ "configuration",
18
+ "transport",
19
+ "response",
20
+ "cooldown",
21
+ "busy",
22
+ "closed"
23
+ ]) }) {};
24
+ var ClaimValidationFailed = class extends Schema.TaggedError()("JoseClaimValidationFailed", {
25
+ claim: Schema.Literals([
26
+ "registered",
27
+ "iss",
28
+ "sub",
29
+ "aud",
30
+ "exp",
31
+ "nbf",
32
+ "iat",
33
+ "jti",
34
+ "typ"
35
+ ]),
36
+ reason: Schema.Literals([
37
+ "invalid",
38
+ "missing",
39
+ "mismatch",
40
+ "expired",
41
+ "notYetValid",
42
+ "tooOld",
43
+ "future"
44
+ ])
45
+ }) {};
46
+ //#endregion
47
+ export { AlgorithmNotAllowed, AmbiguousKey, ClaimValidationFailed, DecryptionFailed, InvalidKey, InvalidToken, JwksUnavailable, KeyNotFound, SignatureVerificationFailed };
48
+
49
+ //# sourceMappingURL=Errors.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Errors.mjs","names":[],"sources":["../src/Errors.ts"],"sourcesContent":["import type { OperationError as CryptoError } from \"@yielded/crypto/Errors\";\nimport { Schema } from \"effect\";\n\n/** Fixed diagnostics never include a token, claims, key, URL, or native cause. */\nexport class InvalidToken extends Schema.TaggedError<InvalidToken>()(\"JoseInvalidToken\", {\n reason: Schema.Literals([\"serialization\", \"header\", \"payload\", \"parameters\"]),\n}) {}\n\nexport class AlgorithmNotAllowed extends Schema.TaggedError<AlgorithmNotAllowed>()(\n \"JoseAlgorithmNotAllowed\",\n {},\n) {}\n\nexport class InvalidKey extends Schema.TaggedError<InvalidKey>()(\"JoseInvalidKey\", {}) {}\n\nexport class SignatureVerificationFailed extends Schema.TaggedError<SignatureVerificationFailed>()(\n \"JoseSignatureVerificationFailed\",\n {},\n) {}\n\nexport class DecryptionFailed extends Schema.TaggedError<DecryptionFailed>()(\n \"JoseDecryptionFailed\",\n {},\n) {}\n\nexport class KeyNotFound extends Schema.TaggedError<KeyNotFound>()(\"JoseKeyNotFound\", {}) {}\nexport class AmbiguousKey extends Schema.TaggedError<AmbiguousKey>()(\"JoseAmbiguousKey\", {}) {}\n\nexport class JwksUnavailable extends Schema.TaggedError<JwksUnavailable>()(\"JoseJwksUnavailable\", {\n reason: Schema.Literals([\"configuration\", \"transport\", \"response\", \"cooldown\", \"busy\", \"closed\"]),\n}) {}\n\nexport class ClaimValidationFailed extends Schema.TaggedError<ClaimValidationFailed>()(\n \"JoseClaimValidationFailed\",\n {\n claim: Schema.Literals([\"registered\", \"iss\", \"sub\", \"aud\", \"exp\", \"nbf\", \"iat\", \"jti\", \"typ\"]),\n reason: Schema.Literals([\n \"invalid\",\n \"missing\",\n \"mismatch\",\n \"expired\",\n \"notYetValid\",\n \"tooOld\",\n \"future\",\n ]),\n },\n) {}\n\nexport type KeyError = InvalidKey | KeyNotFound | AmbiguousKey | JwksUnavailable | CryptoError;\n\nexport type VerifyError =\n | KeyError\n | InvalidToken\n | AlgorithmNotAllowed\n | SignatureVerificationFailed;\n"],"mappings":";;;AAIA,IAAa,eAAb,cAAkC,OAAO,YAA0B,CAAC,CAAC,oBAAoB,EACvF,QAAQ,OAAO,SAAS;CAAC;CAAiB;CAAU;CAAW;AAAY,CAAC,EAC9E,CAAC,CAAC,CAAC,CAAC;AAEJ,IAAa,sBAAb,cAAyC,OAAO,YAAiC,CAAC,CAChF,2BACA,CAAC,CACH,CAAC,CAAC,CAAC;AAEH,IAAa,aAAb,cAAgC,OAAO,YAAwB,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;AAExF,IAAa,8BAAb,cAAiD,OAAO,YAAyC,CAAC,CAChG,mCACA,CAAC,CACH,CAAC,CAAC,CAAC;AAEH,IAAa,mBAAb,cAAsC,OAAO,YAA8B,CAAC,CAC1E,wBACA,CAAC,CACH,CAAC,CAAC,CAAC;AAEH,IAAa,cAAb,cAAiC,OAAO,YAAyB,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3F,IAAa,eAAb,cAAkC,OAAO,YAA0B,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9F,IAAa,kBAAb,cAAqC,OAAO,YAA6B,CAAC,CAAC,uBAAuB,EAChG,QAAQ,OAAO,SAAS;CAAC;CAAiB;CAAa;CAAY;CAAY;CAAQ;AAAQ,CAAC,EAClG,CAAC,CAAC,CAAC,CAAC;AAEJ,IAAa,wBAAb,cAA2C,OAAO,YAAmC,CAAC,CACpF,6BACA;CACE,OAAO,OAAO,SAAS;EAAC;EAAc;EAAO;EAAO;EAAO;EAAO;EAAO;EAAO;EAAO;CAAK,CAAC;CAC7F,QAAQ,OAAO,SAAS;EACtB;EACA;EACA;EACA;EACA;EACA;EACA;CACF,CAAC;AACH,CACF,CAAC,CAAC,CAAC"}
package/dist/Jwe.d.mts ADDED
@@ -0,0 +1,35 @@
1
+ import { DecryptionFailed, InvalidKey, InvalidToken } from "./Errors.mjs";
2
+ import { SecretKey } from "./Jwk.mjs";
3
+ import { Crypto, Effect, Redacted, Schema } from "effect";
4
+ import { Aead } from "@yielded/crypto/Aead";
5
+ import { OperationError } from "@yielded/crypto/Errors";
6
+ //#region src/Jwe.d.ts
7
+ export declare const Header: Schema.Struct<{
8
+ readonly alg: Schema.Literal<"dir">;
9
+ readonly enc: Schema.Literal<"A256GCM">;
10
+ readonly kid: Schema.optionalKey<Schema.String>;
11
+ readonly typ: Schema.optionalKey<Schema.NonEmptyString>;
12
+ readonly cty: Schema.optionalKey<Schema.NonEmptyString>;
13
+ }>;
14
+ export type Header = typeof Header.Type;
15
+ export type JweError = InvalidToken | InvalidKey | OperationError | DecryptionFailed;
16
+ /** Generates a fresh 96-bit IV; random-source failures become CryptoUnavailable. */
17
+ export declare const encrypt: (plaintext: Redacted.Redacted<Uint8Array<ArrayBufferLike>>, key: SecretKey, input: {
18
+ readonly alg: "dir";
19
+ readonly enc: "A256GCM";
20
+ readonly kid?: string;
21
+ readonly typ?: string;
22
+ readonly cty?: string;
23
+ }) => Effect.Effect<Redacted.Redacted<string>, JweError, Aead | Crypto.Crypto>;
24
+ export declare const decrypt: (token: Redacted.Redacted<string>, key: SecretKey) => Effect.Effect<{
25
+ protectedHeader: {
26
+ readonly alg: "dir";
27
+ readonly enc: "A256GCM";
28
+ readonly kid?: string;
29
+ readonly typ?: string;
30
+ readonly cty?: string;
31
+ };
32
+ plaintext: Redacted.Redacted<Uint8Array<ArrayBufferLike>>;
33
+ }, DecryptionFailed | InvalidKey | InvalidToken | OperationError, Aead>;
34
+ //#endregion
35
+ //# sourceMappingURL=Jwe.d.mts.map
package/dist/Jwe.mjs ADDED
@@ -0,0 +1,66 @@
1
+ import { DecryptionFailed, InvalidKey, InvalidToken } from "./Errors.mjs";
2
+ import { JsonObject, decode, json, parse, reveal, split, stringify, utf8 } from "./internal/encoding.mjs";
3
+ import { check } from "./internal/keyPolicy.mjs";
4
+ import { Crypto, Effect, Redacted, Schema } from "effect";
5
+ import { Base64Url } from "effect/encoding";
6
+ import { Aead } from "@yielded/crypto/Aead";
7
+ import { CryptoUnavailable } from "@yielded/crypto/Errors";
8
+ //#region src/Jwe.ts
9
+ const Header = Schema.Struct({
10
+ alg: Schema.Literal("dir"),
11
+ enc: Schema.Literal("A256GCM"),
12
+ kid: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(256))),
13
+ typ: Schema.optionalKey(Schema.NonEmptyString),
14
+ cty: Schema.optionalKey(Schema.NonEmptyString)
15
+ });
16
+ const readHeader = Effect.fnUntraced(function* (input) {
17
+ const raw = yield* parse(JsonObject, input, "header");
18
+ if (raw.crit !== void 0 || raw.zip !== void 0) return yield* InvalidToken.make({ reason: "header" });
19
+ return yield* parse(Header, raw, "header");
20
+ });
21
+ /** Generates a fresh 96-bit IV; random-source failures become CryptoUnavailable. */
22
+ const encrypt = Effect.fnUntraced(function* (plaintext, key, input) {
23
+ const header = yield* readHeader(input);
24
+ if (key.algorithm !== "dir") return yield* InvalidKey.make({});
25
+ yield* check(yield* reveal(key.jwk), "dir", "encrypt");
26
+ yield* parse(Schema.Uint8Array.check(Schema.isMaxLength(45e3)), yield* reveal(plaintext), "payload");
27
+ const protectedPart = Base64Url.encode(yield* stringify(header).pipe(Effect.mapError(() => InvalidToken.make({ reason: "header" }))));
28
+ if (protectedPart.length > 4096) return yield* InvalidToken.make({ reason: "header" });
29
+ const nonce = yield* (yield* Crypto.Crypto).randomBytes(12).pipe(Effect.mapError(() => CryptoUnavailable.make({})));
30
+ const sealed = yield* (yield* Aead).encrypt({
31
+ algorithm: "AES-256-GCM",
32
+ key: key.material,
33
+ nonce,
34
+ plaintext,
35
+ additionalData: utf8(protectedPart)
36
+ });
37
+ return Redacted.make(`${protectedPart}..${Base64Url.encode(nonce)}.${Base64Url.encode(sealed.subarray(0, -16))}.${Base64Url.encode(sealed.subarray(-16))}`);
38
+ });
39
+ const decrypt = Effect.fnUntraced(function* (token, key) {
40
+ const [protectedPart, encryptedKey, iv, ciphertext, tag] = yield* split(token, 5);
41
+ if (encryptedKey !== "" || protectedPart.length > 4096) return yield* InvalidToken.make({ reason: "serialization" });
42
+ const protectedHeader = yield* readHeader(yield* json(yield* decode(protectedPart), "header"));
43
+ if (key.algorithm !== "dir") return yield* InvalidKey.make({});
44
+ yield* check(yield* reveal(key.jwk), "dir", "decrypt");
45
+ const nonce = yield* decode(iv);
46
+ const data = yield* decode(ciphertext);
47
+ const authTag = yield* decode(tag);
48
+ if (nonce.length !== 12 || authTag.length !== 16) return yield* InvalidToken.make({ reason: "serialization" });
49
+ const sealed = new Uint8Array(data.length + authTag.length);
50
+ sealed.set(data);
51
+ sealed.set(authTag, data.length);
52
+ return {
53
+ protectedHeader,
54
+ plaintext: yield* (yield* Aead).decrypt({
55
+ algorithm: "AES-256-GCM",
56
+ key: key.material,
57
+ nonce,
58
+ ciphertext: sealed,
59
+ additionalData: utf8(protectedPart)
60
+ }).pipe(Effect.catchTag("CryptoAuthenticationFailed", () => DecryptionFailed.make({})))
61
+ };
62
+ });
63
+ //#endregion
64
+ export { Header, decrypt, encrypt };
65
+
66
+ //# sourceMappingURL=Jwe.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Jwe.mjs","names":["KeyPolicy.check"],"sources":["../src/Jwe.ts"],"sourcesContent":["import { Aead } from \"@yielded/crypto/Aead\";\nimport { CryptoUnavailable, type OperationError } from \"@yielded/crypto/Errors\";\nimport { Crypto, Effect, Redacted, Schema } from \"effect\";\nimport { Base64Url } from \"effect/encoding\";\n\nimport { DecryptionFailed, InvalidKey, InvalidToken } from \"./Errors\";\nimport {\n decode,\n json,\n JsonObject,\n parse,\n reveal,\n split,\n stringify,\n utf8,\n} from \"./internal/encoding\";\nimport * as KeyPolicy from \"./internal/keyPolicy\";\nimport type { SecretKey } from \"./Jwk\";\n\nexport const Header = Schema.Struct({\n alg: Schema.Literal(\"dir\"),\n enc: Schema.Literal(\"A256GCM\"),\n kid: Schema.optionalKey(Schema.String.check(Schema.isMaxLength(256))),\n typ: Schema.optionalKey(Schema.NonEmptyString),\n cty: Schema.optionalKey(Schema.NonEmptyString),\n});\n\nexport type Header = typeof Header.Type;\nexport type JweError = InvalidToken | InvalidKey | OperationError | DecryptionFailed;\n\nconst readHeader = Effect.fnUntraced(function* (input: unknown) {\n const raw = yield* parse(JsonObject, input, \"header\");\n\n if (raw.crit !== undefined || raw.zip !== undefined)\n return yield* InvalidToken.make({ reason: \"header\" });\n\n return yield* parse(Header, raw, \"header\");\n});\n\n/** Generates a fresh 96-bit IV; random-source failures become CryptoUnavailable. */\nexport const encrypt = Effect.fnUntraced(function* (\n plaintext: Redacted.Redacted<Uint8Array>,\n key: SecretKey,\n input: Header,\n): Effect.fn.Return<Redacted.Redacted<string>, JweError, Aead | Crypto.Crypto> {\n const header = yield* readHeader(input);\n\n if (key.algorithm !== \"dir\") return yield* InvalidKey.make({});\n yield* KeyPolicy.check(yield* reveal(key.jwk), \"dir\", \"encrypt\");\n yield* parse(\n Schema.Uint8Array.check(Schema.isMaxLength(45000)),\n yield* reveal(plaintext),\n \"payload\",\n );\n\n const protectedPart = Base64Url.encode(\n yield* stringify(header).pipe(Effect.mapError(() => InvalidToken.make({ reason: \"header\" }))),\n );\n\n if (protectedPart.length > 4096) return yield* InvalidToken.make({ reason: \"header\" });\n const random = yield* Crypto.Crypto;\n\n const nonce = yield* random\n .randomBytes(12)\n .pipe(Effect.mapError(() => CryptoUnavailable.make({})));\n\n const aead = yield* Aead;\n\n const sealed = yield* aead.encrypt({\n algorithm: \"AES-256-GCM\",\n key: key.material,\n nonce,\n plaintext,\n additionalData: utf8(protectedPart),\n });\n\n return Redacted.make(\n `${protectedPart}..${Base64Url.encode(nonce)}.${Base64Url.encode(sealed.subarray(0, -16))}.${Base64Url.encode(sealed.subarray(-16))}`,\n );\n});\n\nexport const decrypt = Effect.fnUntraced(function* (\n token: Redacted.Redacted<string>,\n key: SecretKey,\n) {\n const [protectedPart, encryptedKey, iv, ciphertext, tag] = yield* split(token, 5);\n\n if (encryptedKey !== \"\" || protectedPart.length > 4096)\n return yield* InvalidToken.make({ reason: \"serialization\" });\n const protectedHeader = yield* readHeader(yield* json(yield* decode(protectedPart), \"header\"));\n\n if (key.algorithm !== \"dir\") return yield* InvalidKey.make({});\n yield* KeyPolicy.check(yield* reveal(key.jwk), \"dir\", \"decrypt\");\n const nonce = yield* decode(iv);\n const data = yield* decode(ciphertext);\n const authTag = yield* decode(tag);\n\n if (nonce.length !== 12 || authTag.length !== 16)\n return yield* InvalidToken.make({ reason: \"serialization\" });\n const sealed = new Uint8Array(data.length + authTag.length);\n\n sealed.set(data);\n sealed.set(authTag, data.length);\n const aead = yield* Aead;\n\n const plaintext = yield* aead\n .decrypt({\n algorithm: \"AES-256-GCM\",\n key: key.material,\n nonce,\n ciphertext: sealed,\n additionalData: utf8(protectedPart),\n })\n .pipe(Effect.catchTag(\"CryptoAuthenticationFailed\", () => DecryptionFailed.make({})));\n\n return { protectedHeader, plaintext };\n});\n"],"mappings":"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"}
package/dist/Jwk.d.mts ADDED
@@ -0,0 +1,273 @@
1
+ import { InvalidKey } from "./Errors.mjs";
2
+ import { Effect, Redacted, Schema } from "effect";
3
+ import * as Signature$1 from "@yielded/crypto/Signature";
4
+ //#region src/Jwk.d.ts
5
+ export declare const AsymmetricAlgorithm: Schema.Literals<readonly ["RS256", "PS256", "ES256", "EdDSA"]>;
6
+ export type AsymmetricAlgorithm = typeof AsymmetricAlgorithm.Type;
7
+ export declare const Algorithm: Schema.Literals<readonly ["HS256", "RS256", "PS256", "ES256", "EdDSA"]>;
8
+ export type Algorithm = typeof Algorithm.Type;
9
+ export declare const PublicJwk: Schema.Union<readonly [Schema.Struct<{
10
+ readonly kid: Schema.optionalKey<Schema.String>;
11
+ readonly alg: Schema.optionalKey<Schema.NonEmptyString>;
12
+ readonly use: Schema.optionalKey<Schema.Literals<readonly ["sig", "enc"]>>;
13
+ readonly key_ops: Schema.optionalKey<Schema.$Array<Schema.NonEmptyString>>;
14
+ readonly kty: Schema.Literal<"RSA">;
15
+ readonly n: Schema.String;
16
+ readonly e: Schema.String;
17
+ readonly d: Schema.optionalKey<Schema.Never>;
18
+ readonly k: Schema.optionalKey<Schema.Never>;
19
+ }>, Schema.Struct<{
20
+ readonly kid: Schema.optionalKey<Schema.String>;
21
+ readonly alg: Schema.optionalKey<Schema.NonEmptyString>;
22
+ readonly use: Schema.optionalKey<Schema.Literals<readonly ["sig", "enc"]>>;
23
+ readonly key_ops: Schema.optionalKey<Schema.$Array<Schema.NonEmptyString>>;
24
+ readonly kty: Schema.Literal<"EC">;
25
+ readonly crv: Schema.Literal<"P-256">;
26
+ readonly x: Schema.String;
27
+ readonly y: Schema.String;
28
+ readonly d: Schema.optionalKey<Schema.Never>;
29
+ readonly k: Schema.optionalKey<Schema.Never>;
30
+ }>, Schema.Struct<{
31
+ readonly kid: Schema.optionalKey<Schema.String>;
32
+ readonly alg: Schema.optionalKey<Schema.NonEmptyString>;
33
+ readonly use: Schema.optionalKey<Schema.Literals<readonly ["sig", "enc"]>>;
34
+ readonly key_ops: Schema.optionalKey<Schema.$Array<Schema.NonEmptyString>>;
35
+ readonly kty: Schema.Literal<"OKP">;
36
+ readonly crv: Schema.Literal<"Ed25519">;
37
+ readonly x: Schema.String;
38
+ readonly d: Schema.optionalKey<Schema.Never>;
39
+ readonly k: Schema.optionalKey<Schema.Never>;
40
+ }>]>;
41
+ export type PublicJwk = typeof PublicJwk.Type;
42
+ export declare const PrivateJwk: Schema.Union<readonly [Schema.Struct<{
43
+ readonly kid: Schema.optionalKey<Schema.String>;
44
+ readonly alg: Schema.optionalKey<Schema.NonEmptyString>;
45
+ readonly use: Schema.optionalKey<Schema.Literals<readonly ["sig", "enc"]>>;
46
+ readonly key_ops: Schema.optionalKey<Schema.$Array<Schema.NonEmptyString>>;
47
+ readonly kty: Schema.Literal<"RSA">;
48
+ readonly n: Schema.String;
49
+ readonly e: Schema.String;
50
+ readonly d: Schema.String;
51
+ readonly p: Schema.String;
52
+ readonly q: Schema.String;
53
+ readonly dp: Schema.String;
54
+ readonly dq: Schema.String;
55
+ readonly qi: Schema.String;
56
+ readonly oth: Schema.optionalKey<Schema.Never>;
57
+ }>, Schema.Struct<{
58
+ readonly kid: Schema.optionalKey<Schema.String>;
59
+ readonly alg: Schema.optionalKey<Schema.NonEmptyString>;
60
+ readonly use: Schema.optionalKey<Schema.Literals<readonly ["sig", "enc"]>>;
61
+ readonly key_ops: Schema.optionalKey<Schema.$Array<Schema.NonEmptyString>>;
62
+ readonly kty: Schema.Literal<"EC">;
63
+ readonly crv: Schema.Literal<"P-256">;
64
+ readonly x: Schema.String;
65
+ readonly y: Schema.String;
66
+ readonly d: Schema.String;
67
+ }>, Schema.Struct<{
68
+ readonly kid: Schema.optionalKey<Schema.String>;
69
+ readonly alg: Schema.optionalKey<Schema.NonEmptyString>;
70
+ readonly use: Schema.optionalKey<Schema.Literals<readonly ["sig", "enc"]>>;
71
+ readonly key_ops: Schema.optionalKey<Schema.$Array<Schema.NonEmptyString>>;
72
+ readonly kty: Schema.Literal<"OKP">;
73
+ readonly crv: Schema.Literal<"Ed25519">;
74
+ readonly x: Schema.String;
75
+ readonly d: Schema.String;
76
+ }>]>;
77
+ export type PrivateJwk = typeof PrivateJwk.Type;
78
+ export declare const SecretJwk: Schema.Struct<{
79
+ readonly kid: Schema.optionalKey<Schema.String>;
80
+ readonly alg: Schema.optionalKey<Schema.NonEmptyString>;
81
+ readonly use: Schema.optionalKey<Schema.Literals<readonly ["sig", "enc"]>>;
82
+ readonly key_ops: Schema.optionalKey<Schema.$Array<Schema.NonEmptyString>>;
83
+ readonly kty: Schema.Literal<"oct">;
84
+ readonly k: Schema.String;
85
+ }>;
86
+ export type SecretJwk = typeof SecretJwk.Type;
87
+ /** Validated, algorithm-bound key snapshots. Private material remains Redacted. */
88
+ export interface PublicKey {
89
+ readonly _tag: "PublicKey";
90
+ readonly algorithm: AsymmetricAlgorithm;
91
+ readonly jwk: PublicJwk;
92
+ readonly material: Uint8Array;
93
+ }
94
+ export interface PrivateKey {
95
+ readonly _tag: "PrivateKey";
96
+ readonly algorithm: AsymmetricAlgorithm;
97
+ readonly jwk: Redacted.Redacted<PrivateJwk>;
98
+ readonly material: Redacted.Redacted<Uint8Array>;
99
+ }
100
+ export interface SecretKey {
101
+ readonly _tag: "SecretKey";
102
+ readonly algorithm: "HS256" | "dir";
103
+ readonly jwk: Redacted.Redacted<SecretJwk>;
104
+ readonly material: Redacted.Redacted<Uint8Array>;
105
+ }
106
+ export type SigningKey = PrivateKey | SecretKey;
107
+ export type VerificationKey = PublicKey | SecretKey;
108
+ export declare const importPublic: (input: unknown, selected: "ES256" | "EdDSA" | "PS256" | "RS256") => Effect.Effect<Readonly<{
109
+ _tag: "PublicKey";
110
+ algorithm: "ES256" | "EdDSA" | "PS256" | "RS256";
111
+ jwk: {
112
+ readonly kid?: string;
113
+ readonly alg?: string;
114
+ readonly use?: "enc" | "sig";
115
+ readonly key_ops?: readonly string[];
116
+ readonly kty: "RSA";
117
+ readonly n: string;
118
+ readonly e: string;
119
+ readonly d?: never;
120
+ readonly k?: never;
121
+ } | {
122
+ readonly kid?: string;
123
+ readonly alg?: string;
124
+ readonly use?: "enc" | "sig";
125
+ readonly key_ops?: readonly string[];
126
+ readonly kty: "EC";
127
+ readonly crv: "P-256";
128
+ readonly x: string;
129
+ readonly y: string;
130
+ readonly d?: never;
131
+ readonly k?: never;
132
+ } | {
133
+ readonly kid?: string;
134
+ readonly alg?: string;
135
+ readonly use?: "enc" | "sig";
136
+ readonly key_ops?: readonly string[];
137
+ readonly kty: "OKP";
138
+ readonly crv: "Ed25519";
139
+ readonly x: string;
140
+ readonly d?: never;
141
+ readonly k?: never;
142
+ };
143
+ material: Uint8Array<ArrayBufferLike>;
144
+ }>, import("@yielded/crypto/Errors").CryptoUnavailable | InvalidKey | import("@yielded/crypto/Errors").UnsupportedAlgorithm, Signature$1.Signature>;
145
+ export declare const importPrivate: (input: Redacted.Redacted<unknown>, selected: "ES256" | "EdDSA" | "PS256" | "RS256") => Effect.Effect<Readonly<{
146
+ _tag: "PrivateKey";
147
+ algorithm: "ES256" | "EdDSA" | "PS256" | "RS256";
148
+ jwk: Redacted.Redacted<{
149
+ readonly kid?: string;
150
+ readonly alg?: string;
151
+ readonly use?: "enc" | "sig";
152
+ readonly key_ops?: readonly string[];
153
+ readonly kty: "RSA";
154
+ readonly n: string;
155
+ readonly e: string;
156
+ readonly d: string;
157
+ readonly p: string;
158
+ readonly q: string;
159
+ readonly dp: string;
160
+ readonly dq: string;
161
+ readonly qi: string;
162
+ readonly oth?: never;
163
+ } | {
164
+ readonly kid?: string;
165
+ readonly alg?: string;
166
+ readonly use?: "enc" | "sig";
167
+ readonly key_ops?: readonly string[];
168
+ readonly kty: "EC";
169
+ readonly crv: "P-256";
170
+ readonly x: string;
171
+ readonly y: string;
172
+ readonly d: string;
173
+ } | {
174
+ readonly kid?: string;
175
+ readonly alg?: string;
176
+ readonly use?: "enc" | "sig";
177
+ readonly key_ops?: readonly string[];
178
+ readonly kty: "OKP";
179
+ readonly crv: "Ed25519";
180
+ readonly x: string;
181
+ readonly d: string;
182
+ }>;
183
+ material: Redacted.Redacted<Uint8Array<ArrayBufferLike>>;
184
+ }>, import("@yielded/crypto/Errors").CryptoUnavailable | InvalidKey | import("@yielded/crypto/Errors").UnsupportedAlgorithm, Signature$1.Signature>;
185
+ export declare const importSecret: (input: Redacted.Redacted<unknown>, selected: "HS256" | "dir") => Effect.Effect<Readonly<{
186
+ _tag: "SecretKey";
187
+ algorithm: "HS256" | "dir";
188
+ jwk: Redacted.Redacted<{
189
+ readonly kid?: string;
190
+ readonly alg?: string;
191
+ readonly use?: "enc" | "sig";
192
+ readonly key_ops?: readonly string[];
193
+ readonly kty: "oct";
194
+ readonly k: string;
195
+ }>;
196
+ material: Redacted.Redacted<Uint8Array<ArrayBufferLike>>;
197
+ }>, InvalidKey, never>;
198
+ export declare const exportPublic: (key: PublicKey) => Effect.Effect<{
199
+ readonly kid?: string;
200
+ readonly alg?: string;
201
+ readonly use?: "enc" | "sig";
202
+ readonly key_ops?: readonly string[];
203
+ readonly kty: "RSA";
204
+ readonly n: string;
205
+ readonly e: string;
206
+ readonly d?: never;
207
+ readonly k?: never;
208
+ } | {
209
+ readonly kid?: string;
210
+ readonly alg?: string;
211
+ readonly use?: "enc" | "sig";
212
+ readonly key_ops?: readonly string[];
213
+ readonly kty: "EC";
214
+ readonly crv: "P-256";
215
+ readonly x: string;
216
+ readonly y: string;
217
+ readonly d?: never;
218
+ readonly k?: never;
219
+ } | {
220
+ readonly kid?: string;
221
+ readonly alg?: string;
222
+ readonly use?: "enc" | "sig";
223
+ readonly key_ops?: readonly string[];
224
+ readonly kty: "OKP";
225
+ readonly crv: "Ed25519";
226
+ readonly x: string;
227
+ readonly d?: never;
228
+ readonly k?: never;
229
+ }, InvalidKey, never>;
230
+ export declare const exportPrivate: (key: PrivateKey | SecretKey) => Effect.Effect<Redacted.Redacted<{
231
+ readonly kid?: string;
232
+ readonly alg?: string;
233
+ readonly use?: "enc" | "sig";
234
+ readonly key_ops?: readonly string[];
235
+ readonly kty: "RSA";
236
+ readonly n: string;
237
+ readonly e: string;
238
+ readonly d: string;
239
+ readonly p: string;
240
+ readonly q: string;
241
+ readonly dp: string;
242
+ readonly dq: string;
243
+ readonly qi: string;
244
+ readonly oth?: never;
245
+ } | {
246
+ readonly kid?: string;
247
+ readonly alg?: string;
248
+ readonly use?: "enc" | "sig";
249
+ readonly key_ops?: readonly string[];
250
+ readonly kty: "EC";
251
+ readonly crv: "P-256";
252
+ readonly x: string;
253
+ readonly y: string;
254
+ readonly d: string;
255
+ } | {
256
+ readonly kid?: string;
257
+ readonly alg?: string;
258
+ readonly use?: "enc" | "sig";
259
+ readonly key_ops?: readonly string[];
260
+ readonly kty: "OKP";
261
+ readonly crv: "Ed25519";
262
+ readonly x: string;
263
+ readonly d: string;
264
+ } | {
265
+ readonly kid?: string;
266
+ readonly alg?: string;
267
+ readonly use?: "enc" | "sig";
268
+ readonly key_ops?: readonly string[];
269
+ readonly kty: "oct";
270
+ readonly k: string;
271
+ }>, InvalidKey, never>;
272
+ //#endregion
273
+ //# sourceMappingURL=Jwk.d.mts.map