@_mustachio/openauth 0.11.0 → 0.12.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.
Files changed (164) hide show
  1. package/dist/esm/adapters/d1/index.js +18 -9
  2. package/dist/esm/adapters/d1/migrations.js +7 -2
  3. package/dist/esm/adapters/d1/session-store.js +39 -0
  4. package/dist/esm/adapters/d1/session.js +2 -2
  5. package/dist/esm/adapters/durable-object/index.js +4 -0
  6. package/dist/esm/adapters/durable-object/session-store.js +42 -0
  7. package/dist/esm/adapters/dynamo/index.js +24 -7
  8. package/dist/esm/adapters/dynamo/session-store.js +49 -0
  9. package/dist/esm/adapters/kms/index.js +6 -2
  10. package/dist/esm/adapters/kv/index.js +6 -2
  11. package/dist/esm/adapters/memory/index.js +24 -7
  12. package/dist/esm/adapters/memory/session-store.js +23 -0
  13. package/dist/esm/adapters/postgres/executor.js +2 -2
  14. package/dist/esm/adapters/postgres/index.js +33 -10
  15. package/dist/esm/adapters/postgres/migrations.js +8 -2
  16. package/dist/esm/adapters/postgres/session-store.js +42 -0
  17. package/dist/esm/client.js +27 -27
  18. package/dist/esm/domain/authorize.js +2 -2
  19. package/dist/esm/domain/callback.js +121 -7
  20. package/dist/esm/domain/client-auth.js +2 -2
  21. package/dist/esm/domain/crypto.js +14 -14
  22. package/dist/esm/domain/discovery.js +2 -2
  23. package/dist/esm/domain/dpop.js +4 -4
  24. package/dist/esm/domain/id-token.js +5 -5
  25. package/dist/esm/domain/jwt.js +4 -4
  26. package/dist/esm/domain/method-dispatch.js +27 -1
  27. package/dist/esm/domain/method-route.js +80 -1
  28. package/dist/esm/domain/par.js +2 -2
  29. package/dist/esm/domain/pkce.js +2 -2
  30. package/dist/esm/domain/revoke.js +2 -2
  31. package/dist/esm/domain/state-envelope.js +2 -2
  32. package/dist/esm/domain/token.js +5 -5
  33. package/dist/esm/error.js +8 -8
  34. package/dist/esm/http/cookies.js +19 -2
  35. package/dist/esm/http/errors.js +4 -4
  36. package/dist/esm/http/handlers/authorize.js +3 -19
  37. package/dist/esm/http/handlers/callback.js +7 -1
  38. package/dist/esm/http/handlers/metadata.js +2 -2
  39. package/dist/esm/http/handlers/method-route.js +47 -2
  40. package/dist/esm/http/handlers/revocation.js +2 -2
  41. package/dist/esm/http/middleware/tenant.js +6 -6
  42. package/dist/esm/http/schemas/authorize.js +2 -2
  43. package/dist/esm/http/schemas/revocation.js +2 -2
  44. package/dist/esm/http/schemas/token.js +7 -7
  45. package/dist/esm/index.js +33 -32
  46. package/dist/esm/methods/oauth2-factory.js +2 -2
  47. package/dist/esm/methods/password-hash.js +2 -2
  48. package/dist/esm/methods/providers/index.js +30 -14
  49. package/dist/esm/methods/saml-sp/acs.js +208 -0
  50. package/dist/esm/methods/saml-sp/attributes.js +75 -0
  51. package/dist/esm/methods/saml-sp/authnrequest.js +63 -0
  52. package/dist/esm/methods/saml-sp/cache-provider.js +33 -0
  53. package/dist/esm/methods/saml-sp/cert-rotation.js +13 -0
  54. package/dist/esm/methods/saml-sp/factory.js +70 -0
  55. package/dist/esm/methods/saml-sp/index.js +7 -0
  56. package/dist/esm/methods/saml-sp/metadata.js +69 -0
  57. package/dist/esm/methods/saml-sp/method.js +29 -0
  58. package/dist/esm/methods/saml-sp/parse-idp-metadata.js +102 -0
  59. package/dist/esm/methods/saml-sp/saml-instance.js +49 -0
  60. package/dist/esm/methods/saml-sp/slo-initiate.js +84 -0
  61. package/dist/esm/methods/saml-sp/sls.js +154 -0
  62. package/dist/esm/methods/saml-sp/types.js +0 -0
  63. package/dist/esm/types/result.js +3 -3
  64. package/dist/esm/ui/forms.js +3 -3
  65. package/dist/esm/ui/index.js +8 -5
  66. package/dist/esm/ui/picker.js +2 -2
  67. package/dist/types/adapters/d1/migrations.d.ts.map +1 -1
  68. package/dist/types/adapters/d1/session-store.d.ts +3 -0
  69. package/dist/types/adapters/d1/session-store.d.ts.map +1 -1
  70. package/dist/types/adapters/durable-object/session-store.d.ts +3 -0
  71. package/dist/types/adapters/durable-object/session-store.d.ts.map +1 -1
  72. package/dist/types/adapters/dynamo/session-store.d.ts +3 -0
  73. package/dist/types/adapters/dynamo/session-store.d.ts.map +1 -1
  74. package/dist/types/adapters/memory/session-store.d.ts +3 -0
  75. package/dist/types/adapters/memory/session-store.d.ts.map +1 -1
  76. package/dist/types/adapters/postgres/migrations.d.ts +1 -1
  77. package/dist/types/adapters/postgres/migrations.d.ts.map +1 -1
  78. package/dist/types/adapters/postgres/session-store.d.ts +3 -0
  79. package/dist/types/adapters/postgres/session-store.d.ts.map +1 -1
  80. package/dist/types/domain/callback.d.ts +16 -1
  81. package/dist/types/domain/callback.d.ts.map +1 -1
  82. package/dist/types/domain/method-dispatch.d.ts.map +1 -1
  83. package/dist/types/domain/method-route.d.ts +57 -1
  84. package/dist/types/domain/method-route.d.ts.map +1 -1
  85. package/dist/types/http/context.d.ts +3 -1
  86. package/dist/types/http/context.d.ts.map +1 -1
  87. package/dist/types/http/cookies.d.ts +9 -1
  88. package/dist/types/http/cookies.d.ts.map +1 -1
  89. package/dist/types/http/handlers/callback.d.ts.map +1 -1
  90. package/dist/types/http/handlers/method-route.d.ts.map +1 -1
  91. package/dist/types/index.d.ts +1 -1
  92. package/dist/types/index.d.ts.map +1 -1
  93. package/dist/types/methods/saml-sp/acs.d.ts +4 -0
  94. package/dist/types/methods/saml-sp/acs.d.ts.map +1 -0
  95. package/dist/types/methods/saml-sp/attributes.d.ts +40 -0
  96. package/dist/types/methods/saml-sp/attributes.d.ts.map +1 -0
  97. package/dist/types/methods/saml-sp/authnrequest.d.ts +4 -0
  98. package/dist/types/methods/saml-sp/authnrequest.d.ts.map +1 -0
  99. package/dist/types/methods/saml-sp/cache-provider.d.ts +38 -0
  100. package/dist/types/methods/saml-sp/cache-provider.d.ts.map +1 -0
  101. package/dist/types/methods/saml-sp/cert-rotation.d.ts +23 -0
  102. package/dist/types/methods/saml-sp/cert-rotation.d.ts.map +1 -0
  103. package/dist/types/methods/saml-sp/factory.d.ts +704 -0
  104. package/dist/types/methods/saml-sp/factory.d.ts.map +1 -0
  105. package/dist/types/methods/saml-sp/index.d.ts +24 -0
  106. package/dist/types/methods/saml-sp/index.d.ts.map +1 -0
  107. package/dist/types/methods/saml-sp/metadata.d.ts +42 -0
  108. package/dist/types/methods/saml-sp/metadata.d.ts.map +1 -0
  109. package/dist/types/methods/saml-sp/method.d.ts +17 -0
  110. package/dist/types/methods/saml-sp/method.d.ts.map +1 -0
  111. package/dist/types/methods/saml-sp/parse-idp-metadata.d.ts +4 -0
  112. package/dist/types/methods/saml-sp/parse-idp-metadata.d.ts.map +1 -0
  113. package/dist/types/methods/saml-sp/saml-instance.d.ts +81 -0
  114. package/dist/types/methods/saml-sp/saml-instance.d.ts.map +1 -0
  115. package/dist/types/methods/saml-sp/slo-initiate.d.ts +4 -0
  116. package/dist/types/methods/saml-sp/slo-initiate.d.ts.map +1 -0
  117. package/dist/types/methods/saml-sp/sls.d.ts +4 -0
  118. package/dist/types/methods/saml-sp/sls.d.ts.map +1 -0
  119. package/dist/types/methods/saml-sp/types.d.ts +204 -0
  120. package/dist/types/methods/saml-sp/types.d.ts.map +1 -0
  121. package/dist/types/ports/audit-log.d.ts +18 -5
  122. package/dist/types/ports/audit-log.d.ts.map +1 -1
  123. package/dist/types/ports/session-store.d.ts +23 -0
  124. package/dist/types/ports/session-store.d.ts.map +1 -1
  125. package/dist/types/types/idp.d.ts +71 -0
  126. package/dist/types/types/idp.d.ts.map +1 -1
  127. package/dist/types/types/method.d.ts +109 -0
  128. package/dist/types/types/method.d.ts.map +1 -1
  129. package/package.json +9 -1
  130. package/src/adapters/d1/migrations.ts +5 -0
  131. package/src/adapters/d1/session-store.ts +68 -0
  132. package/src/adapters/durable-object/session-store.ts +61 -0
  133. package/src/adapters/dynamo/session-store.ts +63 -0
  134. package/src/adapters/memory/session-store.ts +39 -0
  135. package/src/adapters/postgres/migrations.ts +6 -0
  136. package/src/adapters/postgres/session-store.ts +69 -0
  137. package/src/domain/callback.ts +215 -7
  138. package/src/domain/method-dispatch.ts +53 -1
  139. package/src/domain/method-route.ts +190 -1
  140. package/src/http/context.ts +6 -0
  141. package/src/http/cookies.ts +19 -1
  142. package/src/http/handlers/authorize.ts +2 -21
  143. package/src/http/handlers/callback.ts +9 -1
  144. package/src/http/handlers/method-route.ts +75 -2
  145. package/src/index.ts +3 -0
  146. package/src/methods/saml-sp/acs.ts +399 -0
  147. package/src/methods/saml-sp/attributes.ts +137 -0
  148. package/src/methods/saml-sp/authnrequest.ts +128 -0
  149. package/src/methods/saml-sp/cache-provider.ts +76 -0
  150. package/src/methods/saml-sp/cert-rotation.ts +34 -0
  151. package/src/methods/saml-sp/factory.ts +118 -0
  152. package/src/methods/saml-sp/index.ts +34 -0
  153. package/src/methods/saml-sp/metadata.ts +204 -0
  154. package/src/methods/saml-sp/method.ts +65 -0
  155. package/src/methods/saml-sp/parse-idp-metadata.ts +164 -0
  156. package/src/methods/saml-sp/saml-instance.ts +173 -0
  157. package/src/methods/saml-sp/slo-initiate.ts +177 -0
  158. package/src/methods/saml-sp/sls.ts +306 -0
  159. package/src/methods/saml-sp/types.ts +203 -0
  160. package/src/ports/CONSISTENCY.md +25 -0
  161. package/src/ports/audit-log.ts +18 -5
  162. package/src/ports/session-store.ts +28 -0
  163. package/src/types/idp.ts +74 -0
  164. package/src/types/method.ts +110 -0
