@better-auth/oauth-provider 1.7.0-beta.0 → 1.7.0-beta.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.
- package/dist/{client-assertion-DZqo-L5j.mjs → client-assertion-D-tAYsKC.mjs} +116 -92
- package/dist/client-resource.d.mts +43 -7
- package/dist/client-resource.mjs +45 -25
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +3 -13
- package/dist/index.d.mts +151 -18
- package/dist/index.mjs +2239 -1803
- package/dist/introspect-DvHp2a64.mjs +2507 -0
- package/dist/{oauth-Dh4YXCXY.d.mts → oauth-BrNRbP2A.d.mts} +532 -141
- package/dist/oauth-ScTJEcFV.d.mts +2849 -0
- package/dist/resource-challenge-B-cqv4ur.mjs +63 -0
- package/dist/rolldown-runtime-wcPFST8Q.mjs +13 -0
- package/dist/signed-query-Df1MNiSH.mjs +44 -0
- package/dist/utils-DO8lmoDw.mjs +769 -0
- package/dist/{version-BGWhjYBb.mjs → version-a5HhJg8A.mjs} +1 -1
- package/package.json +9 -10
- package/dist/mcp-CYnz-MXn.mjs +0 -56
- package/dist/oauth-C8aTlaAC.d.mts +0 -1645
- package/dist/utils-CIbcUsZ5.mjs +0 -417
|
@@ -0,0 +1,2849 @@
|
|
|
1
|
+
import * as z from "zod";
|
|
2
|
+
import { PrivateKeyJwtSigningAlgorithm } from "@better-auth/core/oauth2";
|
|
3
|
+
import { JWTPayload } from "jose";
|
|
4
|
+
import { JWSAlgorithms } from "better-auth/plugins";
|
|
5
|
+
import { InferOptionSchema, Session, User } from "better-auth/types";
|
|
6
|
+
import { GenericEndpointContext, LiteralString } from "@better-auth/core";
|
|
7
|
+
|
|
8
|
+
//#region src/schema.d.ts
|
|
9
|
+
declare const schema: {
|
|
10
|
+
oauthClient: {
|
|
11
|
+
modelName: string;
|
|
12
|
+
fields: {
|
|
13
|
+
clientId: {
|
|
14
|
+
type: "string";
|
|
15
|
+
unique: true;
|
|
16
|
+
required: true;
|
|
17
|
+
};
|
|
18
|
+
clientSecret: {
|
|
19
|
+
type: "string";
|
|
20
|
+
required: false;
|
|
21
|
+
};
|
|
22
|
+
disabled: {
|
|
23
|
+
type: "boolean";
|
|
24
|
+
defaultValue: false;
|
|
25
|
+
required: false;
|
|
26
|
+
};
|
|
27
|
+
skipConsent: {
|
|
28
|
+
type: "boolean";
|
|
29
|
+
required: false;
|
|
30
|
+
};
|
|
31
|
+
enableEndSession: {
|
|
32
|
+
type: "boolean";
|
|
33
|
+
required: false;
|
|
34
|
+
};
|
|
35
|
+
subjectType: {
|
|
36
|
+
type: "string";
|
|
37
|
+
required: false;
|
|
38
|
+
};
|
|
39
|
+
scopes: {
|
|
40
|
+
type: "string[]";
|
|
41
|
+
required: false;
|
|
42
|
+
};
|
|
43
|
+
userId: {
|
|
44
|
+
type: "string";
|
|
45
|
+
required: false;
|
|
46
|
+
references: {
|
|
47
|
+
model: string;
|
|
48
|
+
field: string;
|
|
49
|
+
};
|
|
50
|
+
index: true;
|
|
51
|
+
};
|
|
52
|
+
createdAt: {
|
|
53
|
+
type: "date";
|
|
54
|
+
required: false;
|
|
55
|
+
};
|
|
56
|
+
updatedAt: {
|
|
57
|
+
type: "date";
|
|
58
|
+
required: false;
|
|
59
|
+
};
|
|
60
|
+
name: {
|
|
61
|
+
type: "string";
|
|
62
|
+
required: false;
|
|
63
|
+
};
|
|
64
|
+
uri: {
|
|
65
|
+
type: "string";
|
|
66
|
+
required: false;
|
|
67
|
+
};
|
|
68
|
+
icon: {
|
|
69
|
+
type: "string";
|
|
70
|
+
required: false;
|
|
71
|
+
};
|
|
72
|
+
contacts: {
|
|
73
|
+
type: "string[]";
|
|
74
|
+
required: false;
|
|
75
|
+
};
|
|
76
|
+
tos: {
|
|
77
|
+
type: "string";
|
|
78
|
+
required: false;
|
|
79
|
+
};
|
|
80
|
+
policy: {
|
|
81
|
+
type: "string";
|
|
82
|
+
required: false;
|
|
83
|
+
};
|
|
84
|
+
softwareId: {
|
|
85
|
+
type: "string";
|
|
86
|
+
required: false;
|
|
87
|
+
};
|
|
88
|
+
softwareVersion: {
|
|
89
|
+
type: "string";
|
|
90
|
+
required: false;
|
|
91
|
+
};
|
|
92
|
+
softwareStatement: {
|
|
93
|
+
type: "string";
|
|
94
|
+
required: false;
|
|
95
|
+
};
|
|
96
|
+
redirectUris: {
|
|
97
|
+
type: "string[]";
|
|
98
|
+
required: true;
|
|
99
|
+
};
|
|
100
|
+
postLogoutRedirectUris: {
|
|
101
|
+
type: "string[]";
|
|
102
|
+
required: false;
|
|
103
|
+
};
|
|
104
|
+
backchannelLogoutUri: {
|
|
105
|
+
type: "string";
|
|
106
|
+
required: false;
|
|
107
|
+
};
|
|
108
|
+
backchannelLogoutSessionRequired: {
|
|
109
|
+
type: "boolean";
|
|
110
|
+
required: false;
|
|
111
|
+
};
|
|
112
|
+
tokenEndpointAuthMethod: {
|
|
113
|
+
type: "string";
|
|
114
|
+
required: false;
|
|
115
|
+
};
|
|
116
|
+
jwks: {
|
|
117
|
+
type: "string";
|
|
118
|
+
required: false;
|
|
119
|
+
};
|
|
120
|
+
jwksUri: {
|
|
121
|
+
type: "string";
|
|
122
|
+
required: false;
|
|
123
|
+
};
|
|
124
|
+
grantTypes: {
|
|
125
|
+
type: "string[]";
|
|
126
|
+
required: false;
|
|
127
|
+
};
|
|
128
|
+
responseTypes: {
|
|
129
|
+
type: "string[]";
|
|
130
|
+
required: false;
|
|
131
|
+
};
|
|
132
|
+
public: {
|
|
133
|
+
type: "boolean";
|
|
134
|
+
required: false;
|
|
135
|
+
};
|
|
136
|
+
type: {
|
|
137
|
+
type: "string";
|
|
138
|
+
required: false;
|
|
139
|
+
};
|
|
140
|
+
requirePKCE: {
|
|
141
|
+
type: "boolean";
|
|
142
|
+
required: false;
|
|
143
|
+
};
|
|
144
|
+
dpopBoundAccessTokens: {
|
|
145
|
+
type: "boolean";
|
|
146
|
+
required: false;
|
|
147
|
+
defaultValue: false;
|
|
148
|
+
};
|
|
149
|
+
referenceId: {
|
|
150
|
+
type: "string";
|
|
151
|
+
required: false;
|
|
152
|
+
};
|
|
153
|
+
metadata: {
|
|
154
|
+
type: "json";
|
|
155
|
+
required: false;
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* A protected resource the AS issues access tokens for.
|
|
161
|
+
*
|
|
162
|
+
* Promotes protected resources into a first-class persisted entity with
|
|
163
|
+
* per-resource token policy. A null value
|
|
164
|
+
* on any policy column means "inherit the plugin-level default at token
|
|
165
|
+
* issuance time" — admins can later override without re-seeding.
|
|
166
|
+
*
|
|
167
|
+
* @see RFC 8707 (Resource Indicators) — `identifier` is the `resource` parameter value
|
|
168
|
+
* @see RFC 9068 §2.2 — `customClaims` cannot override reserved JWT claims (enforced server-side)
|
|
169
|
+
*/
|
|
170
|
+
oauthResource: {
|
|
171
|
+
modelName: string;
|
|
172
|
+
fields: {
|
|
173
|
+
identifier: {
|
|
174
|
+
type: "string";
|
|
175
|
+
required: true;
|
|
176
|
+
unique: true;
|
|
177
|
+
};
|
|
178
|
+
name: {
|
|
179
|
+
type: "string";
|
|
180
|
+
required: true;
|
|
181
|
+
};
|
|
182
|
+
accessTokenTtl: {
|
|
183
|
+
type: "number";
|
|
184
|
+
required: false;
|
|
185
|
+
};
|
|
186
|
+
refreshTokenTtl: {
|
|
187
|
+
type: "number";
|
|
188
|
+
required: false;
|
|
189
|
+
};
|
|
190
|
+
signingAlgorithm: {
|
|
191
|
+
type: "string";
|
|
192
|
+
required: false;
|
|
193
|
+
};
|
|
194
|
+
signingKeyId: {
|
|
195
|
+
type: "string";
|
|
196
|
+
required: false;
|
|
197
|
+
};
|
|
198
|
+
allowedScopes: {
|
|
199
|
+
type: "string[]";
|
|
200
|
+
required: false;
|
|
201
|
+
};
|
|
202
|
+
customClaims: {
|
|
203
|
+
type: "json";
|
|
204
|
+
required: false;
|
|
205
|
+
};
|
|
206
|
+
dpopBoundAccessTokensRequired: {
|
|
207
|
+
type: "boolean";
|
|
208
|
+
required: false;
|
|
209
|
+
defaultValue: false;
|
|
210
|
+
};
|
|
211
|
+
disabled: {
|
|
212
|
+
type: "boolean";
|
|
213
|
+
required: false;
|
|
214
|
+
defaultValue: false;
|
|
215
|
+
};
|
|
216
|
+
createdAt: {
|
|
217
|
+
type: "date";
|
|
218
|
+
required: false;
|
|
219
|
+
};
|
|
220
|
+
updatedAt: {
|
|
221
|
+
type: "date";
|
|
222
|
+
required: false;
|
|
223
|
+
};
|
|
224
|
+
policyVersion: {
|
|
225
|
+
type: "number";
|
|
226
|
+
required: false;
|
|
227
|
+
defaultValue: number;
|
|
228
|
+
};
|
|
229
|
+
metadata: {
|
|
230
|
+
type: "json";
|
|
231
|
+
required: false;
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
/**
|
|
236
|
+
* Join table — which clients are allowed to request which resources.
|
|
237
|
+
*
|
|
238
|
+
* Authoritative only when `enforcePerClientResources: true` on plugin options.
|
|
239
|
+
* When the flag is off, clients implicitly have access to all enabled resources
|
|
240
|
+
* (preserves pre-entity behavior).
|
|
241
|
+
*
|
|
242
|
+
* Composite uniqueness on `(clientId, resourceId)` is load-bearing — the
|
|
243
|
+
* `enforcePerClientResources` linkage check assumes one row per pair.
|
|
244
|
+
*
|
|
245
|
+
* Better Auth's schema layer doesn't expose composite-UNIQUE syntax (no
|
|
246
|
+
* way to declare `UNIQUE(clientId, resourceId)` at the column level). To
|
|
247
|
+
* enforce it at the database level for free, we set the row's `id` to a
|
|
248
|
+
* deterministic `${clientId}::${resourceId}` value at write time and let
|
|
249
|
+
* the implicit `UNIQUE` constraint on the primary key catch duplicates
|
|
250
|
+
* (see `buildClientResourceLinkId` and the `forceAllowId: true` flag on
|
|
251
|
+
* the `adapter.create` call in `oauthResource/endpoints.ts`). The double
|
|
252
|
+
* colon separator is chosen because `::` cannot appear in either a
|
|
253
|
+
* client_id (URL-safe random string) or a resource identifier (RFC 8707
|
|
254
|
+
* absolute URI — `::` would be an IPv6 form rejected by the validator),
|
|
255
|
+
* so the encoding is collision-free.
|
|
256
|
+
*
|
|
257
|
+
* Concurrent inserts of the same pair surface as a UNIQUE-constraint
|
|
258
|
+
* error which the endpoint catches and converts to a 200 "alreadyLinked"
|
|
259
|
+
* response (idempotency).
|
|
260
|
+
*/
|
|
261
|
+
oauthClientResource: {
|
|
262
|
+
modelName: string;
|
|
263
|
+
fields: {
|
|
264
|
+
clientId: {
|
|
265
|
+
type: "string";
|
|
266
|
+
required: true;
|
|
267
|
+
references: {
|
|
268
|
+
model: string;
|
|
269
|
+
field: string;
|
|
270
|
+
onDelete: "cascade";
|
|
271
|
+
};
|
|
272
|
+
index: true;
|
|
273
|
+
};
|
|
274
|
+
resourceId: {
|
|
275
|
+
type: "string";
|
|
276
|
+
required: true;
|
|
277
|
+
references: {
|
|
278
|
+
model: string;
|
|
279
|
+
field: string;
|
|
280
|
+
onDelete: "cascade";
|
|
281
|
+
};
|
|
282
|
+
index: true;
|
|
283
|
+
};
|
|
284
|
+
metadata: {
|
|
285
|
+
type: "json";
|
|
286
|
+
required: false;
|
|
287
|
+
};
|
|
288
|
+
createdAt: {
|
|
289
|
+
type: "date";
|
|
290
|
+
required: false;
|
|
291
|
+
};
|
|
292
|
+
};
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* An opaque refresh token created with "offline_access"
|
|
296
|
+
*
|
|
297
|
+
* Refresh tokens are linked to a session.
|
|
298
|
+
*/
|
|
299
|
+
oauthRefreshToken: {
|
|
300
|
+
fields: {
|
|
301
|
+
token: {
|
|
302
|
+
type: "string";
|
|
303
|
+
required: true;
|
|
304
|
+
unique: true;
|
|
305
|
+
};
|
|
306
|
+
clientId: {
|
|
307
|
+
type: "string";
|
|
308
|
+
required: true;
|
|
309
|
+
references: {
|
|
310
|
+
model: string;
|
|
311
|
+
field: string;
|
|
312
|
+
};
|
|
313
|
+
index: true;
|
|
314
|
+
};
|
|
315
|
+
sessionId: {
|
|
316
|
+
type: "string";
|
|
317
|
+
required: false;
|
|
318
|
+
references: {
|
|
319
|
+
model: string;
|
|
320
|
+
field: string;
|
|
321
|
+
onDelete: "set null";
|
|
322
|
+
};
|
|
323
|
+
index: true;
|
|
324
|
+
};
|
|
325
|
+
userId: {
|
|
326
|
+
type: "string";
|
|
327
|
+
required: true;
|
|
328
|
+
references: {
|
|
329
|
+
model: string;
|
|
330
|
+
field: string;
|
|
331
|
+
};
|
|
332
|
+
index: true;
|
|
333
|
+
};
|
|
334
|
+
referenceId: {
|
|
335
|
+
type: "string";
|
|
336
|
+
required: false;
|
|
337
|
+
};
|
|
338
|
+
authorizationCodeId: {
|
|
339
|
+
type: "string";
|
|
340
|
+
required: false;
|
|
341
|
+
index: true;
|
|
342
|
+
};
|
|
343
|
+
resources: {
|
|
344
|
+
type: "string[]";
|
|
345
|
+
required: false;
|
|
346
|
+
};
|
|
347
|
+
requestedUserInfoClaims: {
|
|
348
|
+
type: "string[]";
|
|
349
|
+
required: false;
|
|
350
|
+
};
|
|
351
|
+
expiresAt: {
|
|
352
|
+
type: "date";
|
|
353
|
+
};
|
|
354
|
+
createdAt: {
|
|
355
|
+
type: "date";
|
|
356
|
+
};
|
|
357
|
+
revoked: {
|
|
358
|
+
type: "date";
|
|
359
|
+
required: false;
|
|
360
|
+
};
|
|
361
|
+
rotatedAt: {
|
|
362
|
+
type: "date";
|
|
363
|
+
required: false;
|
|
364
|
+
};
|
|
365
|
+
rotationReplayResponse: {
|
|
366
|
+
type: "string";
|
|
367
|
+
required: false;
|
|
368
|
+
};
|
|
369
|
+
rotationReplayExpiresAt: {
|
|
370
|
+
type: "date";
|
|
371
|
+
required: false;
|
|
372
|
+
};
|
|
373
|
+
authTime: {
|
|
374
|
+
type: "date";
|
|
375
|
+
required: false;
|
|
376
|
+
};
|
|
377
|
+
confirmation: {
|
|
378
|
+
type: "json";
|
|
379
|
+
required: false;
|
|
380
|
+
};
|
|
381
|
+
scopes: {
|
|
382
|
+
type: "string[]";
|
|
383
|
+
required: true;
|
|
384
|
+
};
|
|
385
|
+
};
|
|
386
|
+
};
|
|
387
|
+
/**
|
|
388
|
+
* An opaque access token sent when there is no resource audience claim
|
|
389
|
+
* to assigned to the JWT.
|
|
390
|
+
*
|
|
391
|
+
* Access tokens are linked to a session, better-auth
|
|
392
|
+
* authors SHALL always check for valid session!
|
|
393
|
+
*
|
|
394
|
+
* AccessTokens SHALL only be created at refresh,
|
|
395
|
+
* destroyed at revoke, and read at introspection.
|
|
396
|
+
* NEVER update an access token! Typically a refresh and
|
|
397
|
+
* revoke (if not expired) may want to occur at the same time.
|
|
398
|
+
*/
|
|
399
|
+
oauthAccessToken: {
|
|
400
|
+
modelName: string;
|
|
401
|
+
fields: {
|
|
402
|
+
token: {
|
|
403
|
+
type: "string";
|
|
404
|
+
unique: true;
|
|
405
|
+
};
|
|
406
|
+
clientId: {
|
|
407
|
+
type: "string";
|
|
408
|
+
required: true;
|
|
409
|
+
references: {
|
|
410
|
+
model: string;
|
|
411
|
+
field: string;
|
|
412
|
+
};
|
|
413
|
+
index: true;
|
|
414
|
+
};
|
|
415
|
+
sessionId: {
|
|
416
|
+
type: "string";
|
|
417
|
+
required: false;
|
|
418
|
+
references: {
|
|
419
|
+
model: string;
|
|
420
|
+
field: string;
|
|
421
|
+
onDelete: "set null";
|
|
422
|
+
};
|
|
423
|
+
index: true;
|
|
424
|
+
};
|
|
425
|
+
userId: {
|
|
426
|
+
type: "string";
|
|
427
|
+
required: false;
|
|
428
|
+
references: {
|
|
429
|
+
model: string;
|
|
430
|
+
field: string;
|
|
431
|
+
};
|
|
432
|
+
index: true;
|
|
433
|
+
};
|
|
434
|
+
referenceId: {
|
|
435
|
+
type: "string";
|
|
436
|
+
required: false;
|
|
437
|
+
};
|
|
438
|
+
authorizationCodeId: {
|
|
439
|
+
type: "string";
|
|
440
|
+
required: false;
|
|
441
|
+
index: true;
|
|
442
|
+
};
|
|
443
|
+
resources: {
|
|
444
|
+
type: "string[]";
|
|
445
|
+
required: false;
|
|
446
|
+
};
|
|
447
|
+
requestedUserInfoClaims: {
|
|
448
|
+
type: "string[]";
|
|
449
|
+
required: false;
|
|
450
|
+
};
|
|
451
|
+
refreshId: {
|
|
452
|
+
type: "string";
|
|
453
|
+
required: false;
|
|
454
|
+
references: {
|
|
455
|
+
model: string;
|
|
456
|
+
field: string;
|
|
457
|
+
};
|
|
458
|
+
index: true;
|
|
459
|
+
};
|
|
460
|
+
expiresAt: {
|
|
461
|
+
type: "date";
|
|
462
|
+
};
|
|
463
|
+
createdAt: {
|
|
464
|
+
type: "date";
|
|
465
|
+
};
|
|
466
|
+
revoked: {
|
|
467
|
+
type: "date";
|
|
468
|
+
required: false;
|
|
469
|
+
};
|
|
470
|
+
confirmation: {
|
|
471
|
+
type: "json";
|
|
472
|
+
required: false;
|
|
473
|
+
};
|
|
474
|
+
scopes: {
|
|
475
|
+
type: "string[]";
|
|
476
|
+
required: true;
|
|
477
|
+
};
|
|
478
|
+
};
|
|
479
|
+
};
|
|
480
|
+
oauthConsent: {
|
|
481
|
+
modelName: string;
|
|
482
|
+
fields: {
|
|
483
|
+
clientId: {
|
|
484
|
+
type: "string";
|
|
485
|
+
required: true;
|
|
486
|
+
references: {
|
|
487
|
+
model: string;
|
|
488
|
+
field: string;
|
|
489
|
+
};
|
|
490
|
+
index: true;
|
|
491
|
+
};
|
|
492
|
+
userId: {
|
|
493
|
+
type: "string";
|
|
494
|
+
required: false;
|
|
495
|
+
references: {
|
|
496
|
+
model: string;
|
|
497
|
+
field: string;
|
|
498
|
+
};
|
|
499
|
+
index: true;
|
|
500
|
+
};
|
|
501
|
+
referenceId: {
|
|
502
|
+
type: "string";
|
|
503
|
+
required: false;
|
|
504
|
+
};
|
|
505
|
+
resources: {
|
|
506
|
+
type: "string[]";
|
|
507
|
+
required: false;
|
|
508
|
+
};
|
|
509
|
+
requestedUserInfoClaims: {
|
|
510
|
+
type: "string[]";
|
|
511
|
+
required: false;
|
|
512
|
+
};
|
|
513
|
+
scopes: {
|
|
514
|
+
type: "string[]";
|
|
515
|
+
required: true;
|
|
516
|
+
};
|
|
517
|
+
createdAt: {
|
|
518
|
+
type: "date";
|
|
519
|
+
};
|
|
520
|
+
updatedAt: {
|
|
521
|
+
type: "date";
|
|
522
|
+
};
|
|
523
|
+
};
|
|
524
|
+
};
|
|
525
|
+
/**
|
|
526
|
+
* Single-use record for `private_key_jwt` client assertion `jti` values. The
|
|
527
|
+
* row id is a digest of the per-client assertion identifier, so a replayed or
|
|
528
|
+
* concurrent assertion collides on the primary key and the insert fails
|
|
529
|
+
* atomically on every adapter (SQL primary key, MongoDB `_id`), including
|
|
530
|
+
* across multiple server processes.
|
|
531
|
+
*
|
|
532
|
+
* A row keeps blocking its id until deleted; `expiresAt` marks when removal
|
|
533
|
+
* is safe, since the assertion it guards has expired and is rejected earlier.
|
|
534
|
+
* TODO: no scheduled job prunes expired rows yet; like the verification
|
|
535
|
+
* table, they accumulate until a deployment-level sweep removes them.
|
|
536
|
+
*/
|
|
537
|
+
oauthClientAssertion: {
|
|
538
|
+
modelName: string;
|
|
539
|
+
fields: {
|
|
540
|
+
expiresAt: {
|
|
541
|
+
type: "date";
|
|
542
|
+
required: true;
|
|
543
|
+
};
|
|
544
|
+
};
|
|
545
|
+
};
|
|
546
|
+
};
|
|
547
|
+
//#endregion
|
|
548
|
+
//#region src/types/helpers.d.ts
|
|
549
|
+
type Awaitable<T> = Promise<T> | T;
|
|
550
|
+
//#endregion
|
|
551
|
+
//#region src/types/zod.d.ts
|
|
552
|
+
/**
|
|
553
|
+
* Validates an RFC 8707 resource indicator. The value must be an absolute URI
|
|
554
|
+
* with no fragment (RFC 8707 §2). Unlike a redirect URI it is not restricted to
|
|
555
|
+
* HTTPS, because a resource server identifier may use any absolute URI scheme;
|
|
556
|
+
* configured OAuth resources are the authoritative control over
|
|
557
|
+
* which resources a token may target.
|
|
558
|
+
*/
|
|
559
|
+
declare const ResourceUriSchema: z.ZodString;
|
|
560
|
+
/**
|
|
561
|
+
* Request body accepted at `POST /oauth2/register` (RFC 7591 §2 client
|
|
562
|
+
* metadata). This is the single source of truth for the registration contract:
|
|
563
|
+
* the endpoint validates against it and {@link ClientRegistrationRequest} is
|
|
564
|
+
* inferred from it, so the type a `validateInitialAccessToken` callback receives
|
|
565
|
+
* always matches what is actually validated. `grant_types` and
|
|
566
|
+
* `token_endpoint_auth_method` are open strings because extensions can register
|
|
567
|
+
* custom values. Server-assigned fields (`client_id`, `client_secret`, the
|
|
568
|
+
* issued/expiry timestamps) and internal state (`disabled`, `reference_id`) are
|
|
569
|
+
* never part of a registration request.
|
|
570
|
+
*
|
|
571
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7591#section-2
|
|
572
|
+
*/
|
|
573
|
+
declare const clientRegistrationRequestSchema: z.ZodObject<{
|
|
574
|
+
redirect_uris: z.ZodOptional<z.ZodArray<z.ZodURL>>;
|
|
575
|
+
scope: z.ZodOptional<z.ZodString>;
|
|
576
|
+
client_name: z.ZodOptional<z.ZodString>;
|
|
577
|
+
client_uri: z.ZodOptional<z.ZodString>;
|
|
578
|
+
logo_uri: z.ZodOptional<z.ZodString>;
|
|
579
|
+
contacts: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
580
|
+
tos_uri: z.ZodOptional<z.ZodString>;
|
|
581
|
+
policy_uri: z.ZodOptional<z.ZodString>;
|
|
582
|
+
software_id: z.ZodOptional<z.ZodString>;
|
|
583
|
+
software_version: z.ZodOptional<z.ZodString>;
|
|
584
|
+
software_statement: z.ZodOptional<z.ZodString>;
|
|
585
|
+
post_logout_redirect_uris: z.ZodOptional<z.ZodArray<z.ZodURL>>;
|
|
586
|
+
backchannel_logout_uri: z.ZodOptional<z.ZodURL>;
|
|
587
|
+
backchannel_logout_session_required: z.ZodOptional<z.ZodBoolean>;
|
|
588
|
+
token_endpoint_auth_method: z.ZodOptional<z.ZodString>;
|
|
589
|
+
jwks: z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>, z.ZodObject<{
|
|
590
|
+
keys: z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
591
|
+
}, z.core.$strip>]>>;
|
|
592
|
+
jwks_uri: z.ZodOptional<z.ZodString>;
|
|
593
|
+
grant_types: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
594
|
+
response_types: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
595
|
+
code: "code";
|
|
596
|
+
}>>>;
|
|
597
|
+
type: z.ZodOptional<z.ZodEnum<{
|
|
598
|
+
web: "web";
|
|
599
|
+
native: "native";
|
|
600
|
+
"user-agent-based": "user-agent-based";
|
|
601
|
+
}>>;
|
|
602
|
+
subject_type: z.ZodOptional<z.ZodEnum<{
|
|
603
|
+
public: "public";
|
|
604
|
+
pairwise: "pairwise";
|
|
605
|
+
}>>;
|
|
606
|
+
dpop_bound_access_tokens: z.ZodOptional<z.ZodBoolean>;
|
|
607
|
+
resources: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
608
|
+
skip_consent: z.ZodOptional<z.ZodNever>;
|
|
609
|
+
}, z.core.$strip>;
|
|
610
|
+
/**
|
|
611
|
+
* Client metadata as submitted in an RFC 7591 §2 registration request, inferred
|
|
612
|
+
* from {@link clientRegistrationRequestSchema}. Every value is self-asserted by
|
|
613
|
+
* the caller (RFC 7591 §5) and is the raw request before registration defaults
|
|
614
|
+
* are applied, so a `validateInitialAccessToken` callback should treat it as
|
|
615
|
+
* untrusted and not assume defaulted fields are present.
|
|
616
|
+
*
|
|
617
|
+
* @see https://datatracker.ietf.org/doc/html/rfc7591#section-2
|
|
618
|
+
*/
|
|
619
|
+
type ClientRegistrationRequest = z.infer<typeof clientRegistrationRequestSchema>;
|
|
620
|
+
//#endregion
|
|
621
|
+
//#region src/types/index.d.ts
|
|
622
|
+
type StoreTokenType = "access_token" | "refresh_token" | "authorization_code" | (string & {});
|
|
623
|
+
type InternallySupportedScopes = "openid" | "profile" | "email" | "offline_access";
|
|
624
|
+
type Scope = LiteralString | InternallySupportedScopes;
|
|
625
|
+
type Prompt = "none" | "consent" | "login" | "create" | "select_account";
|
|
626
|
+
type AuthorizePrompt = Prompt | "login consent" | "select_account consent";
|
|
627
|
+
/**
|
|
628
|
+
* Describes how to resolve a `client_id` from an external source (a URL-based
|
|
629
|
+
* metadata document, a federated registry, an attestation header, etc.) and
|
|
630
|
+
* what fields that source contributes to discovery metadata.
|
|
631
|
+
*
|
|
632
|
+
* Plugins contribute one of these through
|
|
633
|
+
* {@link OAuthProviderExtension.clientDiscovery}. The host walks every
|
|
634
|
+
* configured entry in order and returns the first non-null `resolve()` result.
|
|
635
|
+
*/
|
|
636
|
+
interface ClientDiscovery {
|
|
637
|
+
/**
|
|
638
|
+
* Stable identifier used in error messages and diagnostics. Convention
|
|
639
|
+
* is to match the plugin id (for example `"cimd"`).
|
|
640
|
+
*/
|
|
641
|
+
readonly id: string;
|
|
642
|
+
/**
|
|
643
|
+
* Return `true` if this discovery handles the given `client_id`. Called
|
|
644
|
+
* on every `getClient()` lookup for every configured discovery, so keep
|
|
645
|
+
* it cheap and synchronous.
|
|
646
|
+
*/
|
|
647
|
+
matches: (clientId: string) => boolean;
|
|
648
|
+
/**
|
|
649
|
+
* Resolve a client when this discovery matches. Receives the existing DB
|
|
650
|
+
* record (or `null`) so an implementation can decide between creating,
|
|
651
|
+
* refreshing, or passing through to the database result.
|
|
652
|
+
*
|
|
653
|
+
* Return:
|
|
654
|
+
* - a client record: `getClient()` returns it (creation / refresh / takeover).
|
|
655
|
+
* - `null`: `getClient()` falls through to the next matching discovery
|
|
656
|
+
* or to the database record (if any).
|
|
657
|
+
*/
|
|
658
|
+
resolve: (ctx: GenericEndpointContext, clientId: string, existing: SchemaClient<Scope[]> | null) => Awaitable<SchemaClient<Scope[]> | null>;
|
|
659
|
+
/**
|
|
660
|
+
* Fields merged into `/.well-known/oauth-authorization-server` and
|
|
661
|
+
* `/.well-known/openid-configuration` responses. Useful for advertising
|
|
662
|
+
* RFC-registered discovery flags like
|
|
663
|
+
* `client_id_metadata_document_supported`.
|
|
664
|
+
*/
|
|
665
|
+
discoveryMetadata?: Record<string, unknown>;
|
|
666
|
+
}
|
|
667
|
+
interface OAuthAuthenticatedClient {
|
|
668
|
+
clientId: string;
|
|
669
|
+
client: SchemaClient<Scope[]>;
|
|
670
|
+
method?: TokenEndpointAuthMethod;
|
|
671
|
+
/**
|
|
672
|
+
* A sender-constraint the authentication step already proved (for example a
|
|
673
|
+
* wallet-instance key thumbprint). Pass it to `issueTokens` as
|
|
674
|
+
* {@link OAuthTokenIssueParams.confirmation} to bind the issued token to it.
|
|
675
|
+
* The authorization server writes this as token material and does not verify
|
|
676
|
+
* it again, so a strategy must set it only after proving possession.
|
|
677
|
+
*/
|
|
678
|
+
confirmation?: Confirmation;
|
|
679
|
+
}
|
|
680
|
+
interface OAuthClientAuthenticationRequest {
|
|
681
|
+
/**
|
|
682
|
+
* Scopes to validate against the registered client.
|
|
683
|
+
*/
|
|
684
|
+
scopes?: string[];
|
|
685
|
+
/**
|
|
686
|
+
* Set to `false` for public extension grants that only require client_id.
|
|
687
|
+
*
|
|
688
|
+
* @default true
|
|
689
|
+
*/
|
|
690
|
+
requireCredentials?: boolean;
|
|
691
|
+
}
|
|
692
|
+
interface OAuthTokenIssueParams {
|
|
693
|
+
client: SchemaClient<Scope[]>;
|
|
694
|
+
scopes: string[];
|
|
695
|
+
user?: User;
|
|
696
|
+
referenceId?: string;
|
|
697
|
+
sessionId?: string;
|
|
698
|
+
nonce?: string;
|
|
699
|
+
refreshToken?: OAuthRefreshToken<Scope[]> & {
|
|
700
|
+
id: string;
|
|
701
|
+
};
|
|
702
|
+
authTime?: Date;
|
|
703
|
+
verificationValue?: VerificationValue;
|
|
704
|
+
resources?: string[];
|
|
705
|
+
/** Full original authorized resources for the grant, used to seed refresh tokens. */
|
|
706
|
+
originalResources?: string[];
|
|
707
|
+
/**
|
|
708
|
+
* OIDC UserInfo claim names requested by the authorization request's
|
|
709
|
+
* `claims.userinfo` object. The authorization server persists these names so
|
|
710
|
+
* refresh-token rotation and opaque access tokens continue honoring the same
|
|
711
|
+
* UserInfo request contract.
|
|
712
|
+
*/
|
|
713
|
+
requestedUserInfoClaims?: string[];
|
|
714
|
+
/**
|
|
715
|
+
* Additional JWT access-token claims for this single issuance.
|
|
716
|
+
*
|
|
717
|
+
* JWT-only: these are baked into the signed token at mint. Opaque access
|
|
718
|
+
* tokens persist no per-issuance claims, so they do NOT reappear at
|
|
719
|
+
* introspection. A claim that must be visible at opaque-token introspection
|
|
720
|
+
* belongs in a grant-type-stable `claims.accessToken` contributor instead,
|
|
721
|
+
* which the introspection path re-derives. Reserved RFC 9068 claim names stay
|
|
722
|
+
* owned by the authorization server.
|
|
723
|
+
*/
|
|
724
|
+
accessTokenClaims?: Record<string, unknown>;
|
|
725
|
+
/**
|
|
726
|
+
* Additional ID-token claims for this single issuance. Additive: they cannot
|
|
727
|
+
* replace identity, authentication-context, or AS-owned claims.
|
|
728
|
+
*/
|
|
729
|
+
idTokenClaims?: Record<string, unknown>;
|
|
730
|
+
/**
|
|
731
|
+
* Additional fields for the token response envelope. Standard OAuth token
|
|
732
|
+
* response fields stay owned by the authorization server.
|
|
733
|
+
*/
|
|
734
|
+
tokenResponse?: Record<string, unknown>;
|
|
735
|
+
/**
|
|
736
|
+
* Sender-constraint to bind this issuance to (RFC 7800 `cnf`). When set, the
|
|
737
|
+
* issuer stamps it as the access token's `cnf` and derives `token_type` from
|
|
738
|
+
* it, instead of leaving the token a bearer token. Use it to carry a
|
|
739
|
+
* confirmation a client-auth strategy or an out-of-band flow already proved
|
|
740
|
+
* (see {@link OAuthAuthenticatedClient.confirmation}). `cnf` is AS-owned: it
|
|
741
|
+
* is stamped after, and cannot be overridden by, contributed claims.
|
|
742
|
+
*/
|
|
743
|
+
confirmation?: Confirmation;
|
|
744
|
+
}
|
|
745
|
+
interface OAuthTokenResponse {
|
|
746
|
+
access_token: string;
|
|
747
|
+
expires_in: number;
|
|
748
|
+
expires_at: number;
|
|
749
|
+
token_type: TokenType;
|
|
750
|
+
refresh_token: string | undefined;
|
|
751
|
+
scope: string;
|
|
752
|
+
id_token: string | undefined;
|
|
753
|
+
[key: string]: unknown;
|
|
754
|
+
}
|
|
755
|
+
type ActiveAccessTokenPayload = JWTPayload & {
|
|
756
|
+
active: true;
|
|
757
|
+
};
|
|
758
|
+
/**
|
|
759
|
+
* The OAuth Provider's server-side capability surface, bound to a request `ctx`.
|
|
760
|
+
* A grant handler receives one as `provider`; a companion plugin's own endpoint
|
|
761
|
+
* obtains one with `getOAuthProviderApi(ctx, opts, grantType?)`. The same object
|
|
762
|
+
* serves both, so issuance, client resolution, and token verification behave the
|
|
763
|
+
* same inside and outside a grant.
|
|
764
|
+
*/
|
|
765
|
+
interface OAuthProviderApi {
|
|
766
|
+
/**
|
|
767
|
+
* Resolves a registered client by id, consulting extension client-discovery
|
|
768
|
+
* sources. Returns `null` when no client matches.
|
|
769
|
+
*/
|
|
770
|
+
getClient: (clientId: string) => Awaitable<SchemaClient<Scope[]> | null>;
|
|
771
|
+
/**
|
|
772
|
+
* Authenticates the calling client from the request (client secret, assertion,
|
|
773
|
+
* or none). For assertion-based methods, the RFC 7523 audience is bound to the
|
|
774
|
+
* endpoint serving the request, so an assertion cannot be replayed across
|
|
775
|
+
* endpoints. Returns the authenticated client, plus any `confirmation` an
|
|
776
|
+
* assertion strategy proved.
|
|
777
|
+
*/
|
|
778
|
+
authenticateClient: (request?: OAuthClientAuthenticationRequest) => Awaitable<OAuthAuthenticatedClient>;
|
|
779
|
+
/**
|
|
780
|
+
* Issues the token set for this grant (access token, optional refresh token,
|
|
781
|
+
* optional ID token, resource policy, response envelope, and any
|
|
782
|
+
* sender-constraint). The grant type is fixed by the `getOAuthProviderApi`
|
|
783
|
+
* binding (the dispatcher's grant for an in-grant handler, the caller's grant
|
|
784
|
+
* for an out-of-grant endpoint), so it cannot be mislabeled per issuance.
|
|
785
|
+
*
|
|
786
|
+
* Authorization is the caller's responsibility. The authorization server does
|
|
787
|
+
* NOT re-check that `params.scopes`, `params.user`, or `params.resources` are
|
|
788
|
+
* a subset of what `authenticateClient` validated: this is a raw minting
|
|
789
|
+
* primitive, and the built-in grants each validate scopes themselves before
|
|
790
|
+
* calling it.
|
|
791
|
+
*/
|
|
792
|
+
issueTokens: (params: OAuthTokenIssueParams) => Awaitable<OAuthTokenResponse>;
|
|
793
|
+
/**
|
|
794
|
+
* Computes the stored lookup key for a token value (the same hash the
|
|
795
|
+
* provider persists), so a caller can find or revoke a previously issued
|
|
796
|
+
* opaque token by its value.
|
|
797
|
+
*/
|
|
798
|
+
hashToken: (token: string, type: StoreTokenType) => Awaitable<string>;
|
|
799
|
+
/**
|
|
800
|
+
* Validates an access token for introspection-style callers. The returned
|
|
801
|
+
* payload can be inactive; protected-resource endpoints should use
|
|
802
|
+
* `requireActiveAccessToken`.
|
|
803
|
+
*/
|
|
804
|
+
validateAccessToken: (token: string, clientId?: string) => Awaitable<JWTPayload>;
|
|
805
|
+
/**
|
|
806
|
+
* Validates an access token for a protected resource and throws the OAuth
|
|
807
|
+
* bearer challenge when the token is inactive or unknown.
|
|
808
|
+
*/
|
|
809
|
+
requireActiveAccessToken: (token: string, clientId?: string) => Awaitable<ActiveAccessTokenPayload>;
|
|
810
|
+
}
|
|
811
|
+
interface OAuthExtensionGrantHandlerInput {
|
|
812
|
+
ctx: GenericEndpointContext;
|
|
813
|
+
opts: OAuthOptions<Scope[]>;
|
|
814
|
+
grantType: GrantType;
|
|
815
|
+
/** The provider capability surface, pre-bound to this grant's `grantType`. */
|
|
816
|
+
provider: OAuthProviderApi;
|
|
817
|
+
}
|
|
818
|
+
type OAuthExtensionGrantHandler = (input: OAuthExtensionGrantHandlerInput) => Awaitable<OAuthTokenResponse>;
|
|
819
|
+
interface OAuthClientAuthenticationInput {
|
|
820
|
+
ctx: GenericEndpointContext;
|
|
821
|
+
opts: OAuthOptions<Scope[]>;
|
|
822
|
+
assertion: string;
|
|
823
|
+
assertionType: string;
|
|
824
|
+
clientId?: string;
|
|
825
|
+
/**
|
|
826
|
+
* The endpoint URL the assertion was presented to. A strategy MUST bind the
|
|
827
|
+
* assertion to this audience (see {@link OAuthClientAuthenticationStrategy.authenticate}).
|
|
828
|
+
*/
|
|
829
|
+
expectedAudience?: string;
|
|
830
|
+
}
|
|
831
|
+
interface OAuthClientAuthenticationResult {
|
|
832
|
+
/** The client id the assertion proved the caller controls. */
|
|
833
|
+
clientId: string;
|
|
834
|
+
/**
|
|
835
|
+
* A sender-constraint the strategy proved (for example a wallet-instance key
|
|
836
|
+
* thumbprint). The provider stamps it as the issued token's RFC 7800 `cnf`.
|
|
837
|
+
* Set it only after proving possession; the authorization server writes it as
|
|
838
|
+
* token material and does not verify it again.
|
|
839
|
+
*/
|
|
840
|
+
confirmation?: Confirmation;
|
|
841
|
+
}
|
|
842
|
+
interface OAuthClientAuthenticationStrategy {
|
|
843
|
+
/**
|
|
844
|
+
* Assertion type URIs this strategy consumes from `client_assertion_type`.
|
|
845
|
+
* Values must be absolute URIs per RFC 7521. When omitted, the strategy key
|
|
846
|
+
* in `OAuthProviderExtension.clientAuthentication` is used and must also be
|
|
847
|
+
* an absolute URI.
|
|
848
|
+
*/
|
|
849
|
+
assertionTypes?: string[];
|
|
850
|
+
/**
|
|
851
|
+
* Verifies the presented assertion and returns the proven client id (plus any
|
|
852
|
+
* sender-constraint it established). The strategy proves the caller controls
|
|
853
|
+
* `clientId`; it does not supply the authorization record. The provider
|
|
854
|
+
* resolves and authorizes the client itself, so a strategy cannot influence
|
|
855
|
+
* the client's grants, scopes, or enabled state.
|
|
856
|
+
*
|
|
857
|
+
* The strategy owns the full RFC 7521/7523 verification. After verifying the
|
|
858
|
+
* signature against its own key source, it MUST enforce the assertion-hygiene
|
|
859
|
+
* checks the built-in `private_key_jwt` path enforces, or the provider will
|
|
860
|
+
* accept a forged or replayed assertion:
|
|
861
|
+
* - bind the assertion to `input.expectedAudience` (RFC 7523 §3 rule 3),
|
|
862
|
+
* - require a bounded `exp` (RFC 7523 §3 rule 4),
|
|
863
|
+
* - reject replays via a single-use `jti`.
|
|
864
|
+
*
|
|
865
|
+
* The exported `consumeClientAssertion` helper performs the audience,
|
|
866
|
+
* lifetime, and `jti` single-use checks for a decoded payload; call it after
|
|
867
|
+
* signature verification so an extension method inherits the same guarantees
|
|
868
|
+
* as `private_key_jwt`.
|
|
869
|
+
*/
|
|
870
|
+
authenticate: (input: OAuthClientAuthenticationInput) => Awaitable<OAuthClientAuthenticationResult>;
|
|
871
|
+
}
|
|
872
|
+
interface OAuthMetadataExtensionInput {
|
|
873
|
+
ctx: GenericEndpointContext;
|
|
874
|
+
opts: OAuthOptions<Scope[]>;
|
|
875
|
+
type: "oauth-authorization-server" | "openid-configuration";
|
|
876
|
+
/**
|
|
877
|
+
* The discovery document the provider assembled (core authorization-server
|
|
878
|
+
* fields plus any client-discovery metadata). Contributions from other
|
|
879
|
+
* extensions are merged afterwards and are not reflected here, so a
|
|
880
|
+
* contributor decides what to add from provider state alone, independent of
|
|
881
|
+
* extension registration order. The contributor returns the fields to add.
|
|
882
|
+
*/
|
|
883
|
+
document: AuthServerMetadata | OIDCMetadata;
|
|
884
|
+
}
|
|
885
|
+
interface OAuthClaimExtensionInput {
|
|
886
|
+
ctx: GenericEndpointContext;
|
|
887
|
+
opts: OAuthOptions<Scope[]>;
|
|
888
|
+
user?: (User & Record<string, unknown>) | null;
|
|
889
|
+
client: SchemaClient<Scope[]>;
|
|
890
|
+
scopes: string[];
|
|
891
|
+
grantType?: GrantType;
|
|
892
|
+
referenceId?: string;
|
|
893
|
+
/**
|
|
894
|
+
* Session the tokens are issued for, when one is available. Best-effort:
|
|
895
|
+
* set on the session-backed grants (authorization_code, refresh_token),
|
|
896
|
+
* undefined otherwise (client_credentials, introspection, or a session that
|
|
897
|
+
* was deleted or unlinked). Treat as possibly undefined.
|
|
898
|
+
*/
|
|
899
|
+
sessionId?: string;
|
|
900
|
+
resources?: string[];
|
|
901
|
+
/** Parsed client metadata, as returned by `parseClientMetadata`. */
|
|
902
|
+
metadata?: Record<string, unknown>;
|
|
903
|
+
}
|
|
904
|
+
interface OAuthUserInfoExtensionInput {
|
|
905
|
+
ctx: GenericEndpointContext;
|
|
906
|
+
opts: OAuthOptions<Scope[]>;
|
|
907
|
+
user: User & Record<string, unknown>;
|
|
908
|
+
scopes: string[];
|
|
909
|
+
jwt: JWTPayload;
|
|
910
|
+
client?: SchemaClient<Scope[]>;
|
|
911
|
+
/**
|
|
912
|
+
* Claim names explicitly requested through the OIDC `claims.userinfo`
|
|
913
|
+
* authorization request parameter.
|
|
914
|
+
*/
|
|
915
|
+
requestedClaims: string[];
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* What a companion plugin contributes to the OAuth Provider, registered through
|
|
919
|
+
* `extendOAuthProvider(ctx, extension)` (or the `oauthProvider({ extensions })`
|
|
920
|
+
* option).
|
|
921
|
+
*
|
|
922
|
+
* All five kinds live on one object so a single protocol plugin (for example
|
|
923
|
+
* RFC 8693 token exchange, which adds a grant, advertises metadata, and emits
|
|
924
|
+
* claims) registers atomically and the host validates the combined surface in
|
|
925
|
+
* one place. Every field is independently optional, so a single-concern plugin
|
|
926
|
+
* (such as `@better-auth/cimd`, which contributes only `clientDiscovery`) sets
|
|
927
|
+
* just the one it needs. This is the shape every future OAuth RFC plugin copies.
|
|
928
|
+
*
|
|
929
|
+
* Two contribution disciplines:
|
|
930
|
+
* - Dispatched kinds (`grants`, `clientAuthentication`) must be disjoint across
|
|
931
|
+
* extensions: registering a grant type, auth method, or assertion type that
|
|
932
|
+
* another extension already registered is rejected at setup, since the second
|
|
933
|
+
* would otherwise be silently unreachable.
|
|
934
|
+
* - Additive kinds (`metadata`, `claims`) never override authorization-server
|
|
935
|
+
* core; a key already owned by the provider is kept, and a key two extensions
|
|
936
|
+
* both contribute resolves to the first-registered extension.
|
|
937
|
+
*/
|
|
938
|
+
interface OAuthProviderExtension {
|
|
939
|
+
/**
|
|
940
|
+
* Token grants keyed by absolute-URI `grant_type`. The token endpoint
|
|
941
|
+
* dispatches a matching `grant_type` to the handler, which authenticates the
|
|
942
|
+
* client and issues tokens through the shared `provider`.
|
|
943
|
+
*/
|
|
944
|
+
grants?: Record<string, OAuthExtensionGrantHandler>;
|
|
945
|
+
/**
|
|
946
|
+
* Assertion-based client authentication, keyed by the advertised
|
|
947
|
+
* `token_endpoint_auth_method`. Consumes the matching `client_assertion_type`
|
|
948
|
+
* at the token, introspection, and revocation endpoints. Built-in method
|
|
949
|
+
* names (`client_secret_basic`/`_post`, `private_key_jwt`, `none`) are
|
|
950
|
+
* reserved.
|
|
951
|
+
*/
|
|
952
|
+
clientAuthentication?: Record<string, OAuthClientAuthenticationStrategy>;
|
|
953
|
+
/**
|
|
954
|
+
* Additional discovery metadata fields. Core fields (`issuer`,
|
|
955
|
+
* `token_endpoint`, advertised grants and auth methods, ...) stay owned by
|
|
956
|
+
* the provider; only absent keys are added. To advertise the claim names a
|
|
957
|
+
* claims contributor emits, set `advertisedMetadata.claims_supported`: the
|
|
958
|
+
* provider owns `claims_supported` and does not infer it from contributors.
|
|
959
|
+
*/
|
|
960
|
+
metadata?: (input: OAuthMetadataExtensionInput) => Record<string, unknown>;
|
|
961
|
+
/**
|
|
962
|
+
* Additional claims for access tokens, ID tokens, and the UserInfo response.
|
|
963
|
+
* Strictly additive: a contributor can add new claims but never replace an
|
|
964
|
+
* identity, authentication-context, reserved RFC 9068, or other AS-owned
|
|
965
|
+
* claim. Access-token claims are re-derived at opaque-token introspection, so
|
|
966
|
+
* they must be grant-type-stable (a contributor receives `grantType:
|
|
967
|
+
* undefined` there). See the claim-authority overview in the docs for the
|
|
968
|
+
* full per-token precedence ladder.
|
|
969
|
+
*/
|
|
970
|
+
claims?: {
|
|
971
|
+
accessToken?: (input: OAuthClaimExtensionInput) => Awaitable<Record<string, unknown>>;
|
|
972
|
+
idToken?: (input: OAuthClaimExtensionInput) => Awaitable<Record<string, unknown>>;
|
|
973
|
+
userInfo?: (input: OAuthUserInfoExtensionInput) => Awaitable<Record<string, unknown>>;
|
|
974
|
+
};
|
|
975
|
+
/**
|
|
976
|
+
* Client-id resolution sources consulted by `getClient()`, plus the
|
|
977
|
+
* discovery-metadata fields they advertise. Entries across all extensions
|
|
978
|
+
* run in order; the first to return a client wins. A plugin that resolves
|
|
979
|
+
* clients from an external source (a metadata-document URL, a federated
|
|
980
|
+
* registry, an attestation header) contributes it here.
|
|
981
|
+
*/
|
|
982
|
+
clientDiscovery?: ClientDiscovery | ClientDiscovery[];
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Result of authorizing an RFC 7591 initial access token, returned by
|
|
986
|
+
* {@link OAuthOptions.validateInitialAccessToken}.
|
|
987
|
+
*/
|
|
988
|
+
interface InitialAccessTokenAuthorization {
|
|
989
|
+
/**
|
|
990
|
+
* Ownership reference to attach to the created OAuth client.
|
|
991
|
+
*
|
|
992
|
+
* Associates machine-provisioned clients with an organization, team, tenant,
|
|
993
|
+
* or other application-level owner. Omit to create an unowned client (the
|
|
994
|
+
* client is stored with neither a `user_id` nor a `reference_id`).
|
|
995
|
+
*/
|
|
996
|
+
referenceId?: string;
|
|
997
|
+
}
|
|
998
|
+
interface OAuthOptions<Scopes extends readonly Scope[] = InternallySupportedScopes[]> {
|
|
999
|
+
/**
|
|
1000
|
+
* Custom schema definitions
|
|
1001
|
+
*/
|
|
1002
|
+
schema?: InferOptionSchema<typeof schema>;
|
|
1003
|
+
/**
|
|
1004
|
+
* The scopes that the client is allowed to request.
|
|
1005
|
+
* Must contain "openid" to be considered an OIDC server,
|
|
1006
|
+
* otherwise it is just an OAuth server.
|
|
1007
|
+
*
|
|
1008
|
+
* @see https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims
|
|
1009
|
+
* @default
|
|
1010
|
+
* ```ts
|
|
1011
|
+
* ["openid", "profile", "email", "offline_access"]
|
|
1012
|
+
* ```
|
|
1013
|
+
*/
|
|
1014
|
+
scopes?: Scopes;
|
|
1015
|
+
/**
|
|
1016
|
+
* Protected resources the AS issues access tokens for. Promotes the
|
|
1017
|
+
* resource model into a first-class persisted entity with per-resource
|
|
1018
|
+
* token policy.
|
|
1019
|
+
*
|
|
1020
|
+
* - String form: each string becomes an `oauthResource` row using plugin-level
|
|
1021
|
+
* defaults.
|
|
1022
|
+
* - Object form: explicit per-resource policy (TTL, signing alg, scope
|
|
1023
|
+
* allowlist, custom claims, sender-constraint requirements).
|
|
1024
|
+
*
|
|
1025
|
+
* Seeding is keyed by `identifier`. Behavior on re-seed is controlled by
|
|
1026
|
+
* {@link OAuthOptions.resourceSeedMode}.
|
|
1027
|
+
*
|
|
1028
|
+
* @see RFC 8707 — `identifier` is the `resource` parameter value
|
|
1029
|
+
* @example
|
|
1030
|
+
* ```ts
|
|
1031
|
+
* resources: [
|
|
1032
|
+
* { identifier: "https://api.example.com/admin", accessTokenTtl: 300,
|
|
1033
|
+
* allowedScopes: ["admin:read", "admin:write"] },
|
|
1034
|
+
* "https://api.example.com/public",
|
|
1035
|
+
* ]
|
|
1036
|
+
* ```
|
|
1037
|
+
*/
|
|
1038
|
+
resources?: Array<string | OAuthResourceInput>;
|
|
1039
|
+
/**
|
|
1040
|
+
* Controls whether boot-time `resources` config overwrites DB-edited rows.
|
|
1041
|
+
*
|
|
1042
|
+
* - `"insertOnly"` (default, safe): only inserts rows whose `identifier` is
|
|
1043
|
+
* not already present. Existing rows are untouched — admin edits via CRUD
|
|
1044
|
+
* are never reverted on restart.
|
|
1045
|
+
* - `"merge"`: inserts missing rows; updates only fields present in the
|
|
1046
|
+
* config object for existing rows.
|
|
1047
|
+
* - `"overwrite"`: inserts missing rows; replaces existing rows with the
|
|
1048
|
+
* config values. Use only when the config is the source of truth.
|
|
1049
|
+
*
|
|
1050
|
+
* Defaults to the safe option to prevent accidental policy reverts in
|
|
1051
|
+
* production deployments.
|
|
1052
|
+
*
|
|
1053
|
+
* @default "insertOnly"
|
|
1054
|
+
*/
|
|
1055
|
+
resourceSeedMode?: "insertOnly" | "merge" | "overwrite";
|
|
1056
|
+
/**
|
|
1057
|
+
* Opt-in cache membership for resources by `identifier`. Mirrors the
|
|
1058
|
+
* {@link OAuthOptions.cachedTrustedClients} pattern.
|
|
1059
|
+
*
|
|
1060
|
+
* Cached resources are invalidated on every CRUD write. Resources not in
|
|
1061
|
+
* this set are looked up from the DB on every request — the safe default
|
|
1062
|
+
* when admins edit rows through external tooling.
|
|
1063
|
+
*/
|
|
1064
|
+
cachedResources?: Set<string>;
|
|
1065
|
+
/**
|
|
1066
|
+
* When true, `/oauth2/token` and `/oauth2/authorize` require the client to be
|
|
1067
|
+
* linked to every requested resource via `oauthClientResource`. When false,
|
|
1068
|
+
* clients implicitly have access to all enabled resources.
|
|
1069
|
+
*
|
|
1070
|
+
* Defaults to `true`, enabling per-client validation per RFC 8707 §3. An
|
|
1071
|
+
* explicit `false` keeps all enabled resources requestable by any client.
|
|
1072
|
+
*
|
|
1073
|
+
* The resolved value is logged at plugin init so admins see which default
|
|
1074
|
+
* applied.
|
|
1075
|
+
*/
|
|
1076
|
+
enforcePerClientResources?: boolean;
|
|
1077
|
+
/**
|
|
1078
|
+
* Customize how a resource `identifier` is validated when resources are
|
|
1079
|
+
* created via CRUD or DCR. The default rejects non-URI identifiers per
|
|
1080
|
+
* RFC 8707 §2 (absolute URI, no fragment). Override only for trusted
|
|
1081
|
+
* internal use cases.
|
|
1082
|
+
*
|
|
1083
|
+
* @default RFC 8707 strict URI validator
|
|
1084
|
+
*/
|
|
1085
|
+
identifierValidator?: (identifier: string) => Awaitable<boolean>;
|
|
1086
|
+
/**
|
|
1087
|
+
* RBAC on OAuth resources. Mirrors {@link OAuthOptions.clientPrivileges}.
|
|
1088
|
+
*
|
|
1089
|
+
* Gates the admin resource CRUD endpoints. Return `false` (or `undefined`)
|
|
1090
|
+
* to deny the action.
|
|
1091
|
+
*/
|
|
1092
|
+
resourcePrivileges?: (context: {
|
|
1093
|
+
headers: Headers;
|
|
1094
|
+
action: "create" | "read" | "update" | "delete" | "list" | "link" | "unlink";
|
|
1095
|
+
user?: User & Record<string, unknown>;
|
|
1096
|
+
session?: Session & Record<string, unknown>;
|
|
1097
|
+
resourceId?: string;
|
|
1098
|
+
}) => Awaitable<boolean | undefined>;
|
|
1099
|
+
/**
|
|
1100
|
+
* Automatically cache trusted clients by client_id.
|
|
1101
|
+
* Clients are cached at request.
|
|
1102
|
+
*
|
|
1103
|
+
* Additionally, cached trusted clients are immutable
|
|
1104
|
+
* through the CRUD endpoints.
|
|
1105
|
+
*/
|
|
1106
|
+
cachedTrustedClients?: Set<string>;
|
|
1107
|
+
/**
|
|
1108
|
+
* The amount of time in seconds that the access token is valid for.
|
|
1109
|
+
*
|
|
1110
|
+
* @default 3600 (1 hour) - Industry standard
|
|
1111
|
+
*/
|
|
1112
|
+
accessTokenExpiresIn?: number;
|
|
1113
|
+
/**
|
|
1114
|
+
* The amount of time in seconds that a client
|
|
1115
|
+
* credentials grant access token is valid for.
|
|
1116
|
+
*
|
|
1117
|
+
* @default 3600 (1 hour)
|
|
1118
|
+
*/
|
|
1119
|
+
m2mAccessTokenExpiresIn?: number;
|
|
1120
|
+
/**
|
|
1121
|
+
* The amount of time in seconds that id token is valid for.
|
|
1122
|
+
*
|
|
1123
|
+
* @default 36000 (10 hours) - Recommended by the OIDC spec
|
|
1124
|
+
*/
|
|
1125
|
+
idTokenExpiresIn?: number;
|
|
1126
|
+
/**
|
|
1127
|
+
* The amount of time in seconds that the refresh token is valid for.
|
|
1128
|
+
* Typical industry standard is 30 days
|
|
1129
|
+
*
|
|
1130
|
+
* @default 2592000 (30 days)
|
|
1131
|
+
*/
|
|
1132
|
+
refreshTokenExpiresIn?: number;
|
|
1133
|
+
/**
|
|
1134
|
+
* Seconds that a rotated refresh token can be reused to receive the same
|
|
1135
|
+
* token response for the same effective scopes, requested resources, and
|
|
1136
|
+
* sender constraint.
|
|
1137
|
+
*
|
|
1138
|
+
* Matching reuse inside this interval is treated as refresh-response replay,
|
|
1139
|
+
* not refresh-token replay. Set to `0` to treat any rotated refresh token
|
|
1140
|
+
* reuse as replay.
|
|
1141
|
+
*
|
|
1142
|
+
* @default 0
|
|
1143
|
+
*/
|
|
1144
|
+
refreshTokenReuseInterval?: number;
|
|
1145
|
+
/**
|
|
1146
|
+
* The amount of time in seconds that the authorization code is valid for.
|
|
1147
|
+
*
|
|
1148
|
+
* @default 600 (10 minutes) - Recommended by the OIDC spec
|
|
1149
|
+
*/
|
|
1150
|
+
codeExpiresIn?: number;
|
|
1151
|
+
/**
|
|
1152
|
+
* Create access token expirations based on scope.
|
|
1153
|
+
*
|
|
1154
|
+
* This is useful for higher-privilege scopes that
|
|
1155
|
+
* require shorter expiration times. The earliest
|
|
1156
|
+
* expiration will take precedence. If not specified,
|
|
1157
|
+
* the default will take place.
|
|
1158
|
+
*
|
|
1159
|
+
* Note: values should be lower than the defaults
|
|
1160
|
+
* `accessTokenExpiresIn` and `m2mAccessTokenExpiresIn`
|
|
1161
|
+
*
|
|
1162
|
+
* @example
|
|
1163
|
+
* { "write:payments": "5m", "read:payments": "30m" }
|
|
1164
|
+
*/
|
|
1165
|
+
scopeExpirations?: { [K in Scopes[number]]?: number | string | Date };
|
|
1166
|
+
/**
|
|
1167
|
+
* Maximum lifetime in seconds for client assertion JWTs
|
|
1168
|
+
* used with `private_key_jwt` authentication.
|
|
1169
|
+
*
|
|
1170
|
+
* @default 300 (5 minutes)
|
|
1171
|
+
*/
|
|
1172
|
+
assertionMaxLifetime?: number;
|
|
1173
|
+
/**
|
|
1174
|
+
* Allows /oauth2/public-client-prelogin endpoint to be
|
|
1175
|
+
* requestable prior to login via a valid oauth_query.
|
|
1176
|
+
*/
|
|
1177
|
+
allowPublicClientPrelogin?: boolean;
|
|
1178
|
+
/**
|
|
1179
|
+
* Allow unauthenticated dynamic client registration.
|
|
1180
|
+
*
|
|
1181
|
+
* When enabled, the `/oauth2/register` endpoint accepts requests
|
|
1182
|
+
* without a session. Public clients use
|
|
1183
|
+
* `token_endpoint_auth_method: "none"`; confidential clients receive a
|
|
1184
|
+
* one-time `client_secret` in the registration response.
|
|
1185
|
+
*
|
|
1186
|
+
* For verified client discovery (MCP), consider installing the
|
|
1187
|
+
* `@better-auth/cimd` plugin, which verifies client identity through
|
|
1188
|
+
* domain ownership via Client ID Metadata Documents.
|
|
1189
|
+
*
|
|
1190
|
+
* @default false
|
|
1191
|
+
*/
|
|
1192
|
+
allowUnauthenticatedClientRegistration?: boolean;
|
|
1193
|
+
/**
|
|
1194
|
+
* Allow dynamic client registration (RFC 7591) at `POST /oauth2/register`.
|
|
1195
|
+
*
|
|
1196
|
+
* Once enabled, a registration request is authorized through one of three
|
|
1197
|
+
* modes:
|
|
1198
|
+
* - session-backed: a logged-in user with client-create privileges.
|
|
1199
|
+
* - token-backed: a valid initial access token, when
|
|
1200
|
+
* {@link OAuthOptions.validateInitialAccessToken} is defined.
|
|
1201
|
+
* - open: unauthenticated registration, when
|
|
1202
|
+
* {@link OAuthOptions.allowUnauthenticatedClientRegistration}
|
|
1203
|
+
* is enabled.
|
|
1204
|
+
*
|
|
1205
|
+
* @default false
|
|
1206
|
+
*/
|
|
1207
|
+
allowDynamicClientRegistration?: boolean;
|
|
1208
|
+
/**
|
|
1209
|
+
* Validates an RFC 7591 initial access token for protected dynamic client
|
|
1210
|
+
* registration, read from the `Authorization: Bearer <token>` header on
|
|
1211
|
+
* `POST /oauth2/register`.
|
|
1212
|
+
*
|
|
1213
|
+
* Return an {@link InitialAccessTokenAuthorization} (optionally carrying a
|
|
1214
|
+
* `referenceId` owner) to authorize the registration, or `false` to reject
|
|
1215
|
+
* the token. Defining this callback enables the token-backed registration
|
|
1216
|
+
* mode; while it is undefined, a Bearer token presented to the endpoint is
|
|
1217
|
+
* rejected rather than downgraded to open registration.
|
|
1218
|
+
*
|
|
1219
|
+
* `clientMetadata` is the schema-validated request body. It is self-asserted
|
|
1220
|
+
* (RFC 7591 §5) and not yet semantically validated, so a request authorized
|
|
1221
|
+
* here may still be rejected by a later metadata check. Compare the token in
|
|
1222
|
+
* constant time; issuance, storage, expiration, and revocation are
|
|
1223
|
+
* deployment-specific in RFC 7591 and belong in your application.
|
|
1224
|
+
*
|
|
1225
|
+
* `headers` is the raw request `Headers`, available to correlate the token
|
|
1226
|
+
* with other request context (a tenant header, a forwarded client identity).
|
|
1227
|
+
*
|
|
1228
|
+
* With the `bearer` plugin enabled, a Bearer value that resolves to a valid
|
|
1229
|
+
* user session is handled as that session, not as an initial access token.
|
|
1230
|
+
*
|
|
1231
|
+
* @see InitialAccessTokenAuthorization
|
|
1232
|
+
*/
|
|
1233
|
+
validateInitialAccessToken?: (context: {
|
|
1234
|
+
initialAccessToken: string;
|
|
1235
|
+
headers: Headers;
|
|
1236
|
+
clientMetadata: ClientRegistrationRequest;
|
|
1237
|
+
}) => Awaitable<InitialAccessTokenAuthorization | false>;
|
|
1238
|
+
/**
|
|
1239
|
+
* OAuth/OIDC extension points used by companion plugins to add protocol
|
|
1240
|
+
* grants, client authentication methods, metadata, claims, and client-id
|
|
1241
|
+
* discovery without modifying oauth-provider core for each RFC.
|
|
1242
|
+
*
|
|
1243
|
+
* Extension plugins should prefer `extendOAuthProvider(ctx, extension)` in
|
|
1244
|
+
* their `init()` hook so users can compose plugins declaratively. Plugins
|
|
1245
|
+
* such as `@better-auth/cimd` contribute their client discovery this way.
|
|
1246
|
+
*/
|
|
1247
|
+
extensions?: OAuthProviderExtension[];
|
|
1248
|
+
/**
|
|
1249
|
+
* List of scopes for newly registered clients
|
|
1250
|
+
* if not requested.
|
|
1251
|
+
*
|
|
1252
|
+
* For scopes that shall automatically adapt to your scopes
|
|
1253
|
+
* list in the future (ie scopes: undefined), create that client
|
|
1254
|
+
* using the server's `createOAuthClient` function.
|
|
1255
|
+
*
|
|
1256
|
+
* @default scopes
|
|
1257
|
+
*/
|
|
1258
|
+
clientRegistrationDefaultScopes?: Scopes;
|
|
1259
|
+
/**
|
|
1260
|
+
* List of scopes for allowed clients in addition to
|
|
1261
|
+
* those listed in the default scope. Finalized allowed list is
|
|
1262
|
+
* the union of the default scopes and this list.
|
|
1263
|
+
*
|
|
1264
|
+
* If both clientRegistrationDefaultScopes and this
|
|
1265
|
+
* are undefined, only scopes listed in the scopes option
|
|
1266
|
+
* are allowed.
|
|
1267
|
+
*
|
|
1268
|
+
* @default - clientRegistrationDefaultScopes
|
|
1269
|
+
*/
|
|
1270
|
+
clientRegistrationAllowedScopes?: Scopes;
|
|
1271
|
+
/**
|
|
1272
|
+
* Whether dynamically registered confidential clients require PKCE by default.
|
|
1273
|
+
*
|
|
1274
|
+
* This is server-owned registration policy. Dynamic client registration does
|
|
1275
|
+
* not accept `require_pkce` from the client request, and public clients or
|
|
1276
|
+
* authorization requests with `offline_access` still require PKCE unless the
|
|
1277
|
+
* confidential OIDC request includes both `openid` and `nonce`.
|
|
1278
|
+
*
|
|
1279
|
+
* @default true
|
|
1280
|
+
*/
|
|
1281
|
+
clientRegistrationRequirePKCE?: boolean;
|
|
1282
|
+
/**
|
|
1283
|
+
* How long a dynamically created confidential client
|
|
1284
|
+
* should last for.
|
|
1285
|
+
*
|
|
1286
|
+
* - If a `number` is passed as an argument it is used as the claim directly.
|
|
1287
|
+
* - If a `Date` instance is passed as an argument it is converted to unix timestamp and used as the
|
|
1288
|
+
* claim.
|
|
1289
|
+
* - If a `string` is passed as an argument it is resolved to a time span, and then added to the
|
|
1290
|
+
* current unix timestamp and used as the claim.
|
|
1291
|
+
*
|
|
1292
|
+
* Format used for time span should be a number followed by a unit, such as "5 minutes" or "1
|
|
1293
|
+
* day".
|
|
1294
|
+
*
|
|
1295
|
+
* Valid units are: "sec", "secs", "second", "seconds", "s", "minute", "minutes", "min", "mins",
|
|
1296
|
+
* "m", "hour", "hours", "hr", "hrs", "h", "day", "days", "d", "week", "weeks", "w", "year",
|
|
1297
|
+
* "years", "yr", "yrs", and "y". It is not possible to specify months. 365.25 days is used as an
|
|
1298
|
+
* alias for a year.
|
|
1299
|
+
*
|
|
1300
|
+
* If the string is suffixed with "ago", or prefixed with a "-", the resulting time span gets
|
|
1301
|
+
* subtracted from the current unix timestamp. A "from now" suffix can also be used for
|
|
1302
|
+
* readability when adding to the current unix timestamp.
|
|
1303
|
+
*
|
|
1304
|
+
* @default - undefined (does not expire)
|
|
1305
|
+
*/
|
|
1306
|
+
clientRegistrationClientSecretExpiration?: number | string | Date;
|
|
1307
|
+
/**
|
|
1308
|
+
* Returns the reference id which owns the oauth clients.
|
|
1309
|
+
*
|
|
1310
|
+
* For example, it can be an organization, team, etc.
|
|
1311
|
+
* When provided, user_id of the client will be undefined
|
|
1312
|
+
* and the owner is defined under the field `reference_id`.
|
|
1313
|
+
*
|
|
1314
|
+
* With the organization plugin: @example ({ session }) => {
|
|
1315
|
+
* return session?.activeOrganizationId;
|
|
1316
|
+
* }
|
|
1317
|
+
*/
|
|
1318
|
+
clientReference?: (context: {
|
|
1319
|
+
user?: User & Record<string, unknown>;
|
|
1320
|
+
session?: Session & Record<string, unknown>;
|
|
1321
|
+
}) => Awaitable<string | undefined>;
|
|
1322
|
+
/**
|
|
1323
|
+
* RBAC on OAuth Clients.
|
|
1324
|
+
*
|
|
1325
|
+
* Provides context to help determine if a user can perform
|
|
1326
|
+
* a specific action.
|
|
1327
|
+
*/
|
|
1328
|
+
clientPrivileges?: (context: {
|
|
1329
|
+
headers: Headers;
|
|
1330
|
+
action: "create" | "read" | "update" | "delete" | "list" | "rotate";
|
|
1331
|
+
user?: User & Record<string, unknown>;
|
|
1332
|
+
session?: Session & Record<string, unknown>;
|
|
1333
|
+
}) => Awaitable<boolean | undefined>;
|
|
1334
|
+
/**
|
|
1335
|
+
* List default scopes when using the token endpoint's
|
|
1336
|
+
* grant type "client_credentials". This is used
|
|
1337
|
+
* only when oauthClients are stored in the database
|
|
1338
|
+
* without a scope and you do not want all `scopes` to be given.
|
|
1339
|
+
*
|
|
1340
|
+
* @default undefined
|
|
1341
|
+
*/
|
|
1342
|
+
clientCredentialGrantDefaultScopes?: Scopes;
|
|
1343
|
+
/**
|
|
1344
|
+
* Grant types supported by the token endpoint
|
|
1345
|
+
*
|
|
1346
|
+
* @default
|
|
1347
|
+
* ["authorization_code", "client_credentials", "refresh_token"]
|
|
1348
|
+
*/
|
|
1349
|
+
grantTypes?: GrantType[];
|
|
1350
|
+
/**
|
|
1351
|
+
* The URL to the login page. This is used if the client requests the `login`
|
|
1352
|
+
* prompt.
|
|
1353
|
+
*/
|
|
1354
|
+
loginPage: string;
|
|
1355
|
+
/**
|
|
1356
|
+
* A URL to the consent page where the user will be redirected if the client
|
|
1357
|
+
* requests consent.
|
|
1358
|
+
*
|
|
1359
|
+
* After the user consents, they should be redirected by the client to the
|
|
1360
|
+
* `redirect_uri` with the authorization code.
|
|
1361
|
+
*
|
|
1362
|
+
* When the server redirects the user to the consent page, it will include the
|
|
1363
|
+
* following query parameters:
|
|
1364
|
+
*
|
|
1365
|
+
* - `client_id` - The ID of the client.
|
|
1366
|
+
* - `scope` - The requested scopes.
|
|
1367
|
+
* - `claims` - The OIDC claims request, when the client requested specific
|
|
1368
|
+
* claims. Consent pages should surface `claims.userinfo` names alongside
|
|
1369
|
+
* scopes because accepted UserInfo claims can affect the UserInfo response.
|
|
1370
|
+
* - `code` - The authorization code.
|
|
1371
|
+
*
|
|
1372
|
+
* once the user consents, you need to call the `/oauth2/consent` endpoint
|
|
1373
|
+
* with the code and `accept: true` to complete the authorization. Include a
|
|
1374
|
+
* `claims` object if the user accepted only some requested UserInfo claims.
|
|
1375
|
+
* The endpoint will then return the client to the `redirect_uri` with the
|
|
1376
|
+
* authorization code.
|
|
1377
|
+
*
|
|
1378
|
+
* @example
|
|
1379
|
+
* ```ts
|
|
1380
|
+
* consentPage: "/consent"
|
|
1381
|
+
* ```
|
|
1382
|
+
*/
|
|
1383
|
+
consentPage: string;
|
|
1384
|
+
/**
|
|
1385
|
+
* Sign Up page settings associated with `prompt: "create"`
|
|
1386
|
+
* @see https://openid.net/specs/openid-connect-prompt-create-1_0.html
|
|
1387
|
+
*/
|
|
1388
|
+
signup?: {
|
|
1389
|
+
/**
|
|
1390
|
+
* A URL to the Sign Up page where the user will be redirected
|
|
1391
|
+
* to continue a signup flow.
|
|
1392
|
+
*
|
|
1393
|
+
* Upon completion of signup, you need to call the `/oauth2/continue`
|
|
1394
|
+
* with `created: true` to continue the login flow.
|
|
1395
|
+
*
|
|
1396
|
+
* @default loginPage
|
|
1397
|
+
* @example `/sign-up`
|
|
1398
|
+
*/
|
|
1399
|
+
page?: string;
|
|
1400
|
+
/**
|
|
1401
|
+
* To add registration steps, specify the page(s) to redirect to.
|
|
1402
|
+
*
|
|
1403
|
+
* Note: the account would need to be logged in (or selected)
|
|
1404
|
+
* to specify steps.
|
|
1405
|
+
*
|
|
1406
|
+
* If true, user with redirect to `page`.
|
|
1407
|
+
* If string, user with redirect to the page specified by string.
|
|
1408
|
+
* If false, user has completed registration and will continue auth flow.
|
|
1409
|
+
*
|
|
1410
|
+
* @param context
|
|
1411
|
+
*/
|
|
1412
|
+
shouldRedirect?: (context: {
|
|
1413
|
+
headers: Headers;
|
|
1414
|
+
user: User & Record<string, unknown>;
|
|
1415
|
+
session: Session & Record<string, unknown>;
|
|
1416
|
+
scopes: Scopes;
|
|
1417
|
+
}) => Awaitable<boolean | string>;
|
|
1418
|
+
};
|
|
1419
|
+
/**
|
|
1420
|
+
* Select Account page settings associated with `prompt: "select_account"`
|
|
1421
|
+
*/
|
|
1422
|
+
selectAccount?: {
|
|
1423
|
+
/**
|
|
1424
|
+
* A URL to the account selection page where the user will be redirected if
|
|
1425
|
+
* the user must select an account (eg. multi-session).
|
|
1426
|
+
*
|
|
1427
|
+
* Once the user selects an account, you need to call the `/oauth2/continue`
|
|
1428
|
+
* with `selected: true` to continue the login flow.
|
|
1429
|
+
*
|
|
1430
|
+
* @default loginPage
|
|
1431
|
+
*/
|
|
1432
|
+
page?: string;
|
|
1433
|
+
/**
|
|
1434
|
+
* Checks to see if an account needs selection
|
|
1435
|
+
* for the `/oauth2/authorize` endpoint.
|
|
1436
|
+
*
|
|
1437
|
+
* @returns
|
|
1438
|
+
* - `true`: account is not selected and needs selection
|
|
1439
|
+
* - `false`: intended user or account already selected
|
|
1440
|
+
*/
|
|
1441
|
+
shouldRedirect: (context: {
|
|
1442
|
+
headers: Headers;
|
|
1443
|
+
user: User & Record<string, unknown>;
|
|
1444
|
+
session: Session & Record<string, unknown>;
|
|
1445
|
+
scopes: Scopes;
|
|
1446
|
+
}) => Awaitable<boolean>;
|
|
1447
|
+
};
|
|
1448
|
+
/**
|
|
1449
|
+
* Post login page settings
|
|
1450
|
+
*/
|
|
1451
|
+
postLogin?: {
|
|
1452
|
+
/**
|
|
1453
|
+
* The page `shouldRedirect` should redirect to.
|
|
1454
|
+
*/
|
|
1455
|
+
page: string;
|
|
1456
|
+
/**
|
|
1457
|
+
* A value to tie to the consent reference_id.
|
|
1458
|
+
*
|
|
1459
|
+
* Note that YOU must fail in this function if the requested
|
|
1460
|
+
* scope doesn't have a reference id and it should.
|
|
1461
|
+
*/
|
|
1462
|
+
consentReferenceId: (context: {
|
|
1463
|
+
user: User & Record<string, unknown>;
|
|
1464
|
+
session: Session & Record<string, unknown>;
|
|
1465
|
+
scopes: Scopes;
|
|
1466
|
+
}) => Awaitable<string | undefined>;
|
|
1467
|
+
/**
|
|
1468
|
+
* After login and before consent, request the user to
|
|
1469
|
+
* select an additional choice for `/oauth2/authorize`.
|
|
1470
|
+
* For example, allow selection of an organization or team.
|
|
1471
|
+
*
|
|
1472
|
+
* Upon selection of a specific account, use `/oauth2/continue`
|
|
1473
|
+
* with `postLogin: true` to continue the login flow.
|
|
1474
|
+
*
|
|
1475
|
+
* @returns
|
|
1476
|
+
* - `true`: account is not selected and needs selection
|
|
1477
|
+
* - `false`: intended user or account selected
|
|
1478
|
+
*/
|
|
1479
|
+
shouldRedirect: (context: {
|
|
1480
|
+
headers: Headers;
|
|
1481
|
+
user: User & Record<string, unknown>;
|
|
1482
|
+
session: Session & Record<string, unknown>;
|
|
1483
|
+
scopes: Scopes;
|
|
1484
|
+
}) => Awaitable<boolean>;
|
|
1485
|
+
};
|
|
1486
|
+
/**
|
|
1487
|
+
* Format your refresh tokens the returned to oauth clients.
|
|
1488
|
+
* For example with JWE encryption/decryption logic.
|
|
1489
|
+
*
|
|
1490
|
+
* If you changed the format after production deployment,
|
|
1491
|
+
* ensure that the prior version can still be decoded.
|
|
1492
|
+
*
|
|
1493
|
+
* NOTE: `prefix.refreshToken` is internally handled,
|
|
1494
|
+
* so `token` only contains the stored database token.
|
|
1495
|
+
*/
|
|
1496
|
+
formatRefreshToken?: {
|
|
1497
|
+
/**
|
|
1498
|
+
* Custom session token format sent to client.
|
|
1499
|
+
*/
|
|
1500
|
+
encrypt: (token: string, sessionId?: string) => Awaitable<string>;
|
|
1501
|
+
/**
|
|
1502
|
+
* Decodes the custom session token.
|
|
1503
|
+
*
|
|
1504
|
+
* @returns {string | undefined} sessionId - if returned,
|
|
1505
|
+
* should be same as the one received in `encode`.
|
|
1506
|
+
* There is an added benefit that updates to the session occur
|
|
1507
|
+
* via id instead of token.
|
|
1508
|
+
* @returns {string} token - should be same as the one
|
|
1509
|
+
* received in `encode`
|
|
1510
|
+
*/
|
|
1511
|
+
decrypt: (token: string) => Awaitable<{
|
|
1512
|
+
sessionId?: string;
|
|
1513
|
+
token: string;
|
|
1514
|
+
}>;
|
|
1515
|
+
};
|
|
1516
|
+
/**
|
|
1517
|
+
* Store the client secret in your database in a secure way
|
|
1518
|
+
* Note: This will not affect the client secret sent to the user,
|
|
1519
|
+
* it will only affect the client secret stored in your database
|
|
1520
|
+
*
|
|
1521
|
+
* When disableJwtPlugin = false (recommended):
|
|
1522
|
+
* - "hashed" - The client secret is hashed using the `hash` function.
|
|
1523
|
+
* - {
|
|
1524
|
+
* hash: (clientSecret: string) => Awaitable<string>,
|
|
1525
|
+
* verify?: (clientSecret: string, storedHash: string) => Awaitable<boolean>
|
|
1526
|
+
* } - A function that hashes the client secret.
|
|
1527
|
+
*
|
|
1528
|
+
* When disableJwtPlugin = true:
|
|
1529
|
+
* - "encrypted" - The client secret is encrypted using the `encrypt` function.
|
|
1530
|
+
* - {
|
|
1531
|
+
* encrypt: (clientSecret: string) => Awaitable<string>,
|
|
1532
|
+
* decrypt: (storedSecret: string) => Awaitable<string>
|
|
1533
|
+
* } - A function that encrypts and decrypts the client secret.
|
|
1534
|
+
*
|
|
1535
|
+
* @default
|
|
1536
|
+
* options.disableJwtPlugin ? "encrypted" : "hashed"
|
|
1537
|
+
*/
|
|
1538
|
+
storeClientSecret?: "hashed" | "encrypted" | {
|
|
1539
|
+
hash: (clientSecret: string) => Awaitable<string>;
|
|
1540
|
+
verify?: (clientSecret: string, storedHash: string) => Awaitable<boolean>;
|
|
1541
|
+
} | {
|
|
1542
|
+
encrypt: (clientSecret: string) => Awaitable<string>;
|
|
1543
|
+
decrypt: (storedSecret: string) => Awaitable<string>;
|
|
1544
|
+
};
|
|
1545
|
+
/**
|
|
1546
|
+
* Storage method of opaque access tokens and refresh tokens on your database.
|
|
1547
|
+
*
|
|
1548
|
+
* - "hashed" - The client secret is hashed using the `hash` function.
|
|
1549
|
+
* - {
|
|
1550
|
+
* hash: (token: string, type: StoreTokenType) => Awaitable<string>
|
|
1551
|
+
* } - A function that hashes the token
|
|
1552
|
+
*
|
|
1553
|
+
* @default "hashed"
|
|
1554
|
+
*/
|
|
1555
|
+
storeTokens?: "hashed" | {
|
|
1556
|
+
hash: (token: string, type: StoreTokenType) => Awaitable<string>;
|
|
1557
|
+
};
|
|
1558
|
+
/**
|
|
1559
|
+
* Custom claims provided at the OIDC `userinfo` endpoint.
|
|
1560
|
+
*
|
|
1561
|
+
* @param info - context that may be useful when creating custom claims
|
|
1562
|
+
* @returns Additional claims for userinfo request
|
|
1563
|
+
*/
|
|
1564
|
+
customUserInfoClaims?: (info: {
|
|
1565
|
+
/** The user object */user: User & Record<string, unknown>;
|
|
1566
|
+
/** The scopes from the access token used
|
|
1567
|
+
* in the /userinfo request (matches jwt.scopes) */
|
|
1568
|
+
scopes: Scopes; /** The access token payload used in the /userinfo request */
|
|
1569
|
+
jwt: JWTPayload;
|
|
1570
|
+
/**
|
|
1571
|
+
* Claim names explicitly requested through the OIDC `claims.userinfo`
|
|
1572
|
+
* authorization request parameter.
|
|
1573
|
+
*/
|
|
1574
|
+
requestedClaims: string[];
|
|
1575
|
+
}) => Awaitable<Record<string, any>>;
|
|
1576
|
+
/**
|
|
1577
|
+
* Custom claims attached to OIDC id tokens.
|
|
1578
|
+
*
|
|
1579
|
+
* To remain OIDC-compliant, claims should be
|
|
1580
|
+
* namespaced with a URI. For example, a site
|
|
1581
|
+
* example.com should namespace an organization at
|
|
1582
|
+
* https://example.com/organization.
|
|
1583
|
+
*
|
|
1584
|
+
* Reserved ID token claim names (`iss`, `sub`, `aud`, `exp`, `nbf`, `iat`,
|
|
1585
|
+
* `jti`, `nonce`, `sid`, `at_hash`, `c_hash`, `s_hash`, `auth_time`, `acr`,
|
|
1586
|
+
* `amr`, `azp`) are stripped at issuance with a warning log. The
|
|
1587
|
+
* authorization server owns these values.
|
|
1588
|
+
*
|
|
1589
|
+
* @param info - context that may be useful when creating custom claims
|
|
1590
|
+
*/
|
|
1591
|
+
customIdTokenClaims?: (info: {
|
|
1592
|
+
/** The user object if token is associated to a user. */user: User & Record<string, unknown>; /** Scopes granted for this token */
|
|
1593
|
+
scopes: Scopes; /** oAuthClient metadata */
|
|
1594
|
+
metadata?: Record<string, any>;
|
|
1595
|
+
}) => Awaitable<Record<string, any>>;
|
|
1596
|
+
/**
|
|
1597
|
+
* Custom claims attached to access tokens.
|
|
1598
|
+
*
|
|
1599
|
+
* Claims are added for both the token and introspect endpoints.
|
|
1600
|
+
*
|
|
1601
|
+
* Use the user and referenceId fields to fetch
|
|
1602
|
+
* for membership roles/permissions to attach for the token.
|
|
1603
|
+
* Note that scopes are those that requested,
|
|
1604
|
+
* permissions are what the the user can actually do which
|
|
1605
|
+
* must be done in this function.
|
|
1606
|
+
*
|
|
1607
|
+
* @param info - context that may be useful when creating custom claims
|
|
1608
|
+
*/
|
|
1609
|
+
customAccessTokenClaims?: (info: {
|
|
1610
|
+
/** The user object if token is associated to a user. Null if user doesn't exist. Undefined if user not applicable. */user?: (User & Record<string, unknown>) | null; /** reference of the consent/authorization */
|
|
1611
|
+
referenceId?: string; /** Scopes granted for this token */
|
|
1612
|
+
scopes: Scopes; /** The resources requested. */
|
|
1613
|
+
resources?: string[]; /** oAuthClient metadata */
|
|
1614
|
+
metadata?: Record<string, any>;
|
|
1615
|
+
}) => Awaitable<Record<string, any>>;
|
|
1616
|
+
/**
|
|
1617
|
+
* Custom fields to include in the token response body.
|
|
1618
|
+
*
|
|
1619
|
+
* Unlike `customAccessTokenClaims` (which adds claims inside the JWT payload),
|
|
1620
|
+
* this adds fields to the JSON response envelope alongside `access_token`,
|
|
1621
|
+
* `token_type`, etc. Standard OAuth fields (`access_token`, `token_type`,
|
|
1622
|
+
* `expires_in`, `expires_at`, `refresh_token`, `scope`, `id_token`) cannot
|
|
1623
|
+
* be overridden.
|
|
1624
|
+
*
|
|
1625
|
+
* @param info - context that may be useful when creating custom fields
|
|
1626
|
+
*/
|
|
1627
|
+
customTokenResponseFields?: (info: {
|
|
1628
|
+
/** The grant type being processed */grantType: GrantType;
|
|
1629
|
+
/**
|
|
1630
|
+
* The user, if applicable.
|
|
1631
|
+
* Undefined for `client_credentials` (M2M, no user).
|
|
1632
|
+
* Always present for `authorization_code` and `refresh_token`.
|
|
1633
|
+
*/
|
|
1634
|
+
user?: (User & Record<string, unknown>) | null; /** Scopes granted for this token */
|
|
1635
|
+
scopes: Scopes; /** oAuthClient metadata */
|
|
1636
|
+
metadata?: Record<string, any>;
|
|
1637
|
+
/**
|
|
1638
|
+
* The authorization code verification value.
|
|
1639
|
+
* Only present for `authorization_code` grant. Contains the original
|
|
1640
|
+
* authorization request parameters (`query`), `referenceId`, `sessionId`, etc.
|
|
1641
|
+
*/
|
|
1642
|
+
verificationValue?: VerificationValue;
|
|
1643
|
+
}) => Awaitable<Record<string, unknown>>;
|
|
1644
|
+
/**
|
|
1645
|
+
* Overwrite specific /.well-known/openid-configuration
|
|
1646
|
+
* values so they are not available publically.
|
|
1647
|
+
* This may be important if not all clients need specific scopes.
|
|
1648
|
+
*/
|
|
1649
|
+
advertisedMetadata?: {
|
|
1650
|
+
/**
|
|
1651
|
+
* Advertised scopes_supported located at /.well-known/openid-configuration
|
|
1652
|
+
*
|
|
1653
|
+
* All values must be found in the scope field
|
|
1654
|
+
*/
|
|
1655
|
+
scopes_supported?: Scopes;
|
|
1656
|
+
/**
|
|
1657
|
+
* Advertised claims_supported located at /.well-known/openid-configuration
|
|
1658
|
+
*
|
|
1659
|
+
* Internally supported claims:
|
|
1660
|
+
* ["sub", "iss", "aud", "exp", "iat", "sid", "scope", "azp"]
|
|
1661
|
+
*/
|
|
1662
|
+
claims_supported?: string[];
|
|
1663
|
+
};
|
|
1664
|
+
/**
|
|
1665
|
+
* Attach prefixes to returned token types.
|
|
1666
|
+
* NOTE: The prefix is not stored in the database.
|
|
1667
|
+
*
|
|
1668
|
+
* Useful when also using the [API Key Plugin](../api-key/index.ts)
|
|
1669
|
+
* or Secret Scanners (ie Github Secret Scanning, GitGuardian, Trufflehog).
|
|
1670
|
+
*
|
|
1671
|
+
* We recommend to append an underscore to make it more identifiable.
|
|
1672
|
+
*/
|
|
1673
|
+
prefix?: {
|
|
1674
|
+
/**
|
|
1675
|
+
* Prefix on returned opaque access tokens.
|
|
1676
|
+
*
|
|
1677
|
+
* Additionally, we recommend you add the prefix prior to the first deployment
|
|
1678
|
+
* otherwise you must utilize this with `generateOpaqueAccessToken` (storing the full
|
|
1679
|
+
* encoded value on the database).
|
|
1680
|
+
*
|
|
1681
|
+
* @example "domain_at_"
|
|
1682
|
+
* @default undefined
|
|
1683
|
+
*/
|
|
1684
|
+
opaqueAccessToken?: string;
|
|
1685
|
+
/**
|
|
1686
|
+
* Prefix on returned refresh tokens.
|
|
1687
|
+
*
|
|
1688
|
+
* Additionally, we recommend you add the prefix prior to the first deployment
|
|
1689
|
+
* otherwise you must utilize this with `generateRefreshToken` (storing the full
|
|
1690
|
+
* encoded value on the database).
|
|
1691
|
+
*
|
|
1692
|
+
* @example "domain_rt_"
|
|
1693
|
+
* @default undefined
|
|
1694
|
+
*/
|
|
1695
|
+
refreshToken?: string;
|
|
1696
|
+
/**
|
|
1697
|
+
* Prefix on returned client secrets.
|
|
1698
|
+
*
|
|
1699
|
+
* Additionally, we recommend you add the prefix prior to the first deployment
|
|
1700
|
+
* otherwise you must utilize this with `generateClientSecret` (storing the full
|
|
1701
|
+
* encoded value on the database).
|
|
1702
|
+
*
|
|
1703
|
+
* @example "domain_cs_"
|
|
1704
|
+
* @default undefined
|
|
1705
|
+
*/
|
|
1706
|
+
clientSecret?: string;
|
|
1707
|
+
};
|
|
1708
|
+
/**
|
|
1709
|
+
* Custom function to generate a client ID.
|
|
1710
|
+
*
|
|
1711
|
+
* @default
|
|
1712
|
+
* generateRandomString(32, "A-Z", "a-z")
|
|
1713
|
+
*/
|
|
1714
|
+
generateClientId?: () => string;
|
|
1715
|
+
/**
|
|
1716
|
+
* Custom function to generate a client secret.
|
|
1717
|
+
*
|
|
1718
|
+
* @default
|
|
1719
|
+
* generateRandomString(32, "A-Z", "a-z")
|
|
1720
|
+
*/
|
|
1721
|
+
generateClientSecret?: () => string;
|
|
1722
|
+
/**
|
|
1723
|
+
* Generate a unique access token to save on the database.
|
|
1724
|
+
*
|
|
1725
|
+
* @default
|
|
1726
|
+
* generateRandomString(32, "A-Z", "a-z")
|
|
1727
|
+
*/
|
|
1728
|
+
generateOpaqueAccessToken?: () => Awaitable<string>;
|
|
1729
|
+
/**
|
|
1730
|
+
* Generate a unique refresh token to save on the database.
|
|
1731
|
+
*
|
|
1732
|
+
* @default
|
|
1733
|
+
* generateRandomString(32, "A-Z", "a-z")
|
|
1734
|
+
*/
|
|
1735
|
+
generateRefreshToken?: () => Awaitable<string>;
|
|
1736
|
+
/**
|
|
1737
|
+
* Confirmations that individually silences specific well-known endpoint
|
|
1738
|
+
* configuration warnings.
|
|
1739
|
+
*
|
|
1740
|
+
* Only set these specific values if you see the error as they
|
|
1741
|
+
* are configuration specific.
|
|
1742
|
+
*/
|
|
1743
|
+
silenceWarnings?: {
|
|
1744
|
+
/**
|
|
1745
|
+
* Config warning for `/.well-known/oauth-authorization-server/[issuer-path]`
|
|
1746
|
+
*
|
|
1747
|
+
* @default false
|
|
1748
|
+
*/
|
|
1749
|
+
oauthAuthServerConfig?: boolean;
|
|
1750
|
+
/**
|
|
1751
|
+
* Config warning for `[issuer-path]/.well-known/openid-configuration`
|
|
1752
|
+
*
|
|
1753
|
+
* @default false
|
|
1754
|
+
*/
|
|
1755
|
+
openidConfig?: boolean;
|
|
1756
|
+
};
|
|
1757
|
+
/**
|
|
1758
|
+
* By default, access and id tokens can be issued and verified
|
|
1759
|
+
* through the JWT plugin.
|
|
1760
|
+
*
|
|
1761
|
+
* You can disable the JWT requirement in which access tokens
|
|
1762
|
+
* will always be opaque and id tokens are always signed
|
|
1763
|
+
* with HS256 using the client secret.
|
|
1764
|
+
*
|
|
1765
|
+
* @default false
|
|
1766
|
+
*/
|
|
1767
|
+
disableJwtPlugin?: boolean;
|
|
1768
|
+
/**
|
|
1769
|
+
* Rate limit configuration for OAuth endpoints.
|
|
1770
|
+
*
|
|
1771
|
+
* Each endpoint can be configured with a `window` (in seconds) and `max` requests.
|
|
1772
|
+
* Set to `false` to disable rate limiting for a specific endpoint.
|
|
1773
|
+
*
|
|
1774
|
+
* @default
|
|
1775
|
+
* ```ts
|
|
1776
|
+
* {
|
|
1777
|
+
* token: { window: 60, max: 20 },
|
|
1778
|
+
* authorize: { window: 60, max: 30 },
|
|
1779
|
+
* introspect: { window: 60, max: 100 },
|
|
1780
|
+
* revoke: { window: 60, max: 30 },
|
|
1781
|
+
* register: { window: 60, max: 5 },
|
|
1782
|
+
* userinfo: { window: 60, max: 60 },
|
|
1783
|
+
* }
|
|
1784
|
+
* ```
|
|
1785
|
+
*/
|
|
1786
|
+
rateLimit?: {
|
|
1787
|
+
/**
|
|
1788
|
+
* Rate limit for /oauth2/token endpoint
|
|
1789
|
+
* @default { window: 60, max: 20 }
|
|
1790
|
+
*/
|
|
1791
|
+
token?: {
|
|
1792
|
+
window: number;
|
|
1793
|
+
max: number;
|
|
1794
|
+
} | false;
|
|
1795
|
+
/**
|
|
1796
|
+
* Rate limit for /oauth2/authorize endpoint
|
|
1797
|
+
* @default { window: 60, max: 30 }
|
|
1798
|
+
*/
|
|
1799
|
+
authorize?: {
|
|
1800
|
+
window: number;
|
|
1801
|
+
max: number;
|
|
1802
|
+
} | false;
|
|
1803
|
+
/**
|
|
1804
|
+
* Rate limit for /oauth2/introspect endpoint
|
|
1805
|
+
* @default { window: 60, max: 100 }
|
|
1806
|
+
*/
|
|
1807
|
+
introspect?: {
|
|
1808
|
+
window: number;
|
|
1809
|
+
max: number;
|
|
1810
|
+
} | false;
|
|
1811
|
+
/**
|
|
1812
|
+
* Rate limit for /oauth2/revoke endpoint
|
|
1813
|
+
* @default { window: 60, max: 30 }
|
|
1814
|
+
*/
|
|
1815
|
+
revoke?: {
|
|
1816
|
+
window: number;
|
|
1817
|
+
max: number;
|
|
1818
|
+
} | false;
|
|
1819
|
+
/**
|
|
1820
|
+
* Rate limit for /oauth2/register endpoint
|
|
1821
|
+
* @default { window: 60, max: 5 }
|
|
1822
|
+
*/
|
|
1823
|
+
register?: {
|
|
1824
|
+
window: number;
|
|
1825
|
+
max: number;
|
|
1826
|
+
} | false;
|
|
1827
|
+
/**
|
|
1828
|
+
* Rate limit for /oauth2/userinfo endpoint
|
|
1829
|
+
* @default { window: 60, max: 60 }
|
|
1830
|
+
*/
|
|
1831
|
+
userinfo?: {
|
|
1832
|
+
window: number;
|
|
1833
|
+
max: number;
|
|
1834
|
+
} | false;
|
|
1835
|
+
};
|
|
1836
|
+
/**
|
|
1837
|
+
* Secret used to compute pairwise subject identifiers (HMAC-SHA256).
|
|
1838
|
+
* When set, clients with `subject_type: "pairwise"` receive unique,
|
|
1839
|
+
* unlinkable `sub` values per sector identifier.
|
|
1840
|
+
*
|
|
1841
|
+
* @see https://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg
|
|
1842
|
+
*/
|
|
1843
|
+
pairwiseSecret?: string;
|
|
1844
|
+
/**
|
|
1845
|
+
* Resolves a `request_uri` at the authorize endpoint (PAR support).
|
|
1846
|
+
*
|
|
1847
|
+
* When the authorize endpoint receives a `request_uri` parameter, this callback
|
|
1848
|
+
* resolves it to the original authorization parameters. Return null if the URI
|
|
1849
|
+
* is invalid or expired.
|
|
1850
|
+
*/
|
|
1851
|
+
requestUriResolver?: (input: {
|
|
1852
|
+
requestUri: string;
|
|
1853
|
+
clientId: string;
|
|
1854
|
+
ctx: GenericEndpointContext;
|
|
1855
|
+
}) => Promise<Record<string, string> | null>;
|
|
1856
|
+
/**
|
|
1857
|
+
* DPoP proof validation settings.
|
|
1858
|
+
*
|
|
1859
|
+
* DPoP is enabled by default when a client or resource asks for DPoP-bound
|
|
1860
|
+
* access tokens. These values tune proof validation without changing that
|
|
1861
|
+
* contract.
|
|
1862
|
+
*/
|
|
1863
|
+
dpop?: {
|
|
1864
|
+
/**
|
|
1865
|
+
* Accepted age of a DPoP proof JWT in seconds.
|
|
1866
|
+
*
|
|
1867
|
+
* @default 300
|
|
1868
|
+
*/
|
|
1869
|
+
proofMaxAgeSeconds?: number;
|
|
1870
|
+
/**
|
|
1871
|
+
* Supported JWS algorithms for DPoP proof JWTs.
|
|
1872
|
+
*
|
|
1873
|
+
* @default ["EdDSA", "ES256", "ES512", "PS256", "RS256"]
|
|
1874
|
+
*/
|
|
1875
|
+
signingAlgorithms?: JWSAlgorithms[];
|
|
1876
|
+
};
|
|
1877
|
+
}
|
|
1878
|
+
interface OAuthAuthorizationQuery {
|
|
1879
|
+
/**
|
|
1880
|
+
* The response type.
|
|
1881
|
+
* - "code": authorization code flow.
|
|
1882
|
+
* Optional in the query when using request_uri (PAR) — resolved from stored params.
|
|
1883
|
+
*/
|
|
1884
|
+
response_type?: "code";
|
|
1885
|
+
/**
|
|
1886
|
+
* OpenID Connect Request Object by value.
|
|
1887
|
+
*
|
|
1888
|
+
* The parameter is parsed so unsupported use can be rejected with
|
|
1889
|
+
* `request_not_supported`; Better Auth does not process Request Objects yet.
|
|
1890
|
+
*/
|
|
1891
|
+
request?: string;
|
|
1892
|
+
/**
|
|
1893
|
+
* PAR request_uri. When present, other params are resolved from the stored request.
|
|
1894
|
+
*/
|
|
1895
|
+
request_uri?: string;
|
|
1896
|
+
/**
|
|
1897
|
+
* The redirect URI for the client. Must be one of the registered redirect URLs for the client.
|
|
1898
|
+
*/
|
|
1899
|
+
redirect_uri: string;
|
|
1900
|
+
/**
|
|
1901
|
+
* The scope of the request. Must be a space-separated list of case sensitive strings.
|
|
1902
|
+
*
|
|
1903
|
+
* - "openid" is required for most requests to obtain user id (ie sub)
|
|
1904
|
+
* - "profile" is required for requests that require user profile information.
|
|
1905
|
+
* - "email" is required for requests that require user email information.
|
|
1906
|
+
* - "offline_access" is required for requests that require a refresh token.
|
|
1907
|
+
*/
|
|
1908
|
+
scope?: string;
|
|
1909
|
+
/**
|
|
1910
|
+
* Opaque value used to maintain state between the request and the callback. Typically,
|
|
1911
|
+
* Cross-Site Request Forgery (CSRF, XSRF) mitigation is done by cryptographically binding the
|
|
1912
|
+
* value of this parameter with a browser cookie.
|
|
1913
|
+
*
|
|
1914
|
+
* Recommended for clients, but optional for the authorization server.
|
|
1915
|
+
*
|
|
1916
|
+
* Note: Better Auth stores the state in a database instead of a cookie. - This is to minimize
|
|
1917
|
+
* the complication with native apps and other clients that may not have access to cookies.
|
|
1918
|
+
*/
|
|
1919
|
+
state?: string;
|
|
1920
|
+
/**
|
|
1921
|
+
* The client ID. Must be the ID of a registered client.
|
|
1922
|
+
*/
|
|
1923
|
+
client_id: string;
|
|
1924
|
+
/**
|
|
1925
|
+
* The prompt parameter is used to specify the type of user interaction that is required.
|
|
1926
|
+
*/
|
|
1927
|
+
prompt?: AuthorizePrompt;
|
|
1928
|
+
/**
|
|
1929
|
+
* The display parameter is used to specify how the authorization server displays the
|
|
1930
|
+
* authentication and consent user interface pages to the end user.
|
|
1931
|
+
*/
|
|
1932
|
+
display?: "page" | "popup" | "touch" | "wap";
|
|
1933
|
+
/**
|
|
1934
|
+
* End-User's preferred languages and scripts for the user interface, represented as a
|
|
1935
|
+
* space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. For
|
|
1936
|
+
* instance, the value "fr-CA fr en" represents a preference for French as spoken in Canada,
|
|
1937
|
+
* then French (without a region designation), followed by English (without a region
|
|
1938
|
+
* designation).
|
|
1939
|
+
*
|
|
1940
|
+
* Better Auth does not support this parameter yet. It'll not throw an error if it's provided,
|
|
1941
|
+
*
|
|
1942
|
+
* 🏗️ currently not implemented
|
|
1943
|
+
*/
|
|
1944
|
+
ui_locales?: string;
|
|
1945
|
+
/**
|
|
1946
|
+
* The maximum authentication age.
|
|
1947
|
+
*
|
|
1948
|
+
* Specifies the allowable elapsed time in seconds since the last time the End-User was
|
|
1949
|
+
* actively authenticated by the provider. If the elapsed time is greater than this value, the
|
|
1950
|
+
* provider MUST attempt to actively re-authenticate the End-User.
|
|
1951
|
+
*
|
|
1952
|
+
* Note that max_age=0 is equivalent to prompt=login.
|
|
1953
|
+
*/
|
|
1954
|
+
max_age?: number;
|
|
1955
|
+
/**
|
|
1956
|
+
* Requested Authentication Context Class Reference values.
|
|
1957
|
+
*
|
|
1958
|
+
* Space-separated string that
|
|
1959
|
+
* specifies the acr values that the Authorization Server is being requested to use for
|
|
1960
|
+
* processing this Authentication Request, with the values appearing in order of preference.
|
|
1961
|
+
* The Authentication Context Class satisfied by the authentication performed is returned as
|
|
1962
|
+
* the acr Claim Value, as specified in Section 2. The acr Claim is requested as a Voluntary
|
|
1963
|
+
* Claim by this parameter.
|
|
1964
|
+
*/
|
|
1965
|
+
acr_values?: string;
|
|
1966
|
+
/**
|
|
1967
|
+
* Hint to the Authorization Server about the login identifier the End-User might use to log in
|
|
1968
|
+
* (if necessary). This hint can be used by an RP if it first asks the End-User for their
|
|
1969
|
+
* e-mail address (or other identifier) and then wants to pass that value as a hint to the
|
|
1970
|
+
* discovered authorization service. It is RECOMMENDED that the hint value match the value used
|
|
1971
|
+
* for discovery. This value MAY also be a phone number in the format specified for the
|
|
1972
|
+
* phone_number Claim. The use of this parameter is left to the OP's discretion.
|
|
1973
|
+
*/
|
|
1974
|
+
login_hint?: string;
|
|
1975
|
+
/**
|
|
1976
|
+
* ID Token previously issued by the Authorization Server being passed as a hint about the
|
|
1977
|
+
* End-User's current or past authenticated session with the Client.
|
|
1978
|
+
*
|
|
1979
|
+
* 🏗️ currently not implemented
|
|
1980
|
+
*/
|
|
1981
|
+
id_token_hint?: string;
|
|
1982
|
+
/**
|
|
1983
|
+
* Code challenge
|
|
1984
|
+
*/
|
|
1985
|
+
code_challenge?: string;
|
|
1986
|
+
/**
|
|
1987
|
+
* Code challenge method used
|
|
1988
|
+
*/
|
|
1989
|
+
code_challenge_method?: "S256";
|
|
1990
|
+
/**
|
|
1991
|
+
* String value used to associate a Client session with an ID Token, and to mitigate replay
|
|
1992
|
+
* attacks. The value is passed through unmodified from the Authentication Request to the ID Token.
|
|
1993
|
+
* If present in the ID Token, Clients MUST verify that the nonce Claim Value is equal to the
|
|
1994
|
+
* value of the nonce parameter sent in the Authentication Request. If present in the
|
|
1995
|
+
* Authentication Request, Authorization Servers MUST include a nonce Claim in the ID Token
|
|
1996
|
+
* with the Claim Value being the nonce value sent in the Authentication Request.
|
|
1997
|
+
*/
|
|
1998
|
+
nonce?: string;
|
|
1999
|
+
/**
|
|
2000
|
+
* OIDC Claims request parameter. In an authorization request it is a
|
|
2001
|
+
* form-encoded JSON string; Request Object resolvers may provide the parsed
|
|
2002
|
+
* object form.
|
|
2003
|
+
*
|
|
2004
|
+
* @see https://openid.net/specs/openid-connect-core-1_0.html#ClaimsParameter
|
|
2005
|
+
*/
|
|
2006
|
+
claims?: string | Record<string, unknown>;
|
|
2007
|
+
/**
|
|
2008
|
+
* RFC 9449 authorization request parameter. When present, the authorization
|
|
2009
|
+
* code is bound to this JWK thumbprint and the token request must present a
|
|
2010
|
+
* matching DPoP proof.
|
|
2011
|
+
*/
|
|
2012
|
+
dpop_jkt?: string;
|
|
2013
|
+
/**
|
|
2014
|
+
* Resource parameter as specified by [RFC 8707](https://www.rfc-editor.org/rfc/rfc8707.html)
|
|
2015
|
+
*/
|
|
2016
|
+
resource?: string | string[];
|
|
2017
|
+
}
|
|
2018
|
+
/**
|
|
2019
|
+
* A persisted protected-resource row as stored in `oauthResource`.
|
|
2020
|
+
*
|
|
2021
|
+
* `null` on any policy column means "inherit the plugin-level default at
|
|
2022
|
+
* token issuance time" — admins can later override without re-seeding.
|
|
2023
|
+
*/
|
|
2024
|
+
interface OAuthResource {
|
|
2025
|
+
/** Auto-generated primary key */
|
|
2026
|
+
id: string;
|
|
2027
|
+
/**
|
|
2028
|
+
* Business key used in the `aud` claim and as the RFC 8707 `resource` value.
|
|
2029
|
+
*/
|
|
2030
|
+
identifier: string;
|
|
2031
|
+
/** Human-friendly label for admin UIs */
|
|
2032
|
+
name: string;
|
|
2033
|
+
/** Access token TTL in seconds; null inherits {@link OAuthOptions.accessTokenExpiresIn} */
|
|
2034
|
+
accessTokenTtl?: number | null;
|
|
2035
|
+
/** Refresh token TTL in seconds; null inherits {@link OAuthOptions.refreshTokenExpiresIn} */
|
|
2036
|
+
refreshTokenTtl?: number | null;
|
|
2037
|
+
/** When set, overrides the JWT plugin's getLatestKey() default at signing time. */
|
|
2038
|
+
signingAlgorithm?: JWSAlgorithms | null;
|
|
2039
|
+
signingKeyId?: string | null;
|
|
2040
|
+
/**
|
|
2041
|
+
* When non-null, requested scopes must intersect this set or the request is
|
|
2042
|
+
* rejected with `invalid_scope`.
|
|
2043
|
+
*/
|
|
2044
|
+
allowedScopes?: string[] | null;
|
|
2045
|
+
/**
|
|
2046
|
+
* Per-resource claims merged into the access token JWT payload. Reserved
|
|
2047
|
+
* RFC 9068 claim names (`iss`, `sub`, `aud`, `exp`, `iat`, `jti`,
|
|
2048
|
+
* `client_id`, `scope`, `auth_time`, `acr`, `amr`) are stripped at issuance
|
|
2049
|
+
* with a warning log — never silently dropped.
|
|
2050
|
+
*/
|
|
2051
|
+
customClaims?: Record<string, unknown> | null;
|
|
2052
|
+
/**
|
|
2053
|
+
* Require newly issued access tokens for this resource to be DPoP-bound.
|
|
2054
|
+
*/
|
|
2055
|
+
dpopBoundAccessTokensRequired?: boolean;
|
|
2056
|
+
/**
|
|
2057
|
+
* Disabled → no new issuance for this resource; existing tokens still verify
|
|
2058
|
+
* until natural expiry. Compare to delete, which hard-rejects existing tokens.
|
|
2059
|
+
*/
|
|
2060
|
+
disabled: boolean;
|
|
2061
|
+
createdAt: Date;
|
|
2062
|
+
updatedAt: Date;
|
|
2063
|
+
/**
|
|
2064
|
+
* Forward-migration anchor. Lets the runtime branch behavior when claim
|
|
2065
|
+
* emission or validation semantics change in a future PR without forcing
|
|
2066
|
+
* every row to migrate. PR 1 ships with `policyVersion = 1`.
|
|
2067
|
+
*/
|
|
2068
|
+
policyVersion: number;
|
|
2069
|
+
/** Open-ended extension data — not yet promoted to columns. */
|
|
2070
|
+
metadata?: Record<string, unknown> | null;
|
|
2071
|
+
}
|
|
2072
|
+
/**
|
|
2073
|
+
* Plugin-config input for {@link OAuthOptions.resources}. A subset of the
|
|
2074
|
+
* persisted {@link OAuthResource} — only `identifier` is required; the rest
|
|
2075
|
+
* fall back to plugin defaults when omitted.
|
|
2076
|
+
*/
|
|
2077
|
+
interface OAuthResourceInput {
|
|
2078
|
+
identifier: string;
|
|
2079
|
+
name?: string;
|
|
2080
|
+
accessTokenTtl?: number;
|
|
2081
|
+
refreshTokenTtl?: number;
|
|
2082
|
+
signingAlgorithm?: JWSAlgorithms;
|
|
2083
|
+
signingKeyId?: string;
|
|
2084
|
+
allowedScopes?: string[];
|
|
2085
|
+
customClaims?: Record<string, unknown>;
|
|
2086
|
+
dpopBoundAccessTokensRequired?: boolean;
|
|
2087
|
+
disabled?: boolean;
|
|
2088
|
+
metadata?: Record<string, unknown>;
|
|
2089
|
+
}
|
|
2090
|
+
/**
|
|
2091
|
+
* A row of `oauthClientResource` linking a client to a resource.
|
|
2092
|
+
*
|
|
2093
|
+
* Authoritative only when {@link OAuthOptions.enforcePerClientResources} is true.
|
|
2094
|
+
*/
|
|
2095
|
+
interface OAuthClientResource {
|
|
2096
|
+
clientId: string;
|
|
2097
|
+
resourceId: string;
|
|
2098
|
+
metadata?: Record<string, unknown> | null;
|
|
2099
|
+
createdAt: Date;
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* The authorization request as persisted alongside a minted code. Identical to
|
|
2103
|
+
* {@link OAuthAuthorizationQuery} except `redirect_uri` is optional: a headless
|
|
2104
|
+
* authorization request (first-party-apps / device-style) carries none, and
|
|
2105
|
+
* RFC 6749 §4.1.3 only binds `redirect_uri` at the token endpoint when the
|
|
2106
|
+
* authorization request included one. Mirrors the runtime
|
|
2107
|
+
* `storedAuthorizationQuerySchema`.
|
|
2108
|
+
*/
|
|
2109
|
+
interface StoredAuthorizationQuery extends Omit<OAuthAuthorizationQuery, "redirect_uri"> {
|
|
2110
|
+
redirect_uri?: string;
|
|
2111
|
+
}
|
|
2112
|
+
/**
|
|
2113
|
+
* Stored within the verification.value field
|
|
2114
|
+
* in JSON format.
|
|
2115
|
+
*
|
|
2116
|
+
* It is stored in JSON to prevent
|
|
2117
|
+
* direct searches by field on the db
|
|
2118
|
+
*/
|
|
2119
|
+
interface VerificationValue {
|
|
2120
|
+
type: "authorization_code";
|
|
2121
|
+
query: StoredAuthorizationQuery;
|
|
2122
|
+
sessionId: string;
|
|
2123
|
+
userId: string;
|
|
2124
|
+
resource?: string[];
|
|
2125
|
+
referenceId?: string;
|
|
2126
|
+
authTime?: number;
|
|
2127
|
+
}
|
|
2128
|
+
/**
|
|
2129
|
+
* Client registered values as used within the plugin
|
|
2130
|
+
*/
|
|
2131
|
+
interface SchemaClient<Scopes extends readonly Scope[] = InternallySupportedScopes[]> {
|
|
2132
|
+
/**
|
|
2133
|
+
* Client ID
|
|
2134
|
+
*
|
|
2135
|
+
* size 32
|
|
2136
|
+
*
|
|
2137
|
+
* as described on https://www.rfc-editor.org/rfc/rfc6749.html#section-2.2
|
|
2138
|
+
*/
|
|
2139
|
+
clientId: string;
|
|
2140
|
+
/**
|
|
2141
|
+
* Client Secret
|
|
2142
|
+
*
|
|
2143
|
+
* A secret for the client, if required by the authorization server.
|
|
2144
|
+
*
|
|
2145
|
+
* size 32
|
|
2146
|
+
*/
|
|
2147
|
+
clientSecret?: string;
|
|
2148
|
+
/** Whether the client is disabled or not. */
|
|
2149
|
+
disabled?: boolean;
|
|
2150
|
+
/**
|
|
2151
|
+
* Restricts scopes allowed for the client.
|
|
2152
|
+
*
|
|
2153
|
+
* If not defined, any scope can be requested.
|
|
2154
|
+
*/
|
|
2155
|
+
scopes?: Scopes;
|
|
2156
|
+
/** User who owns this client */
|
|
2157
|
+
userId?: string | null;
|
|
2158
|
+
/** Created time */
|
|
2159
|
+
createdAt?: Date;
|
|
2160
|
+
/** Last updated time */
|
|
2161
|
+
updatedAt?: Date;
|
|
2162
|
+
/** Expires time */
|
|
2163
|
+
expiresAt?: Date;
|
|
2164
|
+
/** The name of the client. */
|
|
2165
|
+
name?: string;
|
|
2166
|
+
/** Linkable uri of the client. */
|
|
2167
|
+
uri?: string;
|
|
2168
|
+
/** The icon of the client. */
|
|
2169
|
+
icon?: string;
|
|
2170
|
+
/** List of contacts for the client. */
|
|
2171
|
+
contacts?: string[];
|
|
2172
|
+
/** Client Terms of Service Uri */
|
|
2173
|
+
tos?: string;
|
|
2174
|
+
/** Client Privacy Policy Uri */
|
|
2175
|
+
policy?: string;
|
|
2176
|
+
softwareId?: string;
|
|
2177
|
+
softwareVersion?: string;
|
|
2178
|
+
softwareStatement?: string;
|
|
2179
|
+
/**
|
|
2180
|
+
* List of registered redirect URLs. Must include the whole URL, including the protocol, port,
|
|
2181
|
+
* and path.
|
|
2182
|
+
*
|
|
2183
|
+
* For example, `https://example.com/auth/callback`
|
|
2184
|
+
*/
|
|
2185
|
+
redirectUris?: string[];
|
|
2186
|
+
/**
|
|
2187
|
+
* List of registered post-logout redirect URIs. Used for RP-Initiated Logout.
|
|
2188
|
+
* Must include the whole URL, including the protocol, port, and path.
|
|
2189
|
+
*
|
|
2190
|
+
* For example, `https://example.com/logout/callback`
|
|
2191
|
+
*/
|
|
2192
|
+
postLogoutRedirectUris?: string[];
|
|
2193
|
+
/**
|
|
2194
|
+
* RP URL that will receive a signed Logout Token when the end-user's OP
|
|
2195
|
+
* session ends. Registering it is the per-client opt-in for back-channel
|
|
2196
|
+
* logout. Must be absolute, without a fragment, and HTTPS for confidential
|
|
2197
|
+
* clients.
|
|
2198
|
+
*
|
|
2199
|
+
* @see https://openid.net/specs/openid-connect-backchannel-1_0.html#RPMetadata
|
|
2200
|
+
*/
|
|
2201
|
+
backchannelLogoutUri?: string;
|
|
2202
|
+
/**
|
|
2203
|
+
* When true, the RP requires the `sid` claim in every Logout Token.
|
|
2204
|
+
* User-scoped (sid-less) logouts are not dispatched to such a client.
|
|
2205
|
+
*
|
|
2206
|
+
* @default false
|
|
2207
|
+
*/
|
|
2208
|
+
backchannelLogoutSessionRequired?: boolean;
|
|
2209
|
+
tokenEndpointAuthMethod?: TokenEndpointAuthMethod;
|
|
2210
|
+
grantTypes?: GrantType[];
|
|
2211
|
+
responseTypes?: "code"[];
|
|
2212
|
+
/** Client's JSON Web Key Set metadata. Mutually exclusive with `jwksUri`. */
|
|
2213
|
+
jwks?: string;
|
|
2214
|
+
/** URI for the client's JSON Web Key Set. Mutually exclusive with `jwks`. Must be HTTPS. */
|
|
2215
|
+
jwksUri?: string;
|
|
2216
|
+
/**
|
|
2217
|
+
* Indicates whether the client is public or confidential.
|
|
2218
|
+
* If public, refreshing tokens doesn't require
|
|
2219
|
+
* a client_secret. Clients are considered confidential by default.
|
|
2220
|
+
*
|
|
2221
|
+
* Uses `token_endpoint_auth_method` field or `type` field to determine
|
|
2222
|
+
*
|
|
2223
|
+
* Described https://www.rfc-editor.org/rfc/rfc6749.html#section-2.1
|
|
2224
|
+
*
|
|
2225
|
+
* @default undefined
|
|
2226
|
+
*/
|
|
2227
|
+
public?: boolean;
|
|
2228
|
+
/**
|
|
2229
|
+
* The client type
|
|
2230
|
+
*
|
|
2231
|
+
* Described https://www.rfc-editor.org/rfc/rfc6749.html#section-2.1
|
|
2232
|
+
*
|
|
2233
|
+
* - web - A web application (confidential client)
|
|
2234
|
+
* - native - A mobile application (public client)
|
|
2235
|
+
* - user-agent-based - A user-agent-based application (public client)
|
|
2236
|
+
*/
|
|
2237
|
+
type?: "web" | "native" | "user-agent-based";
|
|
2238
|
+
/**
|
|
2239
|
+
* Whether this client requires PKCE for authorization code flow.
|
|
2240
|
+
*
|
|
2241
|
+
* @default true
|
|
2242
|
+
*
|
|
2243
|
+
* Note: PKCE is always required for public clients and when
|
|
2244
|
+
* requesting offline_access scope, regardless of this setting.
|
|
2245
|
+
*/
|
|
2246
|
+
requirePKCE?: boolean;
|
|
2247
|
+
/**
|
|
2248
|
+
* RFC 9449 dynamic client metadata. When true, every token request from this
|
|
2249
|
+
* client must include a valid DPoP proof and receive DPoP-bound tokens.
|
|
2250
|
+
*/
|
|
2251
|
+
dpopBoundAccessTokens?: boolean;
|
|
2252
|
+
/** Used to indicate if consent screen can be skipped */
|
|
2253
|
+
skipConsent?: boolean;
|
|
2254
|
+
/** Used to enable client to logout via the `/oauth2/end-session` endpoint */
|
|
2255
|
+
enableEndSession?: boolean;
|
|
2256
|
+
/** Subject identifier type: "public" (default) or "pairwise" */
|
|
2257
|
+
subjectType?: "public" | "pairwise";
|
|
2258
|
+
/** Reference to the owner of this client. Eg. Organization, Team, Profile */
|
|
2259
|
+
referenceId?: string;
|
|
2260
|
+
/**
|
|
2261
|
+
* Additional metadata about the client.
|
|
2262
|
+
*/
|
|
2263
|
+
metadata?: string;
|
|
2264
|
+
}
|
|
2265
|
+
interface OAuthOpaqueAccessToken<Scopes extends readonly Scope[] = InternallySupportedScopes[]> {
|
|
2266
|
+
/**
|
|
2267
|
+
* The opaque access token.
|
|
2268
|
+
*/
|
|
2269
|
+
token: string;
|
|
2270
|
+
/**
|
|
2271
|
+
* The client ID of the client that requested the access token.
|
|
2272
|
+
*/
|
|
2273
|
+
clientId: string;
|
|
2274
|
+
/**
|
|
2275
|
+
* The session ID the access token is associated with.
|
|
2276
|
+
*
|
|
2277
|
+
* Not available in client credentials grant
|
|
2278
|
+
* where no user session is involved.
|
|
2279
|
+
*/
|
|
2280
|
+
sessionId?: string;
|
|
2281
|
+
/**
|
|
2282
|
+
* The user ID the access token is associated with.
|
|
2283
|
+
*
|
|
2284
|
+
* Not available in client credentials grant
|
|
2285
|
+
* where no user is involved.
|
|
2286
|
+
*/
|
|
2287
|
+
userId?: string;
|
|
2288
|
+
/**
|
|
2289
|
+
* Reference Id of the consent/authorization.
|
|
2290
|
+
*
|
|
2291
|
+
* Not available in client credentials grant
|
|
2292
|
+
* where no user is involved.
|
|
2293
|
+
*/
|
|
2294
|
+
referenceId?: string;
|
|
2295
|
+
/**
|
|
2296
|
+
* Stored authorization-code identifier that produced this token family.
|
|
2297
|
+
* Used to revoke tokens after authorization-code replay is detected.
|
|
2298
|
+
*/
|
|
2299
|
+
authorizationCodeId?: string;
|
|
2300
|
+
/**
|
|
2301
|
+
* The refresh token the access token is associated with.
|
|
2302
|
+
*
|
|
2303
|
+
* Not available without the "offline_access" scope
|
|
2304
|
+
*/
|
|
2305
|
+
refreshId?: string;
|
|
2306
|
+
/** The expiration date of the access token. */
|
|
2307
|
+
expiresAt: Date;
|
|
2308
|
+
/** The creation date of the access token. */
|
|
2309
|
+
createdAt: Date;
|
|
2310
|
+
/**
|
|
2311
|
+
* When the access token was revoked. Set by session-end dispatch, the
|
|
2312
|
+
* revoke endpoint, and back-channel logout. Introspection and protected
|
|
2313
|
+
* endpoints MUST treat a revoked token as inactive.
|
|
2314
|
+
*/
|
|
2315
|
+
revoked?: Date | null;
|
|
2316
|
+
/**
|
|
2317
|
+
* Scope granted for the access token.
|
|
2318
|
+
*
|
|
2319
|
+
* Shall match the refreshId.scopes if refreshId is provided.
|
|
2320
|
+
*/
|
|
2321
|
+
scopes: Scopes;
|
|
2322
|
+
/**
|
|
2323
|
+
* Resources allowed for this access token.
|
|
2324
|
+
*/
|
|
2325
|
+
resources?: string[];
|
|
2326
|
+
/**
|
|
2327
|
+
* OIDC UserInfo claim names requested by the authorization request's
|
|
2328
|
+
* `claims.userinfo` object.
|
|
2329
|
+
*/
|
|
2330
|
+
requestedUserInfoClaims?: string[];
|
|
2331
|
+
/**
|
|
2332
|
+
* RFC 7800 `cnf` confirmation that sender-constrains this access token (for
|
|
2333
|
+
* example DPoP `{ jkt }`). Surfaced as the `cnf` claim at introspection.
|
|
2334
|
+
*/
|
|
2335
|
+
confirmation?: Confirmation;
|
|
2336
|
+
}
|
|
2337
|
+
/**
|
|
2338
|
+
* Refresh Token Database Schema
|
|
2339
|
+
*/
|
|
2340
|
+
interface OAuthRefreshToken<Scopes extends readonly Scope[] = InternallySupportedScopes[]> {
|
|
2341
|
+
token: string;
|
|
2342
|
+
sessionId?: string;
|
|
2343
|
+
userId: string;
|
|
2344
|
+
referenceId?: string;
|
|
2345
|
+
authorizationCodeId?: string;
|
|
2346
|
+
clientId?: string;
|
|
2347
|
+
expiresAt: Date;
|
|
2348
|
+
createdAt: Date;
|
|
2349
|
+
/**
|
|
2350
|
+
* When this token stopped being active.
|
|
2351
|
+
*
|
|
2352
|
+
* A token can be revoked by /oauth2/revoke or consumed by rotation. Use
|
|
2353
|
+
* `rotatedAt` to distinguish rotation from explicit revocation.
|
|
2354
|
+
*/
|
|
2355
|
+
revoked?: Date;
|
|
2356
|
+
/**
|
|
2357
|
+
* When this refresh token was consumed by rotation.
|
|
2358
|
+
*/
|
|
2359
|
+
rotatedAt?: Date;
|
|
2360
|
+
/**
|
|
2361
|
+
* Encrypted token endpoint response and request fingerprint to replay during
|
|
2362
|
+
* the configured refresh-token reuse interval.
|
|
2363
|
+
*/
|
|
2364
|
+
rotationReplayResponse?: string;
|
|
2365
|
+
/**
|
|
2366
|
+
* When the cached rotation response stops being replayable.
|
|
2367
|
+
*/
|
|
2368
|
+
rotationReplayExpiresAt?: Date;
|
|
2369
|
+
/**
|
|
2370
|
+
* The time the user originally authenticated.
|
|
2371
|
+
* Persisted so refreshed ID tokens can include a correct `auth_time` claim.
|
|
2372
|
+
*/
|
|
2373
|
+
authTime?: Date;
|
|
2374
|
+
/**
|
|
2375
|
+
* Scopes granted for this refresh token.
|
|
2376
|
+
*
|
|
2377
|
+
* Considered Immutable once granted.
|
|
2378
|
+
*/
|
|
2379
|
+
scopes: Scopes;
|
|
2380
|
+
/**
|
|
2381
|
+
* Resources allowed for this refresh token
|
|
2382
|
+
*/
|
|
2383
|
+
resources?: string[];
|
|
2384
|
+
/**
|
|
2385
|
+
* OIDC UserInfo claim names requested by the authorization request's
|
|
2386
|
+
* `claims.userinfo` object. Carried forward on rotation.
|
|
2387
|
+
*/
|
|
2388
|
+
requestedUserInfoClaims?: string[];
|
|
2389
|
+
/**
|
|
2390
|
+
* RFC 7800 `cnf` confirmation that sender-constrains this refresh-token
|
|
2391
|
+
* family (for example DPoP `{ jkt }`). Carried forward on rotation.
|
|
2392
|
+
*/
|
|
2393
|
+
confirmation?: Confirmation;
|
|
2394
|
+
}
|
|
2395
|
+
/**
|
|
2396
|
+
* Consent Database Schema
|
|
2397
|
+
*/
|
|
2398
|
+
type OAuthConsent<Scopes extends readonly Scope[] = InternallySupportedScopes[]> = {
|
|
2399
|
+
id: string;
|
|
2400
|
+
clientId: string;
|
|
2401
|
+
userId: string;
|
|
2402
|
+
resources?: string[];
|
|
2403
|
+
referenceId?: string;
|
|
2404
|
+
/**
|
|
2405
|
+
* OIDC UserInfo claim names consented from the authorization request's
|
|
2406
|
+
* `claims.userinfo` object.
|
|
2407
|
+
*/
|
|
2408
|
+
requestedUserInfoClaims?: string[];
|
|
2409
|
+
scopes: Scopes;
|
|
2410
|
+
createdAt: Date;
|
|
2411
|
+
updatedAt: Date;
|
|
2412
|
+
};
|
|
2413
|
+
//#endregion
|
|
2414
|
+
//#region src/types/oauth.d.ts
|
|
2415
|
+
/**
|
|
2416
|
+
* Supported grant types of the token endpoint
|
|
2417
|
+
*/
|
|
2418
|
+
type BuiltInGrantType = "authorization_code" | "client_credentials" | "refresh_token";
|
|
2419
|
+
type GrantType = BuiltInGrantType | (string & {});
|
|
2420
|
+
type BuiltInAuthMethod = "client_secret_basic" | "client_secret_post" | "private_key_jwt";
|
|
2421
|
+
type AuthMethod = BuiltInAuthMethod | (string & {});
|
|
2422
|
+
type TokenEndpointAuthMethod = AuthMethod | "none";
|
|
2423
|
+
type BearerMethodsSupported = "header" | "body";
|
|
2424
|
+
/**
|
|
2425
|
+
* RFC 7800 `cnf` (confirmation) members that sender-constrain an access token to
|
|
2426
|
+
* a key the client must prove possession of. Each binding mechanism populates
|
|
2427
|
+
* one member of the same object: DPoP sets `jkt` (RFC 9449 §6), mTLS sets
|
|
2428
|
+
* `x5t#S256` (RFC 8705 §3.1). The authorization server is the sole authority
|
|
2429
|
+
* over this value; it is token material, never a contributed claim.
|
|
2430
|
+
*/
|
|
2431
|
+
type Confirmation = {
|
|
2432
|
+
jkt: string;
|
|
2433
|
+
} | {
|
|
2434
|
+
"x5t#S256": string;
|
|
2435
|
+
};
|
|
2436
|
+
/**
|
|
2437
|
+
* Token presentation scheme returned in `token_type`. A DPoP-bound token uses
|
|
2438
|
+
* `"DPoP"` (RFC 9449 §5); everything else (including mTLS-bound) uses
|
|
2439
|
+
* `"Bearer"`, since the mTLS constraint lives at the TLS layer.
|
|
2440
|
+
*/
|
|
2441
|
+
type TokenType = "Bearer" | "DPoP";
|
|
2442
|
+
/**
|
|
2443
|
+
* Metadata for authentication servers.
|
|
2444
|
+
*
|
|
2445
|
+
* @see https://datatracker.ietf.org/doc/html/rfc8414#section-2
|
|
2446
|
+
*/
|
|
2447
|
+
interface AuthServerMetadata {
|
|
2448
|
+
/**
|
|
2449
|
+
* The issuer identifier, this is the URL of the provider and can be used to verify
|
|
2450
|
+
* the `iss` claim in the ID token.
|
|
2451
|
+
*
|
|
2452
|
+
* default: the value set for the issuer in the jwt plugin,
|
|
2453
|
+
* otherwise the base URL of the auth server (e.g. `https://example.com`)
|
|
2454
|
+
*/
|
|
2455
|
+
issuer: string;
|
|
2456
|
+
/**
|
|
2457
|
+
* The URL of the authorization endpoint.
|
|
2458
|
+
*
|
|
2459
|
+
* @default `/oauth2/authorize`
|
|
2460
|
+
*/
|
|
2461
|
+
authorization_endpoint: string;
|
|
2462
|
+
/**
|
|
2463
|
+
* The URL of the token endpoint.
|
|
2464
|
+
*
|
|
2465
|
+
* @default `/oauth2/token`
|
|
2466
|
+
*/
|
|
2467
|
+
token_endpoint: string;
|
|
2468
|
+
/**
|
|
2469
|
+
* The URL of the jwks_uri endpoint.
|
|
2470
|
+
*
|
|
2471
|
+
* For JWKS to work, you must install the `jwt` plugin.
|
|
2472
|
+
*
|
|
2473
|
+
* This value is automatically set to `/jwks` if the `jwt` plugin is installed.
|
|
2474
|
+
*
|
|
2475
|
+
* @default `/jwks`
|
|
2476
|
+
*/
|
|
2477
|
+
jwks_uri?: string;
|
|
2478
|
+
/**
|
|
2479
|
+
* The URL of the dynamic client registration endpoint.
|
|
2480
|
+
*
|
|
2481
|
+
* This field is only present when `allowDynamicClientRegistration` is enabled.
|
|
2482
|
+
*
|
|
2483
|
+
* @default `/oauth2/register`
|
|
2484
|
+
*/
|
|
2485
|
+
registration_endpoint?: string;
|
|
2486
|
+
/**
|
|
2487
|
+
* Supported scopes.
|
|
2488
|
+
*/
|
|
2489
|
+
scopes_supported?: string[];
|
|
2490
|
+
/**
|
|
2491
|
+
* Supported response types. (for /authorize endpoint)
|
|
2492
|
+
*/
|
|
2493
|
+
response_types_supported: "code"[];
|
|
2494
|
+
/**
|
|
2495
|
+
* Supported response modes.
|
|
2496
|
+
*
|
|
2497
|
+
* `query`: the authorization code is returned in the query string
|
|
2498
|
+
*/
|
|
2499
|
+
response_modes_supported: "query"[];
|
|
2500
|
+
/**
|
|
2501
|
+
* Supported grant types.
|
|
2502
|
+
*/
|
|
2503
|
+
grant_types_supported: GrantType[];
|
|
2504
|
+
/**
|
|
2505
|
+
* Supported token endpoint authentication methods.
|
|
2506
|
+
*
|
|
2507
|
+
* @default
|
|
2508
|
+
* ["client_secret_basic", "client_secret_post"]
|
|
2509
|
+
*/
|
|
2510
|
+
token_endpoint_auth_methods_supported?: TokenEndpointAuthMethod[];
|
|
2511
|
+
/**
|
|
2512
|
+
* Array containing a list of the JWS signing
|
|
2513
|
+
* algorithms ("alg" values) supported by the token endpoint for
|
|
2514
|
+
* the signature on the JWT used to authenticate the client at the
|
|
2515
|
+
* token endpoint for the "private_key_jwt" and "client_secret_jwt"
|
|
2516
|
+
* authentication methods (see field token_endpoint_auth_methods_supported).
|
|
2517
|
+
*/
|
|
2518
|
+
token_endpoint_auth_signing_alg_values_supported?: PrivateKeyJwtSigningAlgorithm[];
|
|
2519
|
+
/**
|
|
2520
|
+
* URL of a page containing human-readable information
|
|
2521
|
+
* that developers might want or need to know when using the
|
|
2522
|
+
* authorization server
|
|
2523
|
+
*/
|
|
2524
|
+
service_documentation?: string;
|
|
2525
|
+
/**
|
|
2526
|
+
* Languages and scripts supported for the user interface,
|
|
2527
|
+
* represented as an array of language tag values from BCP 47
|
|
2528
|
+
* [RFC5646](https://datatracker.ietf.org/doc/html/rfc5646)
|
|
2529
|
+
*/
|
|
2530
|
+
ui_locales_supported?: string[];
|
|
2531
|
+
/**
|
|
2532
|
+
* URL that the authorization server provides to the
|
|
2533
|
+
* person registering the client to read about the authorization
|
|
2534
|
+
* server's requirements on how the client can use the data provided
|
|
2535
|
+
* by the authorization server.
|
|
2536
|
+
*/
|
|
2537
|
+
op_policy_uri?: string;
|
|
2538
|
+
/**
|
|
2539
|
+
* URL that the authorization server provides to the
|
|
2540
|
+
* person registering the client to read about the authorization
|
|
2541
|
+
* server's terms of service.
|
|
2542
|
+
*/
|
|
2543
|
+
op_tos_uri?: string;
|
|
2544
|
+
/**
|
|
2545
|
+
* URL of the authorization server's OAuth 2.0 revocation
|
|
2546
|
+
* endpoint [RFC7009](https://datatracker.ietf.org/doc/html/rfc7009)
|
|
2547
|
+
*/
|
|
2548
|
+
revocation_endpoint?: string;
|
|
2549
|
+
/**
|
|
2550
|
+
* Array containing a list of client authentication
|
|
2551
|
+
* methods supported by this revocation endpoint
|
|
2552
|
+
*
|
|
2553
|
+
* @default
|
|
2554
|
+
* ["client_secret_basic", "client_secret_post"]
|
|
2555
|
+
*/
|
|
2556
|
+
revocation_endpoint_auth_methods_supported?: TokenEndpointAuthMethod[];
|
|
2557
|
+
/**
|
|
2558
|
+
* Array containing a list of the JWS signing
|
|
2559
|
+
* algorithms ("alg" values) supported by the revocation endpoint for
|
|
2560
|
+
* the signature on the JWT used to authenticate the client at the
|
|
2561
|
+
* token endpoint for the "private_key_jwt" and "client_secret_jwt"
|
|
2562
|
+
* authentication methods (see field revocation_endpoint_auth_methods_supported).
|
|
2563
|
+
*/
|
|
2564
|
+
revocation_endpoint_auth_signing_alg_values_supported?: PrivateKeyJwtSigningAlgorithm[];
|
|
2565
|
+
/**
|
|
2566
|
+
* URL of the authorization server's OAuth 2.0
|
|
2567
|
+
* introspection endpoint [RFC7662](https://datatracker.ietf.org/doc/html/rfc7662)
|
|
2568
|
+
*/
|
|
2569
|
+
introspection_endpoint?: string;
|
|
2570
|
+
/**
|
|
2571
|
+
* Array containing a list of client authentication
|
|
2572
|
+
* methods supported by this introspection endpoint
|
|
2573
|
+
*
|
|
2574
|
+
* @default
|
|
2575
|
+
* ["client_secret_basic", "client_secret_post"]
|
|
2576
|
+
*/
|
|
2577
|
+
introspection_endpoint_auth_methods_supported?: TokenEndpointAuthMethod[];
|
|
2578
|
+
/**
|
|
2579
|
+
* Array containing a list of the JWS signing
|
|
2580
|
+
* algorithms ("alg" values) supported by the introspection endpoint
|
|
2581
|
+
* used to authenticate the client at the token endpoint for
|
|
2582
|
+
* the "private_key_jwt" and "client_secret_jwt" authentication methods
|
|
2583
|
+
* (see field introspection_endpoint_auth_methods_supported).
|
|
2584
|
+
*/
|
|
2585
|
+
introspection_endpoint_auth_signing_alg_values_supported?: PrivateKeyJwtSigningAlgorithm[];
|
|
2586
|
+
/**
|
|
2587
|
+
* Supported code challenge methods.
|
|
2588
|
+
*
|
|
2589
|
+
* @default ["S256"]
|
|
2590
|
+
*/
|
|
2591
|
+
code_challenge_methods_supported: "S256"[];
|
|
2592
|
+
/**
|
|
2593
|
+
* Boolean value specifying whether the authorization server provides
|
|
2594
|
+
* the iss parameter in the authorization response (RFC 9207)
|
|
2595
|
+
*
|
|
2596
|
+
* @see https://datatracker.ietf.org/doc/html/rfc9207
|
|
2597
|
+
* @default true
|
|
2598
|
+
*/
|
|
2599
|
+
authorization_response_iss_parameter_supported?: boolean;
|
|
2600
|
+
/**
|
|
2601
|
+
* Whether the authorization server supports discovering clients via
|
|
2602
|
+
* [Client ID Metadata Documents](https://datatracker.ietf.org/doc/draft-ietf-oauth-client-id-metadata-document/)
|
|
2603
|
+
* (an HTTPS URL as `client_id`).
|
|
2604
|
+
*
|
|
2605
|
+
* Set at runtime by the `@better-auth/cimd` plugin (or any other
|
|
2606
|
+
* `ClientDiscovery` that contributes this field via
|
|
2607
|
+
* {@link ClientDiscovery.discoveryMetadata}). oauth-provider never sets
|
|
2608
|
+
* it on its own.
|
|
2609
|
+
*/
|
|
2610
|
+
client_id_metadata_document_supported?: boolean;
|
|
2611
|
+
/**
|
|
2612
|
+
* Boolean value specifying whether the OP supports back-channel logout,
|
|
2613
|
+
* with true indicating support.
|
|
2614
|
+
*
|
|
2615
|
+
* Registered in the "OAuth Authorization Server Metadata" IANA registry
|
|
2616
|
+
* under OpenID Connect Back-Channel Logout 1.0, so this may appear at both
|
|
2617
|
+
* `.well-known/oauth-authorization-server` and `.well-known/openid-configuration`.
|
|
2618
|
+
*
|
|
2619
|
+
* @default false
|
|
2620
|
+
* @see https://openid.net/specs/openid-connect-backchannel-1_0.html#OPMetadata
|
|
2621
|
+
*/
|
|
2622
|
+
backchannel_logout_supported?: boolean;
|
|
2623
|
+
/**
|
|
2624
|
+
* Boolean value specifying whether the OP can pass a `sid` (session ID)
|
|
2625
|
+
* Claim in the Logout Token to identify the RP session with the OP.
|
|
2626
|
+
*
|
|
2627
|
+
* When true, the OP also includes `sid` in ID Tokens it issues.
|
|
2628
|
+
*
|
|
2629
|
+
* @default false
|
|
2630
|
+
* @see https://openid.net/specs/openid-connect-backchannel-1_0.html#OPMetadata
|
|
2631
|
+
*/
|
|
2632
|
+
backchannel_logout_session_supported?: boolean;
|
|
2633
|
+
/**
|
|
2634
|
+
* JWS algorithms supported for RFC 9449 DPoP proof JWTs.
|
|
2635
|
+
*
|
|
2636
|
+
* @see https://datatracker.ietf.org/doc/html/rfc9449
|
|
2637
|
+
*/
|
|
2638
|
+
dpop_signing_alg_values_supported?: JWSAlgorithms[];
|
|
2639
|
+
}
|
|
2640
|
+
/**
|
|
2641
|
+
* Metadata returned by the openid-configuration endpoint:
|
|
2642
|
+
* /.well-known/openid-configuration
|
|
2643
|
+
*
|
|
2644
|
+
* NOTE: Url structure is different by appending to the end
|
|
2645
|
+
* of the url instead of the base.
|
|
2646
|
+
*
|
|
2647
|
+
* @see https://datatracker.ietf.org/doc/html/rfc8414#section-5
|
|
2648
|
+
*/
|
|
2649
|
+
interface OIDCMetadata extends AuthServerMetadata {
|
|
2650
|
+
/**
|
|
2651
|
+
* The URL of the userinfo endpoint.
|
|
2652
|
+
*
|
|
2653
|
+
* @default `/oauth2/userinfo`
|
|
2654
|
+
*/
|
|
2655
|
+
userinfo_endpoint: string;
|
|
2656
|
+
/**
|
|
2657
|
+
* Authentication Context Class Reference values supported.
|
|
2658
|
+
*
|
|
2659
|
+
* Better Auth does not advertise this field by default because it does not
|
|
2660
|
+
* currently evaluate requested Authentication Context Class References.
|
|
2661
|
+
*
|
|
2662
|
+
* @default
|
|
2663
|
+
* undefined
|
|
2664
|
+
* @see https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
|
|
2665
|
+
*/
|
|
2666
|
+
acr_values_supported?: string[];
|
|
2667
|
+
/**
|
|
2668
|
+
* Supported subject types.
|
|
2669
|
+
*
|
|
2670
|
+
* pairwise: the subject identifier is unique to the client
|
|
2671
|
+
* public: the subject identifier is unique to the server
|
|
2672
|
+
*
|
|
2673
|
+
* @see https://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
|
|
2674
|
+
*/
|
|
2675
|
+
subject_types_supported: ("public" | "pairwise")[];
|
|
2676
|
+
/**
|
|
2677
|
+
* Supported ID token signing algorithms.
|
|
2678
|
+
*
|
|
2679
|
+
* Automatically uses the same algorithm used in the JWK Plugin.
|
|
2680
|
+
* Support for symmetric algorithms is strictly prohibited
|
|
2681
|
+
* to sharing key vulnerabilities!
|
|
2682
|
+
*
|
|
2683
|
+
* @default
|
|
2684
|
+
* ["EdDSA"]
|
|
2685
|
+
*/
|
|
2686
|
+
id_token_signing_alg_values_supported: JWSAlgorithms[];
|
|
2687
|
+
/**
|
|
2688
|
+
* Supported claims.
|
|
2689
|
+
*
|
|
2690
|
+
* @default
|
|
2691
|
+
* ["sub", "iss", "aud", "exp", "nbf", "iat", "jti", "email", "email_verified", "name", "family_name", "given_name", "sid", "scope", "azp"]
|
|
2692
|
+
*/
|
|
2693
|
+
claims_supported: string[];
|
|
2694
|
+
/**
|
|
2695
|
+
* Whether the OP supports the OIDC `claims` request parameter.
|
|
2696
|
+
*
|
|
2697
|
+
* @default true
|
|
2698
|
+
* @see https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
|
|
2699
|
+
*/
|
|
2700
|
+
claims_parameter_supported?: boolean;
|
|
2701
|
+
/**
|
|
2702
|
+
* RP-Initiated Logout Endpoint
|
|
2703
|
+
*
|
|
2704
|
+
* @see https://openid.net/specs/openid-connect-rpinitiated-1_0.html
|
|
2705
|
+
*/
|
|
2706
|
+
end_session_endpoint: string;
|
|
2707
|
+
/**
|
|
2708
|
+
* Whether the OP supports OpenID Connect Request Objects by value.
|
|
2709
|
+
*
|
|
2710
|
+
* @default false
|
|
2711
|
+
* @see https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
|
|
2712
|
+
*/
|
|
2713
|
+
request_parameter_supported?: boolean;
|
|
2714
|
+
/**
|
|
2715
|
+
* Whether the OP supports OpenID Connect Request Objects by reference.
|
|
2716
|
+
*
|
|
2717
|
+
* Discovery defaults this field to true when omitted, so providers that do
|
|
2718
|
+
* not support it should advertise false explicitly.
|
|
2719
|
+
*
|
|
2720
|
+
* @default false
|
|
2721
|
+
* @see https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata
|
|
2722
|
+
*/
|
|
2723
|
+
request_uri_parameter_supported?: boolean;
|
|
2724
|
+
/**
|
|
2725
|
+
* Prompt values supported by this OIDC server
|
|
2726
|
+
*
|
|
2727
|
+
* @see https://openid.net/specs/openid-connect-prompt-create-1_0.html#OpenID.Discovery
|
|
2728
|
+
*/
|
|
2729
|
+
prompt_values_supported: Prompt[];
|
|
2730
|
+
}
|
|
2731
|
+
/**
|
|
2732
|
+
* OAuth 2.0 Dynamic Client Registration Schema
|
|
2733
|
+
*
|
|
2734
|
+
* Current spec is based on OAuth 2.0, but shall use
|
|
2735
|
+
* OAuth 2.1 restrictions.
|
|
2736
|
+
*
|
|
2737
|
+
* https://datatracker.ietf.org/doc/html/rfc7591#section-2
|
|
2738
|
+
*/
|
|
2739
|
+
interface OAuthClient {
|
|
2740
|
+
client_id: string;
|
|
2741
|
+
client_secret?: string;
|
|
2742
|
+
client_secret_expires_at?: number;
|
|
2743
|
+
scope?: string;
|
|
2744
|
+
user_id?: string | null;
|
|
2745
|
+
client_id_issued_at?: number;
|
|
2746
|
+
client_name?: string;
|
|
2747
|
+
client_uri?: string;
|
|
2748
|
+
logo_uri?: string;
|
|
2749
|
+
contacts?: string[];
|
|
2750
|
+
tos_uri?: string;
|
|
2751
|
+
policy_uri?: string;
|
|
2752
|
+
/** JWK Set — accepts either a bare key array or an RFC 7517 JWKS object `{"keys":[...]}` */
|
|
2753
|
+
jwks?: Record<string, unknown>[] | {
|
|
2754
|
+
keys: Record<string, unknown>[];
|
|
2755
|
+
};
|
|
2756
|
+
jwks_uri?: string;
|
|
2757
|
+
software_id?: string;
|
|
2758
|
+
software_version?: string;
|
|
2759
|
+
software_statement?: string;
|
|
2760
|
+
redirect_uris: string[];
|
|
2761
|
+
post_logout_redirect_uris?: string[];
|
|
2762
|
+
/**
|
|
2763
|
+
* RP URL that the OP POSTs a signed Logout Token to when a session at the OP
|
|
2764
|
+
* ends. The RP uses the token to terminate its own session state for that
|
|
2765
|
+
* user (including any access tokens it has bound to the session).
|
|
2766
|
+
*
|
|
2767
|
+
* @see https://openid.net/specs/openid-connect-backchannel-1_0.html#RPMetadata
|
|
2768
|
+
*/
|
|
2769
|
+
backchannel_logout_uri?: string;
|
|
2770
|
+
/**
|
|
2771
|
+
* When true, the RP requires the `sid` Claim in every Logout Token it
|
|
2772
|
+
* receives; the OP will not dispatch user-scoped (sid-less) logouts to it.
|
|
2773
|
+
*
|
|
2774
|
+
* @default false
|
|
2775
|
+
* @see https://openid.net/specs/openid-connect-backchannel-1_0.html#RPMetadata
|
|
2776
|
+
*/
|
|
2777
|
+
backchannel_logout_session_required?: boolean;
|
|
2778
|
+
token_endpoint_auth_method?: TokenEndpointAuthMethod;
|
|
2779
|
+
grant_types?: GrantType[];
|
|
2780
|
+
response_types?: "code"[];
|
|
2781
|
+
public?: boolean;
|
|
2782
|
+
type?: "web" | "native" | "user-agent-based";
|
|
2783
|
+
disabled?: boolean;
|
|
2784
|
+
skip_consent?: boolean;
|
|
2785
|
+
enable_end_session?: boolean;
|
|
2786
|
+
/**
|
|
2787
|
+
* Whether this client requires PKCE for authorization code flow.
|
|
2788
|
+
*
|
|
2789
|
+
* @default true
|
|
2790
|
+
*
|
|
2791
|
+
* Note: PKCE is always required for public clients. When requesting
|
|
2792
|
+
* offline_access without PKCE, confidential OIDC clients must send both
|
|
2793
|
+
* `openid` and `nonce`.
|
|
2794
|
+
*/
|
|
2795
|
+
require_pkce?: boolean;
|
|
2796
|
+
/**
|
|
2797
|
+
* RFC 9449 dynamic client metadata. When true, token requests from this
|
|
2798
|
+
* client must include a valid DPoP proof and receive DPoP-bound access
|
|
2799
|
+
* tokens.
|
|
2800
|
+
*/
|
|
2801
|
+
dpop_bound_access_tokens?: boolean;
|
|
2802
|
+
/**
|
|
2803
|
+
* Subject identifier type for this client.
|
|
2804
|
+
*
|
|
2805
|
+
* @see https://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes
|
|
2806
|
+
*/
|
|
2807
|
+
subject_type?: "public" | "pairwise";
|
|
2808
|
+
reference_id?: string;
|
|
2809
|
+
[key: string]: unknown;
|
|
2810
|
+
}
|
|
2811
|
+
/**
|
|
2812
|
+
* Resource metadata server as defined by RFC 9728
|
|
2813
|
+
*
|
|
2814
|
+
* @see https://datatracker.ietf.org/doc/html/rfc9728#Terminology
|
|
2815
|
+
*/
|
|
2816
|
+
interface ResourceServerMetadata {
|
|
2817
|
+
/**
|
|
2818
|
+
* The protected resource's resource identifier,
|
|
2819
|
+
* which is a URL that uses the https scheme and
|
|
2820
|
+
* has no fragment component. It also SHOULD NOT
|
|
2821
|
+
* include a query component, but it may if
|
|
2822
|
+
* necessary.
|
|
2823
|
+
*
|
|
2824
|
+
* This SHOULD match the aud field of your JWT.
|
|
2825
|
+
*/
|
|
2826
|
+
resource: string;
|
|
2827
|
+
/**
|
|
2828
|
+
* Each server should pertain to one issuer.
|
|
2829
|
+
*
|
|
2830
|
+
* MCP requires at least one server.
|
|
2831
|
+
*
|
|
2832
|
+
* @default [`${baseUrl}/.well-known/oauth-authorization-server`]
|
|
2833
|
+
*/
|
|
2834
|
+
authorization_servers?: string[];
|
|
2835
|
+
jwks_uri?: string;
|
|
2836
|
+
scopes_supported?: string[];
|
|
2837
|
+
bearer_methods_supported?: BearerMethodsSupported[];
|
|
2838
|
+
resource_signing_alg_values_supported?: JWSAlgorithms[];
|
|
2839
|
+
resource_name?: string;
|
|
2840
|
+
resource_documentation?: string;
|
|
2841
|
+
resource_policy_uri?: string;
|
|
2842
|
+
resource_tos_uri?: string;
|
|
2843
|
+
tls_client_certificate_bound_access_tokens?: boolean;
|
|
2844
|
+
authorization_details_types_supported?: string;
|
|
2845
|
+
dpop_signing_alg_values_supported?: JWSAlgorithms[];
|
|
2846
|
+
dpop_bound_access_tokens_required?: boolean;
|
|
2847
|
+
}
|
|
2848
|
+
//#endregion
|
|
2849
|
+
export { OAuthProviderExtension as A, StoreTokenType as B, OAuthConsent as C, OAuthOpaqueAccessToken as D, OAuthMetadataExtensionInput as E, OAuthTokenResponse as F, VerificationValue as H, OAuthUserInfoExtensionInput as I, Prompt as L, OAuthResource as M, OAuthResourceInput as N, OAuthOptions as O, OAuthTokenIssueParams as P, SchemaClient as R, OAuthClientResource as S, OAuthExtensionGrantHandlerInput as T, ClientRegistrationRequest as U, StoredAuthorizationQuery as V, ResourceUriSchema as W, OAuthClaimExtensionInput as _, GrantType as a, OAuthClientAuthenticationResult as b, ResourceServerMetadata as c, ActiveAccessTokenPayload as d, AuthorizePrompt as f, OAuthAuthorizationQuery as g, OAuthAuthenticatedClient as h, Confirmation as i, OAuthRefreshToken as j, OAuthProviderApi as k, TokenEndpointAuthMethod as l, InitialAccessTokenAuthorization as m, AuthServerMetadata as n, OAuthClient as o, ClientDiscovery as p, BearerMethodsSupported as r, OIDCMetadata as s, AuthMethod as t, TokenType as u, OAuthClientAuthenticationInput as v, OAuthExtensionGrantHandler as w, OAuthClientAuthenticationStrategy as x, OAuthClientAuthenticationRequest as y, Scope as z };
|