@fluixi/oauth2 1.0.0-alpha.1 → 1.0.0-alpha.10

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.
Files changed (45) hide show
  1. package/dist/{browser-ONMHX3Z3.mjs → browser-36FHB6KG.mjs} +2 -2
  2. package/dist/browser.cjs +4 -2
  3. package/dist/browser.mjs +4 -2
  4. package/dist/callback.cjs +6 -5
  5. package/dist/callback.mjs +1 -0
  6. package/dist/{chunk-4NSOGPLM.mjs → chunk-F52RUVDM.mjs} +1 -1
  7. package/dist/{chunk-25WE6UWI.mjs → chunk-OGS6MQ3D.mjs} +1 -1
  8. package/dist/{dpop-LVPWWADA.mjs → dpop-GOWCCCFR.mjs} +26 -6
  9. package/dist/{dpop-NS7NKOWM.mjs → dpop-YPGCGL7S.mjs} +22 -2
  10. package/dist/dpop-store.cjs +4 -2
  11. package/dist/dpop-store.mjs +4 -2
  12. package/dist/dpop.cjs +22 -2
  13. package/dist/dpop.d.ts +18 -1
  14. package/dist/dpop.d.ts.map +1 -1
  15. package/dist/dpop.js +23 -2
  16. package/dist/dpop.mjs +22 -2
  17. package/dist/index.cjs +28 -3
  18. package/dist/index.d.ts +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +1 -0
  21. package/dist/index.mjs +31 -6
  22. package/dist/module.cjs +44 -0
  23. package/dist/module.d.ts +13 -0
  24. package/dist/module.d.ts.map +1 -0
  25. package/dist/module.js +22 -0
  26. package/dist/module.mjs +23 -0
  27. package/dist/server.cjs +138 -25
  28. package/dist/server.d.ts +20 -0
  29. package/dist/server.d.ts.map +1 -1
  30. package/dist/server.js +79 -17
  31. package/dist/server.mjs +140 -27
  32. package/dist/service-client.cjs +1 -1
  33. package/dist/service-client.mjs +3 -3
  34. package/dist/service.cjs +12 -2
  35. package/dist/service.d.ts +2 -18
  36. package/dist/service.d.ts.map +1 -1
  37. package/dist/service.js +11 -0
  38. package/dist/service.mjs +12 -2
  39. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  40. package/dist/types.d.ts +4 -2
  41. package/dist/types.d.ts.map +1 -1
  42. package/dist/types.js +0 -12
  43. package/dist/verify.cjs +24 -3
  44. package/dist/verify.mjs +6 -6
  45. package/package.json +15 -15
@@ -1,7 +1,7 @@
1
- /*! @fluixi/oauth2 v1.0.0-alpha.1 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/oauth2 v1.0.0-alpha.10 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  __export
4
- } from "./chunk-25WE6UWI.mjs";
4
+ } from "./chunk-OGS6MQ3D.mjs";
5
5
 
6
6
  // ../../node_modules/.pnpm/jose@5.10.0/node_modules/jose/dist/browser/runtime/webcrypto.js
7
7
  var webcrypto_default = crypto;
package/dist/browser.cjs CHANGED
@@ -165,9 +165,11 @@ async function loadJose2() {
165
165
  );
166
166
  }
167
167
  }
168
- async function createDpopKey(alg = "ES256") {
168
+ async function createDpopKey(alg = "ES256", options = {}) {
169
169
  const jose = await loadJose2();
170
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
170
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
171
+ extractable: options.extractable ?? false
172
+ });
171
173
  const publicJwk = { ...await jose.exportJWK(publicKey) };
172
174
  return {
173
175
  privateKey,
package/dist/browser.mjs CHANGED
@@ -131,9 +131,11 @@ async function loadJose2() {
131
131
  );
132
132
  }
133
133
  }
134
- async function createDpopKey(alg = "ES256") {
134
+ async function createDpopKey(alg = "ES256", options = {}) {
135
135
  const jose = await loadJose2();
136
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
136
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
137
+ extractable: options.extractable ?? false
138
+ });
137
139
  const publicJwk = { ...await jose.exportJWK(publicKey) };
138
140
  return {
139
141
  privateKey,
package/dist/callback.cjs CHANGED
@@ -25,7 +25,7 @@ __export(callback_exports, {
25
25
  });
26
26
  module.exports = __toCommonJS(callback_exports);
27
27
  var import_core = require("@fluixi/core");
28
- var import_signal = require("@fluixi/reactive/signal");
28
+ var import_signal2 = require("@fluixi/reactive/signal");
29
29
  var import_di2 = require("@fluixi/start/di");
30
30
 
31
31
  // src/tokens.ts
@@ -34,6 +34,7 @@ var AuthServiceToken = (0, import_di.injectionToken)("AuthService");
34
34
  var AuthClientToken = (0, import_di.injectionToken)("AuthClient");
35
35
 
36
36
  // src/service.ts
37
+ var import_signal = require("@fluixi/reactive/signal");
37
38
  var import_session = require("@fluixi/session");
38
39
  var import_client = require("@fluixi/auth/client");
39
40
  function paramsFromUrl(url) {
@@ -55,10 +56,10 @@ function reasonFor(cause) {
55
56
  }
56
57
  var spent = /* @__PURE__ */ new Set();