@@ -1,12 +1,21 @@
1
+ // src/adapters/d1/index.ts
2
+ import { D1AuditLog } from "./audit-log";
3
+ import { D1ConfigStore } from "./config-store";
4
+ import { D1KeyStore } from "./key-store";
5
+ import { D1MethodStore } from "./method-store";
6
+ import { D1SessionStore } from "./session-store";
7
+ import { D1TokenStore } from "./token-store";
8
+ import { INITIAL_SCHEMA_SQL, migrate } from "./migrations";
9
+ import { isSessionsCapable, primarySession } from "./session";
1
10
  export {
2
- primarySession,
3
- migrate,
4
- isSessionsCapable,
5
- INITIAL_SCHEMA_SQL,
6
- D1TokenStore,
7
- D1SessionStore,
8
- D1MethodStore,
9
- D1KeyStore,
11
+ D1AuditLog,
10
12
  D1ConfigStore,
11
- D1AuditLog
13
+ D1KeyStore,
14
+ D1MethodStore,
15
+ D1SessionStore,
16
+ D1TokenStore,
17
+ INITIAL_SCHEMA_SQL,
18
+ isSessionsCapable,
19
+ migrate,
20
+ primarySession
12
21
  };
@@ -57,6 +57,11 @@ var INITIAL_SCHEMA_SQL = [
57
57
  payload TEXT NOT NULL,
58
58
  expires_at INTEGER NOT NULL
59
59
  )`,
60
+ `CREATE TABLE IF NOT EXISTS openauth_scratch (
61
+ scratch_key TEXT PRIMARY KEY,
62
+ value TEXT NOT NULL,
63
+ expires_at INTEGER NOT NULL
64
+ )`,
60
65
  `CREATE TABLE IF NOT EXISTS openauth_audit_events (
61
66
  id INTEGER PRIMARY KEY AUTOINCREMENT,
62
67
  ts INTEGER NOT NULL,
@@ -72,6 +77,6 @@ async function migrate(db) {
72
77
  }
73
78
  }
