@gjermundgaraba/clankerauth-dev 0.6.0 → 0.7.0

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/README.md CHANGED
@@ -84,8 +84,7 @@ export default defineConfig({
84
84
  issuer: "http://auth.notes.localhost:5174",
85
85
  appOrigin: "http://app.notes.localhost:5173",
86
86
  resource: "http://app.notes.localhost:5173/",
87
- backend: "http://127.0.0.1:8080",
88
- socketPaths: ["/eventlog"],
87
+ sockets: { backend: "http://127.0.0.1:8080", paths: ["/eventlog"] },
89
88
  onError: (error) => console.error("[forward-auth]", error.message),
90
89
  }),
91
90
  ],
@@ -96,8 +95,9 @@ Nothing in this package imports Vite, at run time or in its types: the plugin is
96
95
 
97
96
  - The check uses `node:http`, never `fetch`: `fetch` owns `Sec-Fetch-Mode`, and that header is what tells the issuer whether a request may be redirected through sign-in. The browser's own header is relayed, along with its cookie, plus `x-forwarded-proto`, `-host` and `-uri`.
98
97
  - It has a timeout (5 s by default) and **rejects** rather than deciding when the issuer is unreachable, too slow, or answers `204` with no `Authorization` to forward. `middleware` turns a rejection into a 502 and passes the error to `onError`; an empty credential is never forwarded upstream.
98
+ - A refusal is relayed as the issuer wrote it: its status, its `Location`, its body and its content type. A script that is not signed in reads `{"error":"unauthenticated"}` rather than an empty 401.
99
99
  - `publicPaths` defaults to `/mcp`, `/.well-known` and `/healthz`, and a request that already carries an `Authorization` header is never checked: agents onboard themselves and probes run.
100
- - `upgrade` only takes the paths in `socketPaths`, so a development server keeps its own hot-reload socket; it returns `false` for everything else, which on a plain Node server means another listener must answer them. A checked upgrade is proxied to `backend`; a half closing normally ends the other half, and only an error destroys. A socket error is reported through `onError` and never crashes the server.
100
+ - `upgrade` only takes the paths in `sockets.paths`, so a development server keeps its own hot-reload socket; it returns `false` for everything else, which on a plain Node server means another listener must answer them. Omit `sockets` and it takes none. A checked upgrade is proxied to `sockets.backend`; a half closing normally ends the other half, and only an error destroys. A client that gives up while the issuer is deciding is not proxied at all. A socket error is reported through `onError` and never crashes the server.
101
101
  - `reserveLoopbackPort()` claims a free port before anything that must know its own origin up front.
102
102
 
103
103
  The edge's types import `node:http` types, so a TypeScript consumer needs `@types/node`.
@@ -107,4 +107,27 @@ Two optional test hooks help exercise integrations:
107
107
  - `cimdTransport(input, init)` replaces outbound Client ID Metadata Document retrieval and returns a `Response` or `Promise<Response>`. Its arguments match `fetch`. Use it to serve fixture metadata for HTTPS client IDs without an external server. When omitted, the issuer uses its secure metadata transport.
108
108
  - `onRequest({ method, url })` observes actual incoming HTTP requests at the issuer listener, such as discovery, JWKS, dynamic client registration, and token requests. Provisioning is in-process, so the observer sees only the test's own traffic. `url` is a `URL`; headers and bodies are never passed. The callback runs synchronously before handling each request. A thrown error makes that request fail with HTTP 500, so keep observers nonthrowing.
109
109
 
110
+ ## A fake issuer for tests
111
+
112
+ `@gjermundgaraba/clankerauth-dev/testing` is the issuer an application test usually wants: the two endpoints a resource server actually calls, and nothing else. It signs with a real EdDSA key and publishes it as JWKS, so every token still travels the resource server's own verifier — signature, issuer, audience, type, claims, scopes — without starting the whole issuer.
113
+
114
+ ```ts
115
+ import { startFakeIssuer } from "@gjermundgaraba/clankerauth-dev/testing";
116
+
117
+ const auth = await startFakeIssuer({
118
+ resource: "http://127.0.0.1:8080/",
119
+ scopes: ["notes:read", "notes:write"],
120
+ });
121
+
122
+ auth.issuer; // configure the resource server with this
123
+ const token = await auth.sign(); // every claim is overridable: auth.sign({ exp, aud, scope })
124
+ const key = auth.apiKey(["notes:read"]); // and auth.apiKey(scopes, someOtherResource)
125
+ auth.revoke(key); // the next verification is 401, online, as the real issuer behaves
126
+ auth.fail(503); // both endpoints answer this instead; auth.fail() restores them
127
+ auth.verifications(); // how many API-key verifications were served
128
+ await auth.close();
129
+ ```
130
+
131
+ Use it for what a real issuer makes slow or awkward: a token that must expire in two seconds, a key granted on someone else's resource, an outage. Use `startDisposableIssuer` when the protocol itself is what the test is about — sign-in, consent, forward auth, dynamic registration.
132
+
110
133
  MIT licensed. The bundled third-party licenses are listed in `dist/THIRD_PARTY_NOTICES.txt`.
@@ -472,7 +472,7 @@ SOFTWARE.
472
472
 
473
473
  ---
474
474
 
475
- @gjermundgaraba/effect-actions@0.3.0
475
+ @gjermundgaraba/effect-actions@0.4.0
476
476
  LICENSE
477
477
  MIT License
478
478
 
package/dist/edge.d.ts CHANGED
@@ -13,11 +13,14 @@ export interface CheckOptions {
13
13
  /** How long to wait for the issuer. Default 5000 ms. */
14
14
  readonly timeoutMs?: number;
15
15
  }