57
58
  function useOAuthCallback(options = {}) {
58
- const stage = (0, import_signal.signal)("waiting");
59
- const error = (0, import_signal.signal)(null);
60
- const destination = (0, import_signal.signal)(null);
61
- const params = (0, import_signal.signal)({});
59
+ const stage = (0, import_signal2.signal)("waiting");
60
+ const error = (0, import_signal2.signal)(null);
61
+ const destination = (0, import_signal2.signal)(null);
62
+ const params = (0, import_signal2.signal)({});
62
63
  let lastQuery = null;
63
64
  let injected = null;
64
65
  let injectionError = null;
package/dist/callback.mjs CHANGED
@@ -11,6 +11,7 @@ var AuthServiceToken = injectionToken("AuthService");
11
11
  var AuthClientToken = injectionToken("AuthClient");
12
12
 
13
13
  // src/service.ts
14
+ import { markReactiveScope, openReactiveScope, withReactiveScope } from "@fluixi/reactive/signal";
14
15
  import { createSession } from "@fluixi/session";
15
16
  import { createAuthHooks } from "@fluixi/auth/client";
16
17
  function paramsFromUrl(url) {
@@ -1,4 +1,4 @@
1
- /*! @fluixi/oauth2 v1.0.0-alpha.1 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/oauth2 v1.0.0-alpha.10 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/types.ts
4
4
  var OAuthError = class extends Error {
@@ -1,4 +1,4 @@
1
- /*! @fluixi/oauth2 v1.0.0-alpha.1 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/oauth2 v1.0.0-alpha.10 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  var __defProp = Object.defineProperty;
3
3
  var __export = (target, all) => {
4
4
  for (var name in all)
@@ -1,13 +1,13 @@
1
- /*! @fluixi/oauth2 v1.0.0-alpha.1 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/oauth2 v1.0.0-alpha.10 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  import {
3
3
  OAuthError
4
- } from "./chunk-4NSOGPLM.mjs";
5
- import "./chunk-25WE6UWI.mjs";
4
+ } from "./chunk-F52RUVDM.mjs";
5
+ import "./chunk-OGS6MQ3D.mjs";
6
6
 
7
7
  // src/dpop.ts
8
8
  async function loadJose() {
9
9
  try {
10
- return await import("./browser-ONMHX3Z3.mjs");
10
+ return await import("./browser-36FHB6KG.mjs");
11
11
  } catch {
12
12
  throw new OAuthError(
13
13
  "DPoP needs `jose`. Install it: npm i jose. It is an optional peer, so a client not using DPoP does not carry it.",
@@ -15,9 +15,11 @@ async function loadJose() {
15
15
  );
16
16
  }
17
17
  }
18
- async function createDpopKey(alg = "ES256") {
18
+ async function createDpopKey(alg = "ES256", options = {}) {
19
19
  const jose = await loadJose();
20
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
20
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
21
+ extractable: options.extractable ?? false
22
+ });
21
23
  const publicJwk = { ...await jose.exportJWK(publicKey) };
22
24
  return {
23
25
  privateKey,
@@ -26,6 +28,22 @@ async function createDpopKey(alg = "ES256") {
26
28
  alg
27
29
  };
28
30
  }
31
+ async function exportDpopKey(key) {
32
+ const jose = await loadJose();
33
+ return { jwk: { ...await jose.exportJWK(key.privateKey) }, alg: key.alg };
34
+ }
35
+ var PRIVATE_MEMBERS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
36
+ async function importDpopKey(stored) {
37
+ const jose = await loadJose();
38
+ const privateKey = await jose.importJWK(stored.jwk, stored.alg);
39
+ const publicJwk = Object.fromEntries(Object.entries(stored.jwk).filter(([k]) => !PRIVATE_MEMBERS.has(k)));
40
+ return {
41
+ privateKey,
42
+ publicJwk,
43
+ thumbprint: await jose.calculateJwkThumbprint(publicJwk, "sha256"),
44
+ alg: stored.alg
45
+ };
46
+ }
29
47
  async function thumbprintOf(jwk) {
30
48
  const jose = await loadJose();
31
49
  return jose.calculateJwkThumbprint(jwk, "sha256");
@@ -73,6 +91,8 @@ function boundKeyOf(claims) {
73
91
  export {
74
92
  boundKeyOf,
75
93
  createDpopKey,
94
+ exportDpopKey,
95
+ importDpopKey,
76
96
  nonceFrom,
77
97
  proofFor,
78
98
  thumbprintOf,
@@ -14,9 +14,11 @@ async function loadJose() {
14
14
  );
15
15
  }
16
16
  }
17
- async function createDpopKey(alg = "ES256") {
17
+ async function createDpopKey(alg = "ES256", options = {}) {
18
18
  const jose = await loadJose();
19
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
19
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
20
+ extractable: options.extractable ?? false
21
+ });
20
22
  const publicJwk = { ...await jose.exportJWK(publicKey) };
21
23
  return {
22
24
  privateKey,
@@ -25,6 +27,22 @@ async function createDpopKey(alg = "ES256") {
25
27
  alg
26
28
  };
27
29
  }
30
+ async function exportDpopKey(key) {
31
+ const jose = await loadJose();
32
+ return { jwk: { ...await jose.exportJWK(key.privateKey) }, alg: key.alg };
33
+ }
34
+ var PRIVATE_MEMBERS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
35
+ async function importDpopKey(stored) {
36
+ const jose = await loadJose();
37
+ const privateKey = await jose.importJWK(stored.jwk, stored.alg);
38
+ const publicJwk = Object.fromEntries(Object.entries(stored.jwk).filter(([k]) => !PRIVATE_MEMBERS.has(k)));
39
+ return {
40
+ privateKey,
41
+ publicJwk,
42
+ thumbprint: await jose.calculateJwkThumbprint(publicJwk, "sha256"),
43
+ alg: stored.alg
44
+ };
45
+ }
28
46
  async function thumbprintOf(jwk) {
29
47
  const jose = await loadJose();
30
48
  return jose.calculateJwkThumbprint(jwk, "sha256");
@@ -72,6 +90,8 @@ function boundKeyOf(claims) {
72
90
  export {
73
91
  boundKeyOf,
74
92
  createDpopKey,
93
+ exportDpopKey,
94
+ importDpopKey,
75
95
  nonceFrom,
76
96
  proofFor,
77
97
  thumbprintOf,
@@ -56,9 +56,11 @@ async function loadJose() {
56
56
  );
57
57
  }
58
58
  }
59
- async function createDpopKey(alg = "ES256") {
59
+ async function createDpopKey(alg = "ES256", options = {}) {
60
60
  const jose = await loadJose();
61
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
61
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
62
+ extractable: options.extractable ?? false
63
+ });
62
64
  const publicJwk = { ...await jose.exportJWK(publicKey) };
63
65
  return {
64
66
  privateKey,
@@ -21,9 +21,11 @@ async function loadJose() {
21
21
  );
22
22
  }
23
23
  }
24
- async function createDpopKey(alg = "ES256") {
24
+ async function createDpopKey(alg = "ES256", options = {}) {
25
25
  const jose = await loadJose();
26
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
26
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
27
+ extractable: options.extractable ?? false
28
+ });
27
29
  const publicJwk = { ...await jose.exportJWK(publicKey) };
28
30
  return {
29
31
  privateKey,
package/dist/dpop.cjs CHANGED
@@ -32,6 +32,8 @@ var dpop_exports = {};
32
32
  __export(dpop_exports, {
33
33
  boundKeyOf: () => boundKeyOf,
34
34
  createDpopKey: () => createDpopKey,
35
+ exportDpopKey: () => exportDpopKey,
36
+ importDpopKey: () => importDpopKey,
35
37
  nonceFrom: () => nonceFrom,
36
38
  proofFor: () => proofFor,
37
39
  thumbprintOf: () => thumbprintOf,
@@ -60,9 +62,11 @@ async function loadJose() {
60
62
  );
61
63
  }
62
64
  }
63
- async function createDpopKey(alg = "ES256") {
65
+ async function createDpopKey(alg = "ES256", options = {}) {
64
66
  const jose = await loadJose();
65
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
67
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
68
+ extractable: options.extractable ?? false
69
+ });
66
70
  const publicJwk = { ...await jose.exportJWK(publicKey) };
67
71
  return {
68
72
  privateKey,
@@ -71,6 +75,22 @@ async function createDpopKey(alg = "ES256") {
71
75
  alg
72
76
  };
73
77
  }
78
+ async function exportDpopKey(key) {
79
+ const jose = await loadJose();
80
+ return { jwk: { ...await jose.exportJWK(key.privateKey) }, alg: key.alg };
81
+ }
82
+ var PRIVATE_MEMBERS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
83
+ async function importDpopKey(stored) {
84
+ const jose = await loadJose();
85
+ const privateKey = await jose.importJWK(stored.jwk, stored.alg);
86
+ const publicJwk = Object.fromEntries(Object.entries(stored.jwk).filter(([k]) => !PRIVATE_MEMBERS.has(k)));
87
+ return {
88
+ privateKey,
89
+ publicJwk,
90
+ thumbprint: await jose.calculateJwkThumbprint(publicJwk, "sha256"),
91
+ alg: stored.alg
92
+ };
93
+ }
74
94
  async function thumbprintOf(jwk) {
75
95
  const jose = await loadJose();
76
96
  return jose.calculateJwkThumbprint(jwk, "sha256");
package/dist/dpop.d.ts CHANGED
@@ -25,7 +25,24 @@ export interface DpopKey {
25
25
  * attacker who can run script can use the key while they are there, and cannot take it
26
26
  * away to use later.
27
27
  */
28
- export declare function createDpopKey(alg?: string): Promise<DpopKey>;
28
+ export declare function createDpopKey(alg?: string, options?: {
29
+ extractable?: boolean;
30
+ }): Promise<DpopKey>;
31
+ /**
32
+ * A key as a server session stores it: the private JWK and its algorithm.
33
+ *
34
+ * Only for a key held by a server, inside an encrypted httpOnly cookie. There it is bytes
35
+ * no page can read, and the session has nowhere else to keep it between requests. A
36
+ * browser key stays non-extractable in IndexedDB instead.
37
+ */
38
+ export interface StoredDpopKey {
39
+ jwk: Record<string, unknown>;
40
+ alg: string;
41
+ }
42
+ /** Export a key made with `extractable: true`, for a server session to store. */
43
+ export declare function exportDpopKey(key: DpopKey): Promise<StoredDpopKey>;
44
+ /** Rebuild a key a server session stored. The thumbprint comes out the same, which is the point. */
45
+ export declare function importDpopKey(stored: StoredDpopKey): Promise<DpopKey>;
29
46
  /** The thumbprint of a public JWK, for comparing against a token's `cnf.jkt`. */
30
47
  export declare function thumbprintOf(jwk: Record<string, unknown>): Promise<string>;
31
48
  export interface ProofOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"dpop.d.ts","sourceRoot":"","sources":["../src/dpop.ts"],"names":[],"mappings":"AAkBA,6EAA6E;AAC7E,MAAM,WAAW,OAAO;IACtB,iEAAiE;IACjE,UAAU,EAAE,SAAS,CAAC;IACtB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,GAAG,EAAE,MAAM,CAAC;CACb;AAcD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CAAC,GAAG,SAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAWnE;AAED,iFAAiF;AACjF,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAGhF;AAED,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAsCnF;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAE3D;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAGvE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAGzE"}
1
+ {"version":3,"file":"dpop.d.ts","sourceRoot":"","sources":["../src/dpop.ts"],"names":[],"mappings":"AAkBA,6EAA6E;AAC7E,MAAM,WAAW,OAAO;IACtB,iEAAiE;IACjE,UAAU,EAAE,SAAS,CAAC;IACtB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC;;;;;OAKG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB,gGAAgG;IAChG,GAAG,EAAE,MAAM,CAAC;CACb;AAcD;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,GAAG,SAAU,EACb,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GACtC,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,iFAAiF;AACjF,wBAAsB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAGxE;AAID,oGAAoG;AACpG,wBAAsB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAW3E;AAED,iFAAiF;AACjF,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAGhF;AAED,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAsB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAsCnF;AAED,mFAAmF;AACnF,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,MAAM,GAAG,IAAI,CAE3D;AAED,0FAA0F;AAC1F,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAGvE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAGzE"}
package/dist/dpop.js CHANGED
@@ -35,9 +35,11 @@ async function loadJose() {
35
35
  * attacker who can run script can use the key while they are there, and cannot take it
36
36
  * away to use later.
37
37
  */
38
- export async function createDpopKey(alg = 'ES256') {
38
+ export async function createDpopKey(alg = 'ES256', options = {}) {
39
39
  const jose = await loadJose();
40
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
40
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
41
+ extractable: options.extractable ?? false,
42
+ });
41
43
  const publicJwk = { ...(await jose.exportJWK(publicKey)) };
42
44
  return {
43
45
  privateKey: privateKey,
@@ -46,6 +48,25 @@ export async function createDpopKey(alg = 'ES256') {
46
48
  alg,
47
49
  };
48
50
  }
51
+ /** Export a key made with `extractable: true`, for a server session to store. */
52
+ export async function exportDpopKey(key) {
53
+ const jose = await loadJose();
54
+ return { jwk: { ...(await jose.exportJWK(key.privateKey)) }, alg: key.alg };
55
+ }
56
+ const PRIVATE_MEMBERS = new Set(['d', 'p', 'q', 'dp', 'dq', 'qi', 'oth']);
57
+ /** Rebuild a key a server session stored. The thumbprint comes out the same, which is the point. */
58
+ export async function importDpopKey(stored) {
59
+ const jose = await loadJose();
60
+ const privateKey = (await jose.importJWK(stored.jwk, stored.alg));
61
+ // The public half is the private JWK without its private members (RFC 7518 §6.2.2, §6.3.2).
62
+ const publicJwk = Object.fromEntries(Object.entries(stored.jwk).filter(([k]) => !PRIVATE_MEMBERS.has(k)));
63
+ return {
64
+ privateKey,
65
+ publicJwk,
66
+ thumbprint: await jose.calculateJwkThumbprint(publicJwk, 'sha256'),
67
+ alg: stored.alg,
68
+ };
69
+ }
49
70
  /** The thumbprint of a public JWK, for comparing against a token's `cnf.jkt`. */
50
71
  export async function thumbprintOf(jwk) {
51
72
  const jose = await loadJose();
package/dist/dpop.mjs CHANGED
@@ -21,9 +21,11 @@ async function loadJose() {
21
21
  );
22
22
  }
23
23
  }
24
- async function createDpopKey(alg = "ES256") {
24
+ async function createDpopKey(alg = "ES256", options = {}) {
25
25
  const jose = await loadJose();
26
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
26
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
27
+ extractable: options.extractable ?? false
28
+ });
27
29
  const publicJwk = { ...await jose.exportJWK(publicKey) };
28
30
  return {
29
31
  privateKey,
@@ -32,6 +34,22 @@ async function createDpopKey(alg = "ES256") {
32
34
  alg
33
35
  };
34
36
  }
37
+ async function exportDpopKey(key) {
38
+ const jose = await loadJose();
39
+ return { jwk: { ...await jose.exportJWK(key.privateKey) }, alg: key.alg };
40
+ }
41
+ var PRIVATE_MEMBERS = /* @__PURE__ */ new Set(["d", "p", "q", "dp", "dq", "qi", "oth"]);
42
+ async function importDpopKey(stored) {
43
+ const jose = await loadJose();
44
+ const privateKey = await jose.importJWK(stored.jwk, stored.alg);
45
+ const publicJwk = Object.fromEntries(Object.entries(stored.jwk).filter(([k]) => !PRIVATE_MEMBERS.has(k)));
46
+ return {
47
+ privateKey,
48
+ publicJwk,
49
+ thumbprint: await jose.calculateJwkThumbprint(publicJwk, "sha256"),
50
+ alg: stored.alg
51
+ };
52
+ }
35
53
  async function thumbprintOf(jwk) {
36
54
  const jose = await loadJose();
37
55
  return jose.calculateJwkThumbprint(jwk, "sha256");
@@ -79,6 +97,8 @@ function boundKeyOf(claims) {
79
97
  export {
80
98
  boundKeyOf,
81
99
  createDpopKey,
100
+ exportDpopKey,
101
+ importDpopKey,
82
102
  nonceFrom,
83
103
  proofFor,
84
104
  thumbprintOf,
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- /*! @fluixi/oauth2 v1.0.0-alpha.1 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/oauth2 v1.0.0-alpha.10 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -35,6 +35,7 @@ __export(index_exports, {
35
35
  AuthServiceToken: () => AuthServiceToken,
36
36
  COOKIE_SESSION: () => COOKIE_SESSION,
37
37
  OAuthError: () => OAuthError,
38
+ authModule: () => authModule,
38
39
  boundKeyOf: () => boundKeyOf,
39
40
  clearDiscoveryCache: () => clearDiscoveryCache,
40
41
  createAuthService: () => createAuthService,
@@ -55,6 +56,7 @@ __export(index_exports, {
55
56
  module.exports = __toCommonJS(index_exports);
56
57
 
57
58
  // src/service.ts
59
+ var import_signal = require("@fluixi/reactive/signal");
58
60
  var import_session = require("@fluixi/session");
59
61
  var import_client = require("@fluixi/auth/client");
60
62
 
@@ -212,9 +214,11 @@ async function loadJose2() {
212
214
  );
213
215
  }
214
216
  }
215
- async function createDpopKey(alg = "ES256") {
217
+ async function createDpopKey(alg = "ES256", options = {}) {
216
218
  const jose = await loadJose2();
217
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
219
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
220
+ extractable: options.extractable ?? false
221
+ });
218
222
  const publicJwk = { ...await jose.exportJWK(publicKey) };
219
223
  return {
220
224
  privateKey,
@@ -861,6 +865,13 @@ function clientFor(options) {
861
865
  return options.config.tokens === "server" ? createServerClient(options.config) : createBrowserClient(options.config);
862
866
  }
863
867
  function createAuthService(options) {
868
+ const tokens = options.config.tokens;
869
+ const scope = (0, import_signal.openReactiveScope)({ kind: "service", name: "AuthService", ...tokens ? { detail: `tokens: ${tokens}` } : {} });
870
+ const service = (0, import_signal.withReactiveScope)(scope, () => buildAuthService(options));
871
+ (0, import_signal.markReactiveScope)(service, scope);
872
+ return service;
873
+ }
874
+ function buildAuthService(options) {
864
875
  const client = clientFor(options);
865
876
  let latest = null;
866
877
  const session = (0, import_session.createSession)({
@@ -938,3 +949,17 @@ function createAuthService(options) {
938
949
  var import_di = require("@fluixi/start/di");
939
950
  var AuthServiceToken = (0, import_di.injectionToken)("AuthService");
940
951
  var AuthClientToken = (0, import_di.injectionToken)("AuthClient");
952
+
953
+ // src/module.ts
954
+ var import_app = require("@fluixi/start/app");
955
+ function authModule(auth) {
956
+ return (0, import_app.defineModule)({
957
+ name: "oauth2",
958
+ providers: [
959
+ // One instance for every request on the server. It holds no per-visitor state there:
960
+ // the signed-in user comes from request locals, which `sessionLocals` fills per request.
961
+ { provide: AuthServiceToken, useValue: auth },
962
+ { provide: AuthClientToken, useValue: auth.client }
963
+ ]
964
+ });
965
+ }
package/dist/index.d.ts CHANGED
@@ -101,4 +101,5 @@ export type { ReturnToOptions } from './return-to.js';
101
101
  export { OAuthError } from './types.js';
102
102
  export type { AuthClient, AuthConfig, BaseConfig, BrowserConfig, CallbackParams, Endpoints, LoginOptions, ServerConfig, Tokens, } from './types.js';
103
103
  export { AuthServiceToken, AuthClientToken } from './tokens.js';
104
+ export { authModule } from './module.js';
104
105
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AACH,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAExE,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EACL,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC9E,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,YAAY,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,aAAa,EACb,cAAc,EACd,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,MAAM,GACP,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyFG;AACH,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAErF,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAExE,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EACL,cAAc,EACd,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,aAAa,GACd,MAAM,WAAW,CAAC;AAEnB,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC9E,YAAY,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEtD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,YAAY,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,aAAa,EACb,cAAc,EACd,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,MAAM,GACP,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -97,5 +97,6 @@ export { createDpopKey, proofFor, thumbprintOf, boundKeyOf } from './dpop.js';
97
97
  export { safeReturnTo } from './return-to.js';
98
98
  export { OAuthError } from './types.js';
99
99
  export { AuthServiceToken, AuthClientToken } from './tokens.js';
100
+ export { authModule } from './module.js';
100
101
  // Token verification lives on `@fluixi/oauth2/verify`, so a browser bundle never pulls in
101
102
  // `jose` just because the package was imported.
package/dist/index.mjs CHANGED
@@ -1,7 +1,8 @@
1
- /*! @fluixi/oauth2 v1.0.0-alpha.1 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
- import "./chunk-25WE6UWI.mjs";
1
+ /*! @fluixi/oauth2 v1.0.0-alpha.10 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
+ import "./chunk-OGS6MQ3D.mjs";
3
3
 
4
4
  // src/service.ts
5
+ import { markReactiveScope, openReactiveScope, withReactiveScope } from "@fluixi/reactive/signal";
5
6
  import { createSession } from "@fluixi/session";
6
7
  import { createAuthHooks } from "@fluixi/auth/client";
7
8
 
@@ -111,7 +112,7 @@ function resolveMethod(auth) {
111
112
  }
112
113
  async function loadJose() {
113
114
  try {
114
- return await import("./browser-ONMHX3Z3.mjs");
115
+ return await import("./browser-36FHB6KG.mjs");
115
116
  } catch {
116
117
  throw new OAuthError(
117
118
  "private_key_jwt needs `jose`. Install it: npm i jose. It is an optional peer, so a client using a secret does not carry it.",
@@ -151,7 +152,7 @@ async function applyClientAuth(auth, endpoint, headers, form) {
151
152
  // src/dpop.ts
152
153
  async function loadJose2() {
153
154
  try {
154
- return await import("./browser-ONMHX3Z3.mjs");
155
+ return await import("./browser-36FHB6KG.mjs");
155
156
  } catch {
156
157
  throw new OAuthError(
157
158
  "DPoP needs `jose`. Install it: npm i jose. It is an optional peer, so a client not using DPoP does not carry it.",
@@ -159,9 +160,11 @@ async function loadJose2() {
159
160
  );
160
161
  }
161
162
  }
162
- async function createDpopKey(alg = "ES256") {
163
+ async function createDpopKey(alg = "ES256", options = {}) {
163
164
  const jose = await loadJose2();
164
- const { privateKey, publicKey } = await jose.generateKeyPair(alg, { extractable: false });
165
+ const { privateKey, publicKey } = await jose.generateKeyPair(alg, {
166
+ extractable: options.extractable ?? false
167
+ });
165
168
  const publicJwk = { ...await jose.exportJWK(publicKey) };
166
169
  return {
167
170
  privateKey,
@@ -808,6 +811,13 @@ function clientFor(options) {
808
811
  return options.config.tokens === "server" ? createServerClient(options.config) : createBrowserClient(options.config);
809
812
  }
810
813
  function createAuthService(options) {
814
+ const tokens = options.config.tokens;
815
+ const scope = openReactiveScope({ kind: "service", name: "AuthService", ...tokens ? { detail: `tokens: ${tokens}` } : {} });
816
+ const service = withReactiveScope(scope, () => buildAuthService(options));
817
+ markReactiveScope(service, scope);
818
+ return service;
819
+ }
820
+ function buildAuthService(options) {
811
821
  const client = clientFor(options);
812
822
  let latest = null;
813
823
  const session = createSession({
@@ -885,11 +895,26 @@ function createAuthService(options) {
885
895
  import { injectionToken } from "@fluixi/start/di";
886
896
  var AuthServiceToken = injectionToken("AuthService");
887
897
  var AuthClientToken = injectionToken("AuthClient");
898
+
899
+ // src/module.ts
900
+ import { defineModule } from "@fluixi/start/app";
901
+ function authModule(auth) {
902
+ return defineModule({
903
+ name: "oauth2",
904
+ providers: [
905
+ // One instance for every request on the server. It holds no per-visitor state there:
906
+ // the signed-in user comes from request locals, which `sessionLocals` fills per request.
907
+ { provide: AuthServiceToken, useValue: auth },
908
+ { provide: AuthClientToken, useValue: auth.client }
909
+ ]
910
+ });
911
+ }
888
912
  export {
889
913
  AuthClientToken,
890
914
  AuthServiceToken,
891
915
  COOKIE_SESSION,
892
916
  OAuthError,
917
+ authModule,
893
918
  boundKeyOf,
894
919
  clearDiscoveryCache,
895
920
  createAuthService,
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/module.ts
21
+ var module_exports = {};
22
+ __export(module_exports, {
23
+ authModule: () => authModule
24
+ });
25
+ module.exports = __toCommonJS(module_exports);
26
+ var import_app = require("@fluixi/start/app");
27
+
28
+ // src/tokens.ts
29
+ var import_di = require("@fluixi/start/di");
30
+ var AuthServiceToken = (0, import_di.injectionToken)("AuthService");
31
+ var AuthClientToken = (0, import_di.injectionToken)("AuthClient");
32
+
33
+ // src/module.ts
34
+ function authModule(auth) {
35
+ return (0, import_app.defineModule)({
36
+ name: "oauth2",
37
+ providers: [
38
+ // One instance for every request on the server. It holds no per-visitor state there:
39
+ // the signed-in user comes from request locals, which `sessionLocals` fills per request.
40
+ { provide: AuthServiceToken, useValue: auth },
41
+ { provide: AuthClientToken, useValue: auth.client }
42
+ ]
43
+ });
44
+ }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The app-module half of this package, listed in `src/app.config.ts`.
3
+ *
4
+ * Registers the app's service under `AuthServiceToken` and its client under
5
+ * `AuthClientToken` on both sides. Package code reaches the service through those tokens,
6
+ * `OAuthCallback` among it, because a package cannot import the app. The server half, the
7
+ * routes and session middleware of `tokens: 'server'`, is `authServerModule` in
8
+ * `@fluixi/oauth2/server`, for `app.config.server.ts`.
9
+ */
10
+ import { type AppModule } from '@fluixi/start/app';
11
+ import type { AuthService } from './service.js';
12
+ export declare function authModule<U, P, Q>(auth: AuthService<U, P, Q>): AppModule;
13
+ //# sourceMappingURL=module.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAUzE"}