74
79
  export {
75
- migrate,
76
- INITIAL_SCHEMA_SQL
80
+ INITIAL_SCHEMA_SQL,
81
+ migrate
77
82
  };
@@ -128,6 +128,45 @@ class D1SessionStore {
128
128
  }
129
129
  return ok(undefined);
130
130
  }
131
+ async saveScratch(key, value, ttlMs) {
132
+ if (ttlMs <= 0) {
133
+ return err(authError.internalError(`saveScratch: ttlMs must be positive, got ${ttlMs}`));
134
+ }
135
+ const expiresAt = this.#clock() + ttlMs;
136
+ try {
137
+ await primarySession(this.#db).prepare(`INSERT INTO openauth_scratch (scratch_key, value, expires_at) VALUES (?1, ?2, ?3)
138
+ ON CONFLICT(scratch_key) DO UPDATE SET value = excluded.value, expires_at = excluded.expires_at`).bind(key, value, expiresAt).run();
139
+ } catch (e) {
140
+ return err(authError.internalError("saveScratch: upsert failed", e));
141
+ }
142
+ return ok(undefined);
143
+ }
144
+ async readScratch(key) {
145
+ let row;
146
+ try {
147
+ row = await primarySession(this.#db).prepare(`SELECT value, expires_at FROM openauth_scratch WHERE scratch_key = ?1`).bind(key).first();
148
+ } catch (e) {
149
+ return err(authError.internalError("readScratch: query failed", e));
150
+ }
151
+ if (!row) {
152
+ return err(authError.unknownState(`scratch "${key}" unknown`));
153
+ }
154
+ if (this.#clock() >= Number(row.expires_at)) {
155
+ try {
156
+ await primarySession(this.#db).prepare(`DELETE FROM openauth_scratch WHERE scratch_key = ?1`).bind(key).run();
157
+ } catch {}
158
+ return err(authError.unknownState(`scratch "${key}" expired`));
159
+ }
160
+ return ok(row.value);
161
+ }
162
+ async deleteScratch(key) {
163
+ try {
164
+ await primarySession(this.#db).prepare(`DELETE FROM openauth_scratch WHERE scratch_key = ?1`).bind(key).run();
165
+ } catch (e) {
166
+ return err(authError.internalError("deleteScratch: delete failed", e));
167
+ }
168
+ return ok(undefined);
169
+ }
131
170
  }
132
171
  export {
133
172
  D1SessionStore
@@ -13,6 +13,6 @@ function primarySession(db) {
13
13
  };
14
14
  }
15
15
  export {
16
- primarySession,
17
- isSessionsCapable
16
+ isSessionsCapable,
17
+ primarySession
18
18
  };
@@ -1,3 +1,7 @@
1
+ // src/adapters/durable-object/index.ts
2
+ import {
3
+ DurableObjectSessionStore
4
+ } from "./session-store";
1
5
  export {
2
6
  DurableObjectSessionStore
3
7
  };
@@ -131,9 +131,51 @@ class DurableObjectSessionStore {
131
131
  }
132
132
  return ok(undefined);
133
133
  }
134
+ async saveScratch(key, value, ttlMs) {
135
+ if (ttlMs <= 0) {
136
+ return err(authError.internalError(`saveScratch: ttlMs must be positive, got ${ttlMs}`));
137
+ }
138
+ const stored = {
139
+ value,
140
+ expiresAt: this.#clock() + ttlMs
141
+ };
142
+ try {
143
+ await this.#storage.put(scratchKey(key), stored);
144
+ } catch (e) {
145
+ return err(authError.internalError("saveScratch: put failed", e));
146
+ }
147
+ return ok(undefined);
148
+ }
149
+ async readScratch(key) {
150
+ let stored;
151
+ try {
152
+ stored = await this.#storage.get(scratchKey(key));
153
+ } catch (e) {
154
+ return err(authError.internalError("readScratch: get failed", e));
155
+ }
156
+ if (!stored) {
157
+ return err(authError.unknownState(`scratch "${key}" unknown`));
158
+ }
159
+ if (this.#clock() >= stored.expiresAt) {
160
+ try {
161
+ await this.#storage.delete(scratchKey(key));
162
+ } catch {}
163
+ return err(authError.unknownState(`scratch "${key}" expired`));
164
+ }
165
+ return ok(stored.value);
166
+ }
167
+ async deleteScratch(key) {
168
+ try {
169
+ await this.#storage.delete(scratchKey(key));
170
+ } catch (e) {
171
+ return err(authError.internalError("deleteScratch: delete failed", e));
172
+ }
173
+ return ok(undefined);
174
+ }
134
175
  }
135
176
  var flowKey = (flowId) => `flow:${flowId}`;
136
177
  var sessionKey = (sessionId) => `session:${sessionId}`;
178
+ var scratchKey = (key) => `scratch:${key}`;
137
179
  export {
138
180
  DurableObjectSessionStore
139
181
  };
@@ -1,10 +1,27 @@
1
+ // src/adapters/dynamo/index.ts
2
+ import { DynamoAuditLog } from "./audit-log";
3
+ import {
4
+ DynamoConfigStore
5
+ } from "./config-store";
6
+ import { DynamoKeyStore } from "./key-store";
7
+ import {
8
+ DynamoMethodStore
9
+ } from "./method-store";
10
+ import {
11
+ DynamoSessionStore
12
+ } from "./session-store";
13
+ import { DynamoTokenStore } from "./token-store";
14
+ import {
15
+ DynamoPasskeyCredentialStore
16
+ } from "./passkey-credential-store";
17
+ import { fromDynamoDBClient } from "./sdk";
1
18
  export {
2
- fromDynamoDBClient,
3
- DynamoTokenStore,
4
- DynamoSessionStore,
5
- DynamoPasskeyCredentialStore,
6
- DynamoMethodStore,
7
- DynamoKeyStore,
19
+ DynamoAuditLog,
8
20
  DynamoConfigStore,
9
- DynamoAuditLog
21
+ DynamoKeyStore,
22
+ DynamoMethodStore,
23
+ DynamoPasskeyCredentialStore,
24
+ DynamoSessionStore,
25
+ DynamoTokenStore,
26
+ fromDynamoDBClient
10
27
  };
@@ -152,6 +152,55 @@ class DynamoSessionStore {
152
152
  }
153
153
  return ok(undefined);
154
154
  }
155
+ async saveScratch(key, value, ttlMs) {
156
+ if (ttlMs <= 0) {
157
+ return err(authError.internalError(`saveScratch: ttlMs must be positive, got ${ttlMs}`));
158
+ }
159
+ const expiresAtMs = this.#clock() + ttlMs;
160
+ try {
161
+ await this.#exec.put({
162
+ item: {
163
+ pk: "scratch",
164
+ sk: key,
165
+ value,
166
+ expires_at: expiresAtMs,
167
+ ttl: Math.floor(expiresAtMs / 1000)
168
+ }
169
+ });
170
+ } catch (e) {
171
+ return err(authError.internalError("saveScratch: put failed", e));
172
+ }
173
+ return ok(undefined);
174
+ }
175
+ async readScratch(key) {
176
+ let row;
177
+ try {
178
+ row = await this.#exec.get({
179
+ key: { pk: "scratch", sk: key },
180
+ consistentRead: true
181
+ });
182
+ } catch (e) {
183
+ return err(authError.internalError("readScratch: get failed", e));
184
+ }
185
+ if (!row) {
186
+ return err(authError.unknownState(`scratch "${key}" unknown`));
187
+ }
188
+ if (this.#clock() >= Number(row.expires_at)) {
189
+ try {
190
+ await this.#exec.delete({ key: { pk: "scratch", sk: key } });
191
+ } catch {}
192
+ return err(authError.unknownState(`scratch "${key}" expired`));
193
+ }
194
+ return ok(String(row.value));
195
+ }
196
+ async deleteScratch(key) {
197
+ try {
198
+ await this.#exec.delete({ key: { pk: "scratch", sk: key } });
199
+ } catch (e) {
200
+ return err(authError.internalError("deleteScratch: delete failed", e));
201
+ }
202
+ return ok(undefined);
203
+ }
155
204
  }
156
205
  function parseFlowPayload(raw) {
157
206
  if (typeof raw === "string")
@@ -1,5 +1,9 @@
1
+ // src/adapters/kms/index.ts
2
+ import { inMemoryKmsBackingStore } from "./in-memory-backing";
3
+ import { KmsKeyStore } from "./key-store";
4
+ import { fromKmsClient } from "./sdk";
1
5
  export {
2
- inMemoryKmsBackingStore,
6
+ KmsKeyStore,
3
7
  fromKmsClient,
4
- KmsKeyStore
8
+ inMemoryKmsBackingStore
5
9
  };
@@ -1,5 +1,9 @@
1
+ // src/adapters/kv/index.ts
2
+ import { KvAuditLog } from "./audit-log";
3
+ import { KvConfigStore } from "./config-store";
4
+ import { KvMethodStore } from "./method-store";
1
5
  export {
2
- KvMethodStore,
6
+ KvAuditLog,
3
7
  KvConfigStore,
4
- KvAuditLog
8
+ KvMethodStore
5
9
  };
@@ -1,10 +1,27 @@
1
+ // src/adapters/memory/index.ts
2
+ import { MemoryAuditLog } from "./audit-log";
3
+ import {
4
+ MemoryConfigStore
5
+ } from "./config-store";
6
+ import { MemoryKeyStore } from "./key-store";
7
+ import {
8
+ MemoryMethodStore
9
+ } from "./method-store";
10
+ import {
11
+ MemorySessionStore
12
+ } from "./session-store";
13
+ import { MemoryTokenStore } from "./token-store";
14
+ import {
15
+ MemoryPasskeyCredentialStore
16
+ } from "./passkey-credential-store";
17
+ import { realClock } from "./clock";
1
18
  export {
2
- realClock,
3
- MemoryTokenStore,
4
- MemorySessionStore,
5
- MemoryPasskeyCredentialStore,
6
- MemoryMethodStore,
7
- MemoryKeyStore,
19
+ MemoryAuditLog,
8
20
  MemoryConfigStore,
9
- MemoryAuditLog
21
+ MemoryKeyStore,
22
+ MemoryMethodStore,
23
+ MemoryPasskeyCredentialStore,
24
+ MemorySessionStore,
25
+ MemoryTokenStore,
26
+ realClock
10
27
  };
@@ -8,6 +8,7 @@ class MemorySessionStore {
8
8
  #flows = new Map;
9
9
  #sessions = new Map;
10
10
  #par = new Map;
11
+ #scratch = new Map;
11
12
  constructor(opts = {}) {
12
13
  this.#clock = opts.clock ?? realClock;
13
14
  }
@@ -98,6 +99,28 @@ class MemorySessionStore {
98
99
  }
99
100
  return ok(stored.record);
100
101
  }
102
+ async saveScratch(key, value, ttlMs) {
103
+ if (ttlMs <= 0) {
104
+ return err(authError.internalError(`saveScratch: ttlMs must be positive, got ${ttlMs}`));
105
+ }
106
+ this.#scratch.set(key, { value, expiresAt: this.#clock() + ttlMs });
107
+ return ok(undefined);
108
+ }
109
+ async readScratch(key) {
110
+ const stored = this.#scratch.get(key);
111
+ if (!stored) {
112
+ return err(authError.unknownState(`scratch "${key}" unknown`));
113
+ }
114
+ if (this.#clock() >= stored.expiresAt) {
115
+ this.#scratch.delete(key);
116
+ return err(authError.unknownState(`scratch "${key}" expired`));
117
+ }
118
+ return ok(stored.value);
119
+ }
120
+ async deleteScratch(key) {
121
+ this.#scratch.delete(key);
122
+ return ok(undefined);
123
+ }
101
124
  }
102
125
  export {
103
126
  MemorySessionStore
@@ -16,6 +16,6 @@ function fromPGlite(db) {
16
16
  };
17
17
  }
18
18
  export {
19
- fromPostgresJs,
20
- fromPGlite
19
+ fromPGlite,
20
+ fromPostgresJs
21
21
  };
@@ -1,13 +1,36 @@
1
- export {
2
- migrate,
3
- fromPostgresJs,
1
+ // src/adapters/postgres/index.ts
2
+ import {
4
3
  fromPGlite,
5
- PostgresTokenStore,
6
- PostgresSessionStore,
7
- PostgresPasskeyCredentialStore,
8
- PostgresMethodStore,
9
- PostgresKeyStore,
10
- PostgresConfigStore,
4
+ fromPostgresJs
5
+ } from "./executor";
6
+ import { INITIAL_SCHEMA_SQL, migrate } from "./migrations";
7
+ import { PostgresAuditLog } from "./audit-log";
8
+ import {
9
+ PostgresConfigStore
10
+ } from "./config-store";
11
+ import { PostgresKeyStore } from "./key-store";
12
+ import {
13
+ PostgresMethodStore
14
+ } from "./method-store";
15
+ import {
16
+ PostgresSessionStore
17
+ } from "./session-store";
18
+ import {
19
+ PostgresTokenStore
20
+ } from "./token-store";
21
+ import {
22
+ PostgresPasskeyCredentialStore
23
+ } from "./passkey-credential-store";
24
+ export {
25
+ INITIAL_SCHEMA_SQL,
11
26
  PostgresAuditLog,
12
- INITIAL_SCHEMA_SQL
27
+ PostgresConfigStore,
28
+ PostgresKeyStore,
29
+ PostgresMethodStore,
30
+ PostgresPasskeyCredentialStore,
31
+ PostgresSessionStore,
32
+ PostgresTokenStore,
33
+ fromPGlite,
34
+ fromPostgresJs,
35
+ migrate
13
36
  };
@@ -75,6 +75,12 @@ CREATE TABLE IF NOT EXISTS openauth_sessions (
75
75
  expires_at bigint NOT NULL
76
76
  );
77
77
 
78
+ CREATE TABLE IF NOT EXISTS openauth_scratch (
79
+ scratch_key text PRIMARY KEY,
80
+ value text NOT NULL,
81
+ expires_at bigint NOT NULL
82
+ );
83
+
78
84
  CREATE TABLE IF NOT EXISTS openauth_audit_events (
79
85
  id bigserial PRIMARY KEY,
80
86
  ts bigint NOT NULL,
@@ -106,6 +112,6 @@ async function migrate(exec) {
106
112
  }
107
113
  }
108
114
  export {
109
- migrate,
110
- INITIAL_SCHEMA_SQL
115
+ INITIAL_SCHEMA_SQL,
116
+ migrate
111
117
  };
@@ -119,6 +119,48 @@ class PostgresSessionStore {
119
119
  }
120
120
  return ok(undefined);
121
121
  }
122
+ async saveScratch(key, value, ttlMs) {
123
+ if (ttlMs <= 0) {
124
+ return err(authError.internalError(`saveScratch: ttlMs must be positive, got ${ttlMs}`));
125
+ }
126
+ const expiresAt = this.#clock() + ttlMs;
127
+ try {
128
+ await this.#exec.query(`INSERT INTO openauth_scratch (scratch_key, value, expires_at)
129
+ VALUES ($1, $2, $3)
130
+ ON CONFLICT (scratch_key)
131
+ DO UPDATE SET value = EXCLUDED.value, expires_at = EXCLUDED.expires_at`, [key, value, expiresAt]);
132
+ } catch (e) {
133
+ return err(authError.internalError("saveScratch: upsert failed", e));
134
+ }
135
+ return ok(undefined);
136
+ }
137
+ async readScratch(key) {
138
+ let row;
139
+ try {
140
+ const result = await this.#exec.query(`SELECT value, expires_at FROM openauth_scratch WHERE scratch_key = $1`, [key]);
141
+ row = result.rows[0];
142
+ } catch (e) {
143
+ return err(authError.internalError("readScratch: query failed", e));
144
+ }
145
+ if (!row) {
146
+ return err(authError.unknownState(`scratch "${key}" unknown`));
147
+ }
148
+ if (this.#clock() >= Number(row.expires_at)) {
149
+ try {
150
+ await this.#exec.query(`DELETE FROM openauth_scratch WHERE scratch_key = $1`, [key]);
151
+ } catch {}
152
+ return err(authError.unknownState(`scratch "${key}" expired`));
153
+ }
154
+ return ok(row.value);
155
+ }
156
+ async deleteScratch(key) {
157
+ try {
158
+ await this.#exec.query(`DELETE FROM openauth_scratch WHERE scratch_key = $1`, [key]);
159
+ } catch (e) {
160
+ return err(authError.internalError("deleteScratch: delete failed", e));
161
+ }
162
+ return ok(undefined);
163
+ }
122
164
  }
123
165
  function parseFlowRecord(raw) {
124
166
  if (typeof raw === "string")
@@ -33,49 +33,49 @@ function createClient(input) {
33
33
  if (cached)
34
34
  return cached;
35
35
  const keyset = await (f || fetch)(wk.jwks_uri).then((r) => r.json());
36
- const result2 = createLocalJWKSet(keyset);
37
- jwksCache.set(issuer, result2);
38
- return result2;
36
+ const result = createLocalJWKSet(keyset);
37
+ jwksCache.set(issuer, result);
38
+ return result;
39
39
  }
40
40
  const result = {
41
41
  async authorize(redirectURI, response, opts) {
42
- const result2 = new URL(issuer + "/authorize");
42
+ const result = new URL(issuer + "/authorize");
43
43
  const challenge = {
44
44
  state: crypto.randomUUID()
45
45
  };
46
- result2.searchParams.set("client_id", input.clientID);
47
- result2.searchParams.set("redirect_uri", redirectURI);
48
- result2.searchParams.set("response_type", response);
49
- result2.searchParams.set("state", challenge.state);
46
+ result.searchParams.set("client_id", input.clientID);
47
+ result.searchParams.set("redirect_uri", redirectURI);
48
+ result.searchParams.set("response_type", response);
49
+ result.searchParams.set("state", challenge.state);
50
50
  if (opts?.provider)
51
- result2.searchParams.set("provider", opts.provider);
51
+ result.searchParams.set("provider", opts.provider);
52
52
  if (opts?.scope !== undefined) {
53
53
  const scope = Array.isArray(opts.scope) ? opts.scope.join(" ") : opts.scope;
54
54
  if (scope)
55
- result2.searchParams.set("scope", scope);
55
+ result.searchParams.set("scope", scope);
56
56
  }
57
57
  if (opts?.pkce && response === "code") {
58
58
  const pkce = await generatePKCE();
59
- result2.searchParams.set("code_challenge_method", "S256");
60
- result2.searchParams.set("code_challenge", pkce.challenge);
59
+ result.searchParams.set("code_challenge_method", "S256");
60
+ result.searchParams.set("code_challenge", pkce.challenge);
61
61
  challenge.verifier = pkce.verifier;
62
62
  }
63
63
  return {
64
64
  challenge,
65
- url: result2.toString()
65
+ url: result.toString()
66
66
  };
67
67
  },
68
68
  async pkce(redirectURI, opts) {
69
- const result2 = new URL(issuer + "/authorize");
69
+ const result = new URL(issuer + "/authorize");
70
70
  if (opts?.provider)
71
- result2.searchParams.set("provider", opts.provider);
72
- result2.searchParams.set("client_id", input.clientID);
73
- result2.searchParams.set("redirect_uri", redirectURI);
74
- result2.searchParams.set("response_type", "code");
71
+ result.searchParams.set("provider", opts.provider);
72
+ result.searchParams.set("client_id", input.clientID);
73
+ result.searchParams.set("redirect_uri", redirectURI);
74
+ result.searchParams.set("response_type", "code");
75
75
  const pkce = await generatePKCE();
76
- result2.searchParams.set("code_challenge_method", "S256");
77
- result2.searchParams.set("code_challenge", pkce.challenge);
78
- return [pkce.verifier, result2.toString()];
76
+ result.searchParams.set("code_challenge_method", "S256");
77
+ result.searchParams.set("code_challenge", pkce.challenge);
78
+ return [pkce.verifier, result.toString()];
79
79
  },
80
80
  async exchange(code, redirectURI, verifier) {
81
81
  const tokens = await f(issuer + "/token", {
@@ -150,18 +150,18 @@ function createClient(input) {
150
150
  async verify(subjects, token, options) {
151
151
  const jwks = await getJWKS();
152
152
  try {
153
- const result2 = await jwtVerify(token, jwks, {
153
+ const result = await jwtVerify(token, jwks, {
154
154
  issuer
155
155
  });
156
- const claim = result2.payload.claim;
156
+ const claim = result.payload.claim;
157
157
  let subjectType;
158
158
  let subjectProperties;
159
159
  if (claim && typeof claim.type === "string") {
160
160
  subjectType = claim.type;
161
161
  subjectProperties = claim.properties;
162
- } else if (result2.payload.mode === "access" && typeof result2.payload.type === "string") {
163
- subjectType = result2.payload.type;
164
- subjectProperties = result2.payload.properties;
162
+ } else if (result.payload.mode === "access" && typeof result.payload.type === "string") {
163
+ subjectType = result.payload.type;
164
+ subjectProperties = result.payload.properties;
165
165
  }
166
166
  if (subjectType === undefined) {
167
167
  return { err: new InvalidSubjectError };
@@ -175,7 +175,7 @@ function createClient(input) {
175
175
  return { err: new InvalidSubjectError };
176
176
  }
177
177
  return {
178
- aud: result2.payload.aud,
178
+ aud: result.payload.aud,
179
179
  subject: {
180
180
  type: subjectType,
181
181
  properties: validated.value
@@ -211,7 +211,7 @@ async function issueCodeFromInlineSuccess(result, record, deps) {
211
211
  });
212
212
  }
213
213
  export {
214
- startAuthorize,
214
+ AUTH_CODE_TTL_MS,
215
215
  DEFAULT_FLOW_TTL_MS,
216
- AUTH_CODE_TTL_MS
216
+ startAuthorize
217
217
  };