16
- /** What the issuer decided about one request. */
16
+ /** What the issuer decided about one request, including the refusal it wrote. */
17
17
  export interface Decision {
18
18
  readonly status: number;
19
19
  readonly authorization: string | undefined;
20
20
  readonly location: string | undefined;
21
+ /** The issuer's own response body, relayed verbatim so a refusal reads the same here. */
22
+ readonly body: Buffer;
23
+ readonly contentType: string | undefined;
21
24
  }
22
25
  /** The request fields a check reads. A Node `IncomingMessage` already is one. */
23
26
  export interface CheckedRequest {
@@ -30,19 +33,24 @@ export interface CheckedRequest {
30
33
  * those are a broken edge, not a refusal to show a browser.
31
34
  */
32
35
  export declare const check: (options: CheckOptions) => (request: CheckedRequest) => Promise<Decision>;
36
+ /** The upgrades this edge owns, and where it proxies them once they are checked. */
37
+ export interface SocketOptions {
38
+ /** Where a checked upgrade is proxied, such as `http://127.0.0.1:8080`. */
39
+ readonly backend: string;
40
+ /**
41
+ * Paths whose upgrades this edge owns. Everything else, including a development
42
+ * server's own hot-reload socket, is left untouched.
43
+ */
44
+ readonly paths: readonly string[];
45
+ }
33
46
  export interface EdgeOptions extends CheckOptions {
34
47
  /**
35
48
  * Path prefixes answered without a check, because their callers bring their own
36
49
  * credential or must work without one. Defaults to `/mcp`, `/.well-known`, `/healthz`.
37
50
  */
38
51
  readonly publicPaths?: readonly string[];
39
- /** Where a checked upgrade is proxied, such as `http://127.0.0.1:8080`. */
40
- readonly backend?: string;
41
- /**
42
- * Paths whose upgrades this edge owns. Everything else, including a development
43
- * server's own hot-reload socket, is left untouched. Defaults to none.
44
- */
45
- readonly socketPaths?: readonly string[];
52
+ /** Omit it and every upgrade is left to whoever else listens. */
53
+ readonly sockets?: SocketOptions;
46
54
  /** Called with anything this edge swallowed, so a dev server can print it. */
47
55
  readonly onError?: (error: Error) => void;
48
56
  }
package/dist/edge.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{createServer as e,request as t}from"node:http";const n=[`/mcp`,`/.well-known`,`/healthz`],r=e=>typeof e==`function`,i=e=>{let t=e.search(/[?#]/u);return t===-1?e:e.slice(0,t)},a=e=>e===void 0?``:Array.isArray(e)?e.join(`, `):String(e),o=e=>{let n=new URL(e.appOrigin),o=e.timeoutMs??5e3,s=t=>r(e.resource)?e.resource(t):e.resource;return r=>new Promise((c,l)=>{let u=r.url??`/`,d=new URL(`/forward-auth`,e.issuer);d.searchParams.set(`resource`,s(i(u)));let f=t(d,{headers:{cookie:a(r.headers.cookie),"sec-fetch-mode":a(r.headers[`sec-fetch-mode`]),"x-forwarded-proto":n.protocol.slice(0,-1),"x-forwarded-host":n.host,"x-forwarded-uri":u}},e=>{e.resume();let t=e.statusCode??502,{authorization:n,location:r}=e.headers;if(t===204&&n===void 0){l(/* @__PURE__ */ Error(`Forward auth answered 204 without an Authorization header to forward`));return}c({status:t,authorization:n,location:r})});f.setTimeout(o,()=>{f.destroy(/* @__PURE__ */ Error(`Forward auth did not answer within ${o}ms`))}),f.on(`error`,l),f.end()})},s=(e,t)=>t.some(t=>e===t||e.startsWith(`${t}/`)),c=e=>e instanceof Error?e:Error(String(e)),l=e=>{let t=o(e),r=e.publicPaths??[...n];return(n,a,o)=>{let l=i(n.url??`/`);if(n.headers.authorization!==void 0||s(l,r)){o();return}t(n).then(e=>{if(e.status===204){n.headers.authorization=e.authorization,o();return}a.writeHead(e.status,e.location===void 0?{}:{location:e.location}),a.end()},t=>{let n=c(t);e.onError?.(n),a.writeHead(502,{"content-type":`text/plain`}),a.end(n.message)})}},u=e=>Object.fromEntries(Object.entries(e).flatMap(([e,t])=>t===void 0?[]:[[e,Array.isArray(t)?t.join(`, `):t]])),d=e=>{let n=o(e);return(r,a,o)=>{let l=i(r.url??`/`);if(e.backend===void 0||!s(l,e.socketPaths??[]))return!1;let d=new URL(e.backend),f=(t,n,r)=>{r&&e.onError?.(r),a.end(`HTTP/1.1 ${t} ${n}\r\nConnection: close\r\n\r\n`)};a.on(`error`,t=>{e.onError?.(t),a.destroy()});let p=n=>{let i=t({hostname:d.hostname,port:d.port,path:r.url??`/`,headers:{...u(r.headers),authorization:n}});i.on(`upgrade`,(t,n,r)=>{let i=`HTTP/1.1 101 Switching Protocols\r
2
- `;for(let e=0;e<t.rawHeaders.length;e+=2)i+=`${t.rawHeaders[e]}: ${t.rawHeaders[e+1]}\r\n`;a.write(`${i}\r\n`),r.length&&a.write(r),o.length&&n.write(o),n.on(`error`,t=>{e.onError?.(t),a.destroy()}),a.once(`close`,()=>n.end()),n.once(`close`,()=>a.end()),a.pipe(n),n.pipe(a)}),i.on(`response`,e=>{e.resume(),f(e.statusCode??502,`Upgrade refused`)}),i.on(`error`,e=>f(502,`Bad Gateway`,e)),i.end()};return n(r).then(e=>{if(e.status!==204||e.authorization===void 0){f(401,`Unauthorized`);return}p(e.authorization)},e=>f(502,`Bad Gateway`,c(e))),!0}},f=(e,t)=>{let n=l(t),r=d(t);return e.on(`upgrade`,(e,t,n)=>{r(e,t,n)}),n},p=e=>{let t=l(e),n=d(e);return{name:`clankerauth-forward-auth`,apply:`serve`,configureServer:e=>{e.middlewares.use(t),e.httpServer?.on(`upgrade`,(e,t,r)=>{n(e,t,r)})}}},m=async()=>{let t=e();await new Promise(e=>t.listen(0,`127.0.0.1`,e));let n=t.address();if(!(n instanceof Object))throw Error(`Could not reserve a loopback port`);return await new Promise((e,n)=>t.close(t=>t?n(t):e())),n.port};export{f as attach,o as check,p as forwardAuth,l as middleware,m as reserveLoopbackPort,d as upgrade};
1
+ import{createServer as e,request as t}from"node:http";const n=[`/mcp`,`/.well-known`,`/healthz`],r=e=>typeof e==`function`,i=e=>{let t=e.search(/[?#]/u);return t===-1?e:e.slice(0,t)},a=e=>e===void 0?``:Array.isArray(e)?e.join(`, `):String(e),o=e=>{let n=new URL(e.appOrigin),o=e.timeoutMs??5e3,s=t=>r(e.resource)?e.resource(t):e.resource;return r=>new Promise((c,l)=>{let u=r.url??`/`,d=new URL(`/forward-auth`,e.issuer);d.searchParams.set(`resource`,s(i(u)));let f=t(d,{headers:{cookie:a(r.headers.cookie),"sec-fetch-mode":a(r.headers[`sec-fetch-mode`]),"x-forwarded-proto":n.protocol.slice(0,-1),"x-forwarded-host":n.host,"x-forwarded-uri":u}},e=>{let t=e.statusCode??502,{authorization:n,location:r}=e.headers;if(t===204&&n===void 0){e.resume(),l(/* @__PURE__ */ Error(`Forward auth answered 204 without an Authorization header to forward`));return}let i=[];e.on(`data`,e=>i.push(e)),e.on(`error`,l),e.on(`end`,()=>c({status:t,authorization:n,location:r,body:Buffer.concat(i),contentType:e.headers[`content-type`]}))});f.setTimeout(o,()=>{f.destroy(/* @__PURE__ */ Error(`Forward auth did not answer within ${o}ms`))}),f.on(`error`,l),f.end()})},s=(e,t)=>t.some(t=>e===t||e.startsWith(`${t}/`)),c=e=>e instanceof Error?e:Error(String(e)),l=e=>{let t=o(e),r=e.publicPaths??[...n];return(n,a,o)=>{let l=i(n.url??`/`);if(n.headers.authorization!==void 0||s(l,r)){o();return}t(n).then(e=>{if(e.status===204){n.headers.authorization=e.authorization,o();return}let t={};e.location!==void 0&&(t.location=e.location),e.contentType!==void 0&&(t[`content-type`]=e.contentType),a.writeHead(e.status,t),a.end(e.body)},t=>{let n=c(t);e.onError?.(n),a.writeHead(502,{"content-type":`text/plain`}),a.end(n.message)})}},u=e=>Object.fromEntries(Object.entries(e).flatMap(([e,t])=>t===void 0?[]:[[e,Array.isArray(t)?t.join(`, `):t]])),d=e=>{let n=o(e);return(r,a,o)=>{let l=i(r.url??`/`),d=e.sockets;if(d===void 0||!s(l,d.paths))return!1;let f=new URL(d.backend),p=(t,n,r)=>{r&&e.onError?.(r),a.end(`HTTP/1.1 ${t} ${n}\r\nConnection: close\r\n\r\n`)};a.on(`error`,t=>{e.onError?.(t),a.destroy()});let m=n=>{let i=t({hostname:f.hostname,port:f.port,path:r.url??`/`,headers:{...u(r.headers),authorization:n}});i.on(`upgrade`,(t,n,r)=>{let i=`HTTP/1.1 101 Switching Protocols\r
2
+ `;for(let e=0;e<t.rawHeaders.length;e+=2)i+=`${t.rawHeaders[e]}: ${t.rawHeaders[e+1]}\r\n`;a.write(`${i}\r\n`),r.length&&a.write(r),o.length&&n.write(o),n.on(`error`,t=>{e.onError?.(t),a.destroy()}),a.once(`close`,()=>n.end()),n.once(`close`,()=>a.end()),a.pipe(n),n.pipe(a)}),i.on(`response`,e=>{e.resume(),p(e.statusCode??502,`Upgrade refused`)}),i.on(`error`,e=>p(502,`Bad Gateway`,e)),i.end()};return n(r).then(e=>{if(!a.destroyed){if(e.status!==204||e.authorization===void 0){p(401,`Unauthorized`);return}m(e.authorization)}},e=>{a.destroyed||p(502,`Bad Gateway`,c(e))}),!0}},f=(e,t)=>{let n=l(t),r=d(t);return e.on(`upgrade`,(e,t,n)=>{r(e,t,n)}),n},p=e=>{let t=l(e),n=d(e);return{name:`clankerauth-forward-auth`,apply:`serve`,configureServer:e=>{e.middlewares.use(t),e.httpServer?.on(`upgrade`,(e,t,r)=>{n(e,t,r)})}}},m=async()=>{let t=e();await new Promise(e=>t.listen(0,`127.0.0.1`,e));let n=t.address();if(!(n instanceof Object))throw Error(`Could not reserve a loopback port`);return await new Promise((e,n)=>t.close(t=>t?n(t):e())),n.port};export{f as attach,o as check,p as forwardAuth,l as middleware,m as reserveLoopbackPort,d as upgrade};
@@ -0,0 +1 @@
1
+ const e=new TextEncoder,t=new TextDecoder,n=new TextDecoder(`utf-8`,{fatal:!0}),r=2**32;function i(...e){let t=e.reduce((e,{length:t})=>e+t,0),n=new Uint8Array(t),r=0;for(let t of e)n.set(t,r),r+=t.length;return n}function a(e,t,n){if(t<0||t>=r)throw RangeError(`value must be >= 0 and <= ${r-1}. Received ${t}`);e.set([t>>>24,t>>>16,t>>>8,t&255],n)}function o(e){let t=Math.floor(e/r),n=e%r,i=/* @__PURE__ */ new Uint8Array(8);return a(i,t,0),a(i,n,4),i}function s(e){let t=/* @__PURE__ */ new Uint8Array(4);return a(t,e),t}const c=/[^\x00-\x7f]/;function l(t){if(typeof t==`string`&&t.length>=128){if(c.test(t))throw TypeError(`non-ASCII string encountered in encode()`);return e.encode(t)}let n=new Uint8Array(t.length);for(let e=0;e<t.length;e++){let r=t.charCodeAt(e);if(r>127)throw TypeError(`non-ASCII string encountered in encode()`);n[e]=r}return n}function u(e,t=!1){if(Uint8Array.prototype.toBase64)return e.toBase64({alphabet:t?`base64url`:`base64`,omitPadding:t});let n=32768,r=[];for(let t=0;t<e.length;t+=n)r.push(String.fromCharCode.apply(null,e.subarray(t,t+n)));let i=btoa(r.join(``));return t?i.replace(/=/g,``).replace(/\+/g,`-`).replace(/\//g,`_`):i}function d(e,t=!1){if(Uint8Array.fromBase64)return Uint8Array.fromBase64(e,{alphabet:t?`base64url`:`base64`});if(t){if(e.includes(`+`)||e.includes(`/`))throw TypeError(`Invalid base64url`);e=e.replace(/-/g,`+`).replace(/_/g,`/`)}let n=atob(e),r=new Uint8Array(n.length);for(let e=0;e<n.length;e++)r[e]=n.charCodeAt(e);return r}async function f(e,t){let n=`SHA-${e.slice(-3)}`;return new Uint8Array(await crypto.subtle.digest(n,t))}var p=class extends Error{static code=`ERR_JOSE_GENERIC`;code=`ERR_JOSE_GENERIC`;constructor(e,t){super(e,t),this.name=this.constructor.name,Error.captureStackTrace?.(this,this.constructor)}},m=class extends p{static code=`ERR_JWT_CLAIM_VALIDATION_FAILED`;code=`ERR_JWT_CLAIM_VALIDATION_FAILED`;claim;reason;payload;constructor(e,t,n=`unspecified`,r=`unspecified`){super(e,{cause:{claim:n,reason:r,payload:t}}),this.claim=n,this.reason=r,this.payload=t}},h=class extends p{static code=`ERR_JWT_EXPIRED`;code=`ERR_JWT_EXPIRED`;claim;reason;payload;constructor(e,t,n=`unspecified`,r=`unspecified`){super(e,{cause:{claim:n,reason:r,payload:t}}),this.claim=n,this.reason=r,this.payload=t}},g=class extends p{static code=`ERR_JOSE_ALG_NOT_ALLOWED`;code=`ERR_JOSE_ALG_NOT_ALLOWED`},_=class extends p{static code=`ERR_JOSE_NOT_SUPPORTED`;code=`ERR_JOSE_NOT_SUPPORTED`},v=class extends p{static code=`ERR_JWE_DECRYPTION_FAILED`;code=`ERR_JWE_DECRYPTION_FAILED`;constructor(e=`decryption operation failed`,t){super(e,t)}},y=class extends p{static code=`ERR_JWE_INVALID`;code=`ERR_JWE_INVALID`},b=class extends p{static code=`ERR_JWS_INVALID`;code=`ERR_JWS_INVALID`},x=class extends p{static code=`ERR_JWT_INVALID`;code=`ERR_JWT_INVALID`},ee=class extends p{static code=`ERR_JWK_INVALID`;code=`ERR_JWK_INVALID`},te=class extends p{static code=`ERR_JWKS_INVALID`;code=`ERR_JWKS_INVALID`},ne=class extends p{static code=`ERR_JWKS_NO_MATCHING_KEY`;code=`ERR_JWKS_NO_MATCHING_KEY`;constructor(e=`no applicable key found in the JSON Web Key Set`,t){super(e,t)}},re=class extends p{[Symbol.asyncIterator]=async function*(){};static code=`ERR_JWKS_MULTIPLE_MATCHING_KEYS`;code=`ERR_JWKS_MULTIPLE_MATCHING_KEYS`;constructor(e=`multiple matching keys found in the JSON Web Key Set`,t){super(e,t)}},ie=class extends p{static code=`ERR_JWKS_TIMEOUT`;code=`ERR_JWKS_TIMEOUT`;constructor(e=`request timed out`,t){super(e,t)}},ae=class extends p{static code=`ERR_JWS_SIGNATURE_VERIFICATION_FAILED`;code=`ERR_JWS_SIGNATURE_VERIFICATION_FAILED`;constructor(e=`signature verification failed`,t){super(e,t)}};function S(e){try{return d(typeof e==`string`?e:t.decode(e),!0)}catch(e){throw TypeError(`The input to be decoded is not correctly encoded.`,{cause:e})}}function C(t){return u(typeof t==`string`?e.encode(t):t,!0)}function oe(e,t){if(!(e instanceof Uint8Array))throw TypeError(`${t} must be an instance of Uint8Array`)}function w(e){if(typeof e!=`object`||!e||Object.prototype.toString.call(e)!==`[object Object]`)return!1;let t=Object.getPrototypeOf(e);return t===null||Object.getPrototypeOf(t)===null}function se(e){return w(e)&&Array.isArray(e.keys)&&Array.from(e.keys).every(w)}function ce(...e){let t=/* @__PURE__ */ new Set;for(let n of e)if(n)for(let e of Object.keys(n)){if(t.has(e))return!1;t.add(e)}return!0}function le(e,t){if(e!==void 0)throw TypeError(`${t} can only be called once`)}function ue(e,t,n){try{return S(e)}catch{throw new n(`Failed to base64url decode the ${t}`)}}function de(e,t,n){try{return l(e)}catch{throw new n(`The ${t} is not a valid base64url string`)}}function fe(e,t,r){let i;try{i=JSON.parse(n.decode(S(e)))}catch{throw new t(r)}if(!w(i))throw new t(r);return i}const pe={__proto__:null,b64:!0},me={__proto__:null};function he(e,t){if(t!==void 0&&(!Array.isArray(t)||t.some(e=>typeof e!=`string`)))throw TypeError(`"${e}" option must be an array of strings`);return t===void 0?void 0:new Set(t)}function ge(e,t){let{crit:n}=t??{};if(Array.isArray(n)&&new Set(n).size!==n.length)throw new e(`"crit" (Critical) Header Parameter MUST NOT contain duplicate values`)}function _e(e,t,n,r,i){if(i.crit!==void 0&&r?.crit===void 0)throw new e(`"crit" (Critical) Header Parameter MUST be integrity protected`);if(!r||r.crit===void 0)return[];if(!Array.isArray(r.crit)||r.crit.length===0||r.crit.some(e=>typeof e!=`string`||e.length===0))throw new e(`"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present`);let a=n===void 0?t:{__proto__:null,...n,...t};for(let t of r.crit){if(!(t in a))throw new _(`Extension Header Parameter "${t}" is not recognized`);if(!Object.hasOwn(i,t)||i[t]===void 0)throw new e(`Extension Header Parameter "${t}" is missing`);if(a[t]&&(!Object.hasOwn(r,t)||r[t]===void 0))throw new e(`Extension Header Parameter "${t}" MUST be integrity protected`)}return r.crit}function ve(e,t){if(t.includes(`b64`)){let t=e.b64;if(typeof t!=`boolean`)throw new b(`The "b64" (base64url-encode payload) Header Parameter must be a boolean`);return t}return!0}function T(e,t){let n,r;try{n=JSON.stringify(t),r=JSON.parse(n)}catch(t){throw new e(`JOSE Header is not valid JSON`,{cause:t})}if(!w(r))throw new e(`JOSE Header is not a JSON object`);return[r,n]}const ye=e=>e[Symbol.toStringTag],be=(e,t,n)=>{let{alg:r}=e;if(t.use!==void 0){let e=n===`sign`||n===`verify`?`sig`:`enc`;if(t.use!==e)throw TypeError(`Invalid key for this operation, its "use" must be "${e}" when present`)}if(t.alg!==void 0&&t.alg!==r)throw TypeError(`Invalid key for this operation, its "alg" must be "${r}" when present`);if(Array.isArray(t.key_ops)){let r=n===`encrypt`||n===`decrypt`?e.ops?.[n===`encrypt`?0:1]:n;if(r&&!t.key_ops.includes(r))throw TypeError(`Invalid key for this operation, its "key_ops" must include "${r}" when present`)}};async function xe(e,t,n){let{alg:r,secret:i}=e,a=n===`decrypt`||n===`sign`;if(i&&t instanceof Uint8Array)return t;let o,s;if(w(t)){if(o=Ne(t),typeof o.kty!=`string`)throw Oe(r,t,i);if(!(i?o.kty===`oct`&&typeof o.k==`string`:o.kty!==`oct`&&(a?o.kty===`AKP`&&typeof o.priv==`string`||typeof o.d==`string`:o.d===void 0&&o.priv===void 0)))throw TypeError(i?`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`:`JSON Web Key for this operation must be a ${a?`private`:`public`} JWK`);if(be(e,o,n),o.kty===`oct`)return S(o.k);if(!Object.isFrozen(t)){let{key_ops:e}=t;Array.isArray(e)&&Object.freeze(e),Object.freeze(t)}}else{if(!Te(t))throw Oe(r,t,i);let e=i?`secret`:a?`private`:`public`;if(t.type!==e&&(i||[`secret`,`public`,`private`].includes(t.type)))throw TypeError(`${ye(t)} instances must be of type "${e}" for the ${r} algorithm`);if(D(t))return t;if(s=t,s.type===`secret`)return s.export()}E||=/* @__PURE__ */ new WeakMap;let c=t,l=E.get(c);if(l?.[r])return l[r];if(l||E.set(c,l={}),s&&typeof s.toCryptoKey==`function`){let t=s.type===`public`,n=Se[s.asymmetricKeyDetails?.namedCurve],i=e.resolve?.({crv:n,asymmetricKeyType:s.asymmetricKeyType})??e.subtle;return l[r]=s.toCryptoKey(i,t,e.usages[+!t])}return o??=s.export({format:`jwk`}),o.alg=r,l[r]=await Fe(e,o)}let E;const Se={__proto__:null,prime256v1:`P-256`,secp384r1:`P-384`,secp521r1:`P-521`};function Ce(e){if(!D(e))throw Error(`CryptoKey instance expected`)}const D=e=>{if(e?.[Symbol.toStringTag]===`CryptoKey`)return!0;try{return e instanceof CryptoKey}catch{return!1}},we=e=>e?.[Symbol.toStringTag]===`KeyObject`,Te=e=>D(e)||we(e);function Ee(e,t,...n){if(n.length>2){let t=n.pop();e+=`one of type ${n.join(`, `)}, or ${t}.`}else n.length===2?e+=`one of type ${n[0]} or ${n[1]}.`:e+=`of type ${n[0]}.`;return t==null?e+=` Received ${t}`:typeof t==`function`&&t.name?e+=` Received function ${t.name}`:typeof t==`object`&&t&&t.constructor?.name&&(e+=` Received an instance of ${t.constructor.name}`),e}const De=(e,...t)=>Ee(`Key must be `,e,...t);function Oe(e,t,n){let r=[`CryptoKey`,`KeyObject`,`JSON Web Key`];return n&&r.push(`Uint8Array`),TypeError(Ee(`Key for the ${e} algorithm must be `,t,...r))}const O=(e,t=`algorithm.name`)=>/* @__PURE__ */ TypeError(`CryptoKey does not support this operation, its ${t} must be ${e}`);function ke(e,t){if(t&&!e.usages.includes(t))throw TypeError(`CryptoKey does not support this operation, its usages must include ${t}.`)}function Ae(e,t){let{modulusLength:n}=t.algorithm;if(typeof n!=`number`||n<2048)throw TypeError(`${e} requires key modulusLength to be 2048 bits or larger`)}function je(e,t,n){let r=e.algorithm;if(r.name!==t.name)throw O(t.name);if(t.hash&&r.hash?.name!==t.hash)throw O(t.hash,`algorithm.hash`);if(t.namedCurve&&r.namedCurve!==t.namedCurve)throw O(t.namedCurve,`algorithm.namedCurve`);if(t.length!==void 0&&r.length!==t.length)throw O(t.length,`algorithm.length`);ke(e,n)}function Me(e){return{__proto__:null,...e}}function Ne(e){let t=Me(e);if(t.ext!==void 0&&typeof t.ext!=`boolean`)throw TypeError(`"ext" (Extractable) Parameter must be a boolean`);if(t.key_ops!==void 0){let e=t.key_ops,n=Array.isArray(e)?[...e]:void 0;if(!n||n.some(e=>typeof e!=`string`)||new Set(n).size!==n.length)throw TypeError(`"key_ops" (Key Operations) Parameter must be an array of unique strings`);t.key_ops=n}return t}function Pe(e){if(e!==void 0&&typeof e!=`boolean`)throw TypeError(`"extractable" option must be a boolean`);return e}async function Fe(e,t,n){if(!e.kty.includes(t.kty))throw new _(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value`);let r=e.resolve?.({kty:t.kty,crv:t.crv})??e.subtle,i=!!(t.d||t.priv),a={...t,ext:n??t.ext};return a.kty!==`AKP`&&delete a.alg,delete a.use,crypto.subtle.importKey(`jwk`,a,r,a.ext??!i,t.key_ops??e.usages[+!!i])}async function Ie(e,t,n,r=!1){return e instanceof Uint8Array&&(e=await crypto.subtle.importKey(`raw`,e,t,r,[n])),je(e,t,n),e}function k(e){let t={__proto__:null};for(let n in e)t[n]={...e[n],alg:n};return t}const Le=[[`encrypt`,`wrapKey`],[`decrypt`,`unwrapKey`]],Re=[[],[`deriveBits`]],A=[[],[]];function j(e){return{kty:[`RSA`],mode:`key-encryption`,subtle:{name:`RSA-OAEP`,hash:`SHA-${e}`},usages:Le,ops:[`wrapKey`,`unwrapKey`]}}function M(e){return{kty:[`EC`,`OKP`],mode:e,subtle:{name:`ECDH`},resolve:({kty:e,crv:t,asymmetricKeyType:n})=>{if(t===`X25519`||n===`x25519`)return{name:`X25519`};if(e===`OKP`)throw new _(`Invalid or unsupported JWK "alg" (Algorithm) Parameter value`);return{name:`ECDH`,namedCurve:t}},usages:Re,ops:[void 0,`deriveBits`]}}function N(e,t=!1){return{kty:[`oct`],mode:`key-wrapping`,secret:!0,subtle:{name:t?`AES-GCM`:`AES-KW`,length:e},usages:A,ops:t?[`encrypt`,`decrypt`]:[`wrapKey`,`unwrapKey`]}}function P(){return{kty:[`oct`],mode:`key-wrapping`,secret:!0,subtle:{name:`PBKDF2`},usages:A,ops:[`deriveBits`,`deriveBits`]}}const F=k({dir:{kty:[`oct`],mode:`direct-encryption`,secret:!0,subtle:{name:`AES-GCM`},usages:A,ops:[`encrypt`,`decrypt`]},"RSA-OAEP":j(1),"RSA-OAEP-256":j(256),"RSA-OAEP-384":j(384),"RSA-OAEP-512":j(512),"ECDH-ES":M(`direct-key-agreement`),"ECDH-ES+A128KW":M(`key-agreement-with-key-wrapping`),"ECDH-ES+A192KW":M(`key-agreement-with-key-wrapping`),"ECDH-ES+A256KW":M(`key-agreement-with-key-wrapping`),A128KW:N(128),A192KW:N(192),A256KW:N(256),A128GCMKW:N(128,!0),A192GCMKW:N(192,!0),A256GCMKW:N(256,!0),"PBES2-HS256+A128KW":P(),"PBES2-HS384+A192KW":P(),"PBES2-HS512+A256KW":P()}),ze=[`encrypt`,`decrypt`];function I(e,t=!1){return{kty:[`oct`],secret:!0,subtle:{name:t?`AES-CBC`:`AES-GCM`,length:e},usages:A,ops:ze,cekBits:e,ivBits:t?128:96,cbc:t}}const Be=k({A128GCM:I(128),A192GCM:I(192),A256GCM:I(256),"A128CBC-HS256":I(256,!0),"A192CBC-HS384":I(384,!0),"A256CBC-HS512":I(512,!0)});function Ve(e,t){throw new _(`Invalid or unsupported "${e}" (JWE ${t}) header value`)}function He(e){return(typeof e==`string`?F[e]:void 0)??Ve(`alg`,`Algorithm`)}function Ue(e){return e.mode===`key-wrapping`||e.mode===`key-encryption`||e.mode===`key-agreement-with-key-wrapping`}function We(e){return(typeof e==`string`?Be[e]:void 0)??Ve(`enc`,`Encryption Algorithm`)}const L=[[`verify`],[`sign`]];function R(e){let t={name:`HMAC`,hash:`SHA-${e}`};return{kty:[`oct`],secret:!0,subtle:t,signing:t,usages:L}}function z(e,t){let n={name:t?`RSA-PSS`:`RSASSA-PKCS1-v1_5`,hash:`SHA-${e}`};return{kty:[`RSA`],subtle:n,signing:t?{...n,saltLength:t}:n,usages:L,minRsaBits:2048}}function B(e,t){return{kty:[`EC`],crv:e,subtle:{name:`ECDSA`,namedCurve:e},signing:{name:`ECDSA`,hash:`SHA-${t}`},usages:L}}function Ge(){let e={name:`Ed25519`};return{kty:[`OKP`],crv:`Ed25519`,subtle:e,signing:e,usages:L}}function V(e){let t={name:`ML-DSA-${e}`};return{kty:[`AKP`],subtle:t,signing:t,usages:L}}const H=k({HS256:R(256),HS384:R(384),HS512:R(512),RS256:z(256),RS384:z(384),RS512:z(512),PS256:z(256,32),PS384:z(384,48),PS512:z(512,64),ES256:B(`P-256`,256),ES384:B(`P-384`,384),ES512:B(`P-521`,512),EdDSA:Ge(),Ed25519:Ge(),"ML-DSA-44":V(44),"ML-DSA-65":V(65),"ML-DSA-87":V(87)});function Ke(e){let t=typeof e==`string`?H[e]:void 0;if(!t)throw new _(`alg ${e} is not supported either by JOSE or your javascript runtime`);return t}const U=e=>Math.floor(e.getTime()/1e3),qe={s:1,m:60,h:3600,d:86400,w:604800,y:31557600},Je=/^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i,W=`check_failed`;function G(){throw TypeError(`Invalid time period format`)}function K(e){typeof e!=`string`&&G();let t=Je.exec(e);(!t||t[4]&&t[1])&&G();let n=parseFloat(t[2]),r=Math.round(n*qe[t[3][0].toLowerCase()]);return Number.isFinite(r)||G(),t[1]===`-`||t[4]===`ago`?-r:r}function q(e,t){if(!Number.isFinite(t))throw TypeError(`Invalid ${e} input`);return t}function J(e,t){if(typeof t!=`string`)throw TypeError(`"${e}" claim must be a string`)}function Ye(e){if(typeof e!=`string`&&(!Array.isArray(e)||Array.from(e).some(e=>typeof e!=`string`)))throw TypeError(`"aud" claim must be a string or an array of strings`)}function Y(e,t){return typeof e==`number`?q(t,e):e instanceof Date?q(t,U(e)):U(/* @__PURE__ */ new Date)+K(e)}const Xe=e=>{let t=e.toLowerCase();return e.includes(`/`)?t:`application/${t}`},Ze=(e,t)=>typeof e==`string`?t.includes(e):Array.isArray(e)?t.some(t=>e.includes(t)):!1;function X(e,t,n=!1){let r=e[t];if(r!==void 0||n){if(typeof r!=`number`)throw new m(`"${t}" claim must be a number`,e,t,`invalid`);return r}}function Z(e,t){throw new m(`unexpected "${t}" claim value`,e,t,W)}function Qe(e,t,r={}){let i;try{i=JSON.parse(n.decode(t))}catch{}if(!w(i))throw new x(`JWT Claims Set must be a top-level JSON object`);let{typ:a}=r;if(a!==void 0&&(typeof e.typ!=`string`||Xe(e.typ)!==Xe(a)))throw new m(`unexpected "typ" JWT header value`,i,`typ`,W);let{requiredClaims:o=[],issuer:s,subject:c,audience:l,maxTokenAge:u}=r,d=[...o];u!==void 0&&d.push(`iat`),l!==void 0&&d.push(`aud`),c!==void 0&&d.push(`sub`),s!==void 0&&d.push(`iss`);for(let e of new Set(d.reverse()))if(!Object.hasOwn(i,e))throw new m(`missing required "${e}" claim`,i,e,`missing`);s!==void 0&&!(Array.isArray(s)?s:[s]).includes(i.iss)&&Z(i,`iss`),c!==void 0&&i.sub!==c&&Z(i,`sub`),l!==void 0&&!Ze(i.aud,typeof l==`string`?[l]:l)&&Z(i,`aud`);let{clockTolerance:f}=r,p=0;if(typeof f==`string`)p=K(f);else if(f!==void 0){if(typeof f!=`number`)throw TypeError(`Invalid clockTolerance option type`);p=f}q(`clockTolerance option`,p);let{currentDate:g}=r,_=q(`currentDate option`,U(g===void 0?/* @__PURE__ */ new Date:g)),v=X(i,`iat`,u!==void 0),y=X(i,`nbf`);if(y!==void 0&&y>_+p)throw new m(`"nbf" claim timestamp check failed`,i,`nbf`,W);let b=X(i,`exp`);if(b!==void 0&&b<=_-p)throw new h(`"exp" claim timestamp check failed`,i,`exp`,W);if(u!==void 0){let e=_-v,t=q(`maxTokenAge option`,typeof u==`number`?u:K(u));if(e-p>t)throw new h(`"iat" claim timestamp check failed (too far in the past)`,i,`iat`,W);if(e<-p)throw new m(`"iat" claim timestamp check failed (it should be in the past)`,i,`iat`,W)}return i}let Q;function $(e){return Q.get(e)}function $e(t){let n=$(t);for(let e of[`iat`,`nbf`,`exp`]){let t=n[e];if(typeof t==`number`&&!Number.isFinite(t))throw TypeError(`"${e}" claim must be a finite number`)}return e.encode(JSON.stringify(n))}function et(e,t){return $(e)[t]}var tt=class{constructor(e={}){if(!w(e))throw TypeError(`JWT Claims Set MUST be an object`);(Q||=/* @__PURE__ */ new WeakMap).set(this,structuredClone(e))}setIssuer(e){return J(`iss`,e),$(this).iss=e,this}setSubject(e){return J(`sub`,e),$(this).sub=e,this}setAudience(e){return Ye(e),$(this).aud=e,this}setJti(e){return J(`jti`,e),$(this).jti=e,this}setNotBefore(e){return $(this).nbf=Y(e,`setNotBefore`),this}setExpirationTime(e){return $(this).exp=Y(e,`setExpirationTime`),this}setIssuedAt(e){let t=$(this);return t.iat=e===void 0?U(/* @__PURE__ */ new Date):typeof e==`string`?q(`setIssuedAt`,U(/* @__PURE__ */ new Date)+K(e)):Y(e,`setIssuedAt`),this}};async function nt(t,n,r){let[a,o,s,c]=t,u=``;if(o!==void 0){let e=T(b,o);o=e[0],u=C(e[1])}if(s!==void 0&&(s=T(b,s)[0]),!o&&!s)throw new b(`either setProtectedHeader or setUnprotectedHeader must be called before #sign()`);if(!ce(o,s))throw new b(`JWS Protected and JWS Unprotected Header Parameter names must be disjoint`);let d={...o,...s};ge(b,o);let f=ve(o,_e(b,pe,c,o,d));f||r?.();let{alg:p}=d;if(typeof p!=`string`||!p)throw new b(`JWS "alg" (Algorithm) Header Parameter missing or invalid`);let m=Ke(p),h=``,g=a,_;if(f){let n=t[4];n?(h=n[0]??=C(a),g=n[1]??=l(h)):(h=C(a),_=e.encode(`${u}.${h}`))}_??=i(l(u),l(`.`),g);let v=await Ie(await xe(m,n,`sign`),m.subtle,`sign`);m.minRsaBits&&Ae(m.alg,v);let y={signature:C(new Uint8Array(await crypto.subtle.sign(m.signing,v,_))),payload:h};return o&&(y.protected=u),s&&(y.header=s),[y,f]}async function rt(e,t,n,r,i){let[a]=await nt([e,t,void 0,n],r,i);return`${a.protected}.${a.payload}.${a.signature}`}const it=tt;var at=class extends it{#e;setProtectedHeader(e){return le(this.#e,`setProtectedHeader`),this.#e=e,this}async sign(e,t){return rt($e(this),this.#e,t?.crit,e,()=>{throw new x(`JWTs MUST NOT use unencoded payload`)})}};function ot(e=`JWK "alg" (Algorithm) Parameter`){throw new _(`Invalid or unsupported ${e} value`)}function st(e,t){return(typeof e==`string`?H[e]??F[e]:void 0)??ot(t)}async function ct(e){if(we(e)){if(e.type===`secret`)e=e.export();else return e.export({format:`jwk`})}if(e instanceof Uint8Array)return{kty:`oct`,k:C(e)};if(!D(e))throw TypeError(De(e,`CryptoKey`,`KeyObject`,`Uint8Array`));if(!e.extractable)throw TypeError(`non-extractable CryptoKey cannot be exported as a JWK`);let t=await crypto.subtle.exportKey(`jwk`,e);delete t.ext,delete t.key_ops,delete t.use,t.kty!==`AKP`&&delete t.alg;for(let e of Object.keys(t))t[e]===void 0&&delete t[e];return t}function lt(e){let t=e?.modulusLength??2048;if(typeof t!=`number`||!Number.isInteger(t)||t<2048)throw new _(`Invalid or unsupported modulusLength option provided, 2048 bits or larger keys must be used`);return t}async function ut(e,t){let n=Pe(t?.extractable),r=st(e,`"alg" (Algorithm)`);r.secret&&ot(`"alg" (Algorithm)`);let i;if(r.resolve){let e=t?.crv??`P-256`;if(![`P-256`,`P-384`,`P-521`,`X25519`].includes(e))throw new _(`Invalid or unsupported crv option provided, supported values are P-256, P-384, P-521, and X25519`);i=r.resolve({crv:e})}else{if(r.crv!==void 0&&t?.crv!==void 0&&t.crv!==r.crv)throw new _(`Invalid or unsupported crv option provided, the only supported value for ${e} is ${r.crv}`);i=r.kty[0]===`RSA`?{...r.subtle,publicExponent:Uint8Array.of(1,0,1),modulusLength:lt(t)}:r.subtle}return crypto.subtle.generateKey(i,n??!1,[...r.usages[1],...r.usages[0]])}export{ne as $,le as A,ve as B,Ne as C,Pe as D,Me as E,se as F,g as G,ge as H,w as I,v as J,p as K,fe as L,ue as M,de as N,me as O,ce as P,re as Q,T as R,Fe as S,Ie as T,S as U,_e as V,C as W,ee as X,y as Y,te as Z,Ae as _,tt as a,x as at,D as b,Qe as c,f as ct,F as d,s as dt,ie as et,Ue as f,o as ft,je as g,Ce as h,at as i,h as it,oe as j,pe as k,H as l,l as lt,We as m,ct as n,ae as nt,et as o,i as ot,He as p,_ as q,st as r,m as rt,$e as s,t as st,ut as t,b as tt,Ke as u,n as ut,ke as v,xe as w,Te as x,De as y,he as z};