@better-auth/oauth-provider 1.7.0-beta.4 → 1.7.0-beta.5

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.
@@ -100,6 +100,14 @@ declare const schema: {
100
100
  type: "string[]";
101
101
  required: false;
102
102
  };
103
+ backchannelLogoutUri: {
104
+ type: "string";
105
+ required: false;
106
+ };
107
+ backchannelLogoutSessionRequired: {
108
+ type: "boolean";
109
+ required: false;
110
+ };
103
111
  tokenEndpointAuthMethod: {
104
112
  type: "string";
105
113
  required: false;
@@ -280,6 +288,10 @@ declare const schema: {
280
288
  createdAt: {
281
289
  type: "date";
282
290
  };
291
+ revoked: {
292
+ type: "date";
293
+ required: false;
294
+ };
283
295
  scopes: {
284
296
  type: "string[]";
285
297
  required: true;
@@ -327,6 +339,27 @@ declare const schema: {
327
339
  };
328
340
  };
329
341
  };
342
+ /**
343
+ * Single-use record for `private_key_jwt` client assertion `jti` values. The
344
+ * row id is a digest of the per-client assertion identifier, so a replayed or
345
+ * concurrent assertion collides on the primary key and the insert fails
346
+ * atomically on every adapter (SQL primary key, MongoDB `_id`), including
347
+ * across multiple server processes.
348
+ *
349
+ * A row keeps blocking its id until deleted; `expiresAt` marks when removal
350
+ * is safe, since the assertion it guards has expired and is rejected earlier.
351
+ * TODO: no scheduled job prunes expired rows yet; like the verification
352
+ * table, they accumulate until a deployment-level sweep removes them.
353
+ */
354
+ oauthClientAssertion: {
355
+ modelName: string;
356
+ fields: {
357
+ expiresAt: {
358
+ type: "date";
359
+ required: true;
360
+ };
361
+ };
362
+ };
330
363
  };
331
364
  //#endregion
332
365
  //#region src/types/helpers.d.ts
@@ -1290,6 +1323,22 @@ interface SchemaClient<Scopes extends readonly Scope[] = InternallySupportedScop
1290
1323
  * For example, `https://example.com/logout/callback`
1291
1324
  */
1292
1325
  postLogoutRedirectUris?: string[];
1326
+ /**
1327
+ * RP URL that will receive a signed Logout Token when the end-user's OP
1328
+ * session ends. Registering it is the per-client opt-in for back-channel
1329
+ * logout. Must be absolute, without a fragment, and HTTPS for confidential
1330
+ * clients.
1331
+ *
1332
+ * @see https://openid.net/specs/openid-connect-backchannel-1_0.html#RPMetadata
1333
+ */
1334
+ backchannelLogoutUri?: string;
1335
+ /**
1336
+ * When true, the RP requires the `sid` claim in every Logout Token.
1337
+ * User-scoped (sid-less) logouts are not dispatched to such a client.
1338
+ *
1339
+ * @default false
1340
+ */
1341
+ backchannelLogoutSessionRequired?: boolean;
1293
1342
  tokenEndpointAuthMethod?: "none" | "client_secret_basic" | "client_secret_post" | "private_key_jwt";
1294
1343
  grantTypes?: GrantType[];
1295
1344
  responseTypes?: "code"[];
@@ -1381,6 +1430,12 @@ interface OAuthOpaqueAccessToken<Scopes extends readonly Scope[] = InternallySup
1381
1430
  expiresAt: Date;
1382
1431
  /** The creation date of the access token. */
1383
1432
  createdAt: Date;
1433
+ /**
1434
+ * When the access token was revoked. Set by session-end dispatch, the
1435
+ * revoke endpoint, and back-channel logout. Introspection and protected
1436
+ * endpoints MUST treat a revoked token as inactive.
1437
+ */
1438
+ revoked?: Date | null;
1384
1439
  /**
1385
1440
  * Scope granted for the access token.
1386
1441
  *
@@ -1614,6 +1669,28 @@ interface AuthServerMetadata {
1614
1669
  * it on its own.
1615
1670
  */
1616
1671
  client_id_metadata_document_supported?: boolean;
1672
+ /**
1673
+ * Boolean value specifying whether the OP supports back-channel logout,
1674
+ * with true indicating support.
1675
+ *
1676
+ * Registered in the "OAuth Authorization Server Metadata" IANA registry
1677
+ * under OpenID Connect Back-Channel Logout 1.0, so this may appear at both
1678
+ * `.well-known/oauth-authorization-server` and `.well-known/openid-configuration`.
1679
+ *
1680
+ * @default false
1681
+ * @see https://openid.net/specs/openid-connect-backchannel-1_0.html#OPMetadata
1682
+ */
1683
+ backchannel_logout_supported?: boolean;
1684
+ /**
1685
+ * Boolean value specifying whether the OP can pass a `sid` (session ID)
1686
+ * Claim in the Logout Token to identify the RP session with the OP.
1687
+ *
1688
+ * When true, the OP also includes `sid` in ID Tokens it issues.
1689
+ *
1690
+ * @default false
1691
+ * @see https://openid.net/specs/openid-connect-backchannel-1_0.html#OPMetadata
1692
+ */
1693
+ backchannel_logout_session_supported?: boolean;
1617
1694
  }
1618
1695
  /**
1619
1696
  * Metadata returned by the openid-configuration endpoint:
@@ -1716,6 +1793,22 @@ interface OAuthClient {
1716
1793
  software_statement?: string;
1717
1794
  redirect_uris: string[];
1718
1795
  post_logout_redirect_uris?: string[];
1796
+ /**
1797
+ * RP URL that the OP POSTs a signed Logout Token to when a session at the OP
1798
+ * ends. The RP uses the token to terminate its own session state for that
1799
+ * user (including any access tokens it has bound to the session).
1800
+ *
1801
+ * @see https://openid.net/specs/openid-connect-backchannel-1_0.html#RPMetadata
1802
+ */
1803
+ backchannel_logout_uri?: string;
1804
+ /**
1805
+ * When true, the RP requires the `sid` Claim in every Logout Token it
1806
+ * receives; the OP will not dispatch user-scoped (sid-less) logouts to it.
1807
+ *
1808
+ * @default false
1809
+ * @see https://openid.net/specs/openid-connect-backchannel-1_0.html#RPMetadata
1810
+ */
1811
+ backchannel_logout_session_required?: boolean;
1719
1812
  token_endpoint_auth_method?: "none" | "client_secret_basic" | "client_secret_post" | "private_key_jwt";
1720
1813
  grant_types?: GrantType[];
1721
1814
  response_types?: "code"[];
@@ -1,4 +1,4 @@
1
- import { a as OAuthClient, c as TokenEndpointAuthMethod, f as OAuthConsent, g as Prompt, i as GrantType, m as OAuthOptions, t as AuthMethod, v as Scope } from "./oauth-q7dn10NU.mjs";
1
+ import { a as OAuthClient, c as TokenEndpointAuthMethod, f as OAuthConsent, g as Prompt, i as GrantType, m as OAuthOptions, t as AuthMethod, v as Scope } from "./oauth-BXrYl5x6.mjs";
2
2
  import * as better_call0 from "better-call";
3
3
  import * as z from "zod";
4
4
  import * as better_auth_plugins0 from "better-auth/plugins";
@@ -34,7 +34,13 @@ interface OAuthEndpointRedirectContext<Ctx = unknown> {
34
34
  error_description: string;
35
35
  ctx: Ctx;
36
36
  }
37
- type OAuthRedirectOnError<Ctx = any> = (result: OAuthEndpointRedirectContext<Ctx>) => unknown;
37
+ type OAuthRedirectOnError<Ctx = unknown, Result = unknown> = (result: OAuthEndpointRedirectContext<Ctx>) => Result | Promise<Result>;
38
+ //#endregion
39
+ //#region src/authorize.d.ts
40
+ type OAuthRedirectResult = {
41
+ redirect: true;
42
+ url: string;
43
+ };
38
44
  //#endregion
39
45
  //#region src/oauth.d.ts
40
46
  declare module "@better-auth/core" {
@@ -65,7 +71,26 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
65
71
  } | {
66
72
  request: Request;
67
73
  } | void>;
68
- init: (ctx: better_auth0.AuthContext) => void;
74
+ init: (ctx: better_auth0.AuthContext) => {
75
+ options: {
76
+ databaseHooks: {
77
+ session: {
78
+ delete: {
79
+ before(session: {
80
+ id: string;
81
+ createdAt: Date;
82
+ updatedAt: Date;
83
+ userId: string;
84
+ expiresAt: Date;
85
+ token: string;
86
+ ipAddress?: string | null | undefined;
87
+ userAgent?: string | null | undefined;
88
+ } & Record<string, unknown>, hookCtx: GenericEndpointContext | null): Promise<void>;
89
+ };
90
+ };
91
+ };
92
+ };
93
+ };
69
94
  hooks: {
70
95
  before: {
71
96
  matcher(ctx: better_auth0.HookEndpointContext): any;
@@ -73,10 +98,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
73
98
  }[];
74
99
  after: {
75
100
  matcher(ctx: better_auth0.HookEndpointContext): boolean;
76
- handler: (inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<{
77
- redirect: boolean;
78
- url: string;
79
- } | undefined>;
101
+ handler: (inputContext: better_call0.MiddlewareInputContext<better_call0.MiddlewareOptions>) => Promise<OAuthRedirectResult | undefined>;
80
102
  }[];
81
103
  };
82
104
  endpoints: {
@@ -123,6 +145,8 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
123
145
  code_challenge_methods_supported: "S256"[];
124
146
  authorization_response_iss_parameter_supported?: boolean | undefined;
125
147
  client_id_metadata_document_supported?: boolean | undefined;
148
+ backchannel_logout_supported?: boolean | undefined;
149
+ backchannel_logout_session_supported?: boolean | undefined;
126
150
  id_token_signing_alg_values_supported: better_auth_plugins0.JWSAlgorithms[] | ["HS256"];
127
151
  } | {
128
152
  issuer: string;
@@ -149,6 +173,8 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
149
173
  code_challenge_methods_supported: "S256"[];
150
174
  authorization_response_iss_parameter_supported?: boolean;
151
175
  client_id_metadata_document_supported?: boolean;
176
+ backchannel_logout_supported?: boolean;
177
+ backchannel_logout_session_supported?: boolean;
152
178
  }>;
153
179
  /**
154
180
  * A server-only endpoint that helps provide the
@@ -193,6 +219,8 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
193
219
  code_challenge_methods_supported: "S256"[];
194
220
  authorization_response_iss_parameter_supported?: boolean | undefined;
195
221
  client_id_metadata_document_supported?: boolean | undefined;
222
+ backchannel_logout_supported?: boolean | undefined;
223
+ backchannel_logout_session_supported?: boolean | undefined;
196
224
  id_token_signing_alg_values_supported: better_auth_plugins0.JWSAlgorithms[] | ["HS256"];
197
225
  }>;
198
226
  oauth2Authorize: better_call0.StrictEndpoint<"/oauth2/authorize", {
@@ -201,28 +229,26 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
201
229
  response_type: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodEnum<{
202
230
  code: "code";
203
231
  }>>>;
204
- client_id: z.ZodString;
232
+ request_uri: z.ZodOptional<z.ZodString>;
205
233
  redirect_uri: z.ZodOptional<z.ZodURL>;
206
234
  scope: z.ZodOptional<z.ZodString>;
207
235
  state: z.ZodOptional<z.ZodString>;
208
- request_uri: z.ZodOptional<z.ZodString>;
236
+ client_id: z.ZodString;
237
+ prompt: z.ZodOptional<z.ZodString>;
238
+ display: z.ZodOptional<z.ZodString>;
239
+ ui_locales: z.ZodOptional<z.ZodString>;
240
+ max_age: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
241
+ acr_values: z.ZodOptional<z.ZodString>;
242
+ login_hint: z.ZodOptional<z.ZodString>;
243
+ id_token_hint: z.ZodOptional<z.ZodString>;
209
244
  code_challenge: z.ZodOptional<z.ZodString>;
210
245
  code_challenge_method: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodEnum<{
211
246
  S256: "S256";
212
247
  }>>>;
213
248
  nonce: z.ZodOptional<z.ZodString>;
214
249
  resource: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
215
- prompt: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodEnum<{
216
- none: "none";
217
- consent: "consent";
218
- login: "login";
219
- create: "create";
220
- select_account: "select_account";
221
- "login consent": "login consent";
222
- "select_account consent": "select_account consent";
223
- }>>>;
224
- }, z.core.$strip>;
225
- redirectOnError: OAuthRedirectOnError<GenericEndpointContext>;
250
+ }, z.core.$loose>;
251
+ redirectOnError: OAuthRedirectOnError<GenericEndpointContext, OAuthRedirectResult>;
226
252
  errorCodesByField: {
227
253
  response_type: {
228
254
  invalid: "unsupported_response_type";
@@ -241,6 +267,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
241
267
  schema: {
242
268
  type: "string";
243
269
  format?: undefined;
270
+ minimum?: undefined;
244
271
  items?: undefined;
245
272
  };
246
273
  description: string;
@@ -251,6 +278,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
251
278
  schema: {
252
279
  type: "string";
253
280
  format?: undefined;
281
+ minimum?: undefined;
254
282
  items?: undefined;
255
283
  };
256
284
  description: string;
@@ -261,6 +289,18 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
261
289
  schema: {
262
290
  type: "string";
263
291
  format: string;
292
+ minimum?: undefined;
293
+ items?: undefined;
294
+ };
295
+ description: string;
296
+ } | {
297
+ name: string;
298
+ in: "query";
299
+ required: false;
300
+ schema: {
301
+ type: "integer";
302
+ minimum: number;
303
+ format?: undefined;
264
304
  items?: undefined;
265
305
  };
266
306
  description: string;
@@ -274,6 +314,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
274
314
  type: "string";
275
315
  };
276
316
  format?: undefined;
317
+ minimum?: undefined;
277
318
  };
278
319
  description: string;
279
320
  })[];
@@ -315,10 +356,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
315
356
  };
316
357
  };
317
358
  };
318
- }, {
319
- redirect: boolean;
320
- url: string;
321
- }>;
359
+ }, OAuthRedirectResult>;
322
360
  oauth2Consent: better_call0.StrictEndpoint<"/oauth2/consent", {
323
361
  method: "POST";
324
362
  body: z.ZodObject<{
@@ -374,7 +412,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
374
412
  };
375
413
  };
376
414
  };
377
- }, {
415
+ }, OAuthRedirectResult | {
378
416
  redirect: boolean;
379
417
  url: string;
380
418
  }>;
@@ -434,10 +472,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
434
472
  };
435
473
  };
436
474
  };
437
- }, {
438
- redirect: boolean;
439
- url: string;
440
- }>;
475
+ }, OAuthRedirectResult>;
441
476
  oauth2Token: better_call0.StrictEndpoint<"/oauth2/token", {
442
477
  method: "POST";
443
478
  body: z.ZodObject<{
@@ -817,7 +852,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
817
852
  };
818
853
  }, null | undefined>;
819
854
  oauth2UserInfo: better_call0.StrictEndpoint<"/oauth2/userinfo", {
820
- method: "GET";
855
+ method: ("GET" | "POST")[];
821
856
  metadata: {
822
857
  openapi: {
823
858
  description: string;
@@ -973,10 +1008,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
973
1008
  };
974
1009
  };
975
1010
  };
976
- }, {
977
- redirect: boolean;
978
- url: string;
979
- } | undefined>;
1011
+ }, OAuthRedirectResult | undefined>;
980
1012
  registerOAuthClient: better_call0.StrictEndpoint<"/oauth2/register", {
981
1013
  method: "POST";
982
1014
  body: z.ZodObject<{
@@ -992,6 +1024,8 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
992
1024
  software_version: z.ZodOptional<z.ZodString>;
993
1025
  software_statement: z.ZodOptional<z.ZodString>;
994
1026
  post_logout_redirect_uris: z.ZodOptional<z.ZodArray<z.ZodURL>>;
1027
+ backchannel_logout_uri: z.ZodOptional<z.ZodURL>;
1028
+ backchannel_logout_session_required: z.ZodOptional<z.ZodBoolean>;
995
1029
  token_endpoint_auth_method: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
996
1030
  none: "none";
997
1031
  client_secret_basic: "client_secret_basic";
@@ -1117,6 +1151,15 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
1117
1151
  };
1118
1152
  description: string;
1119
1153
  };
1154
+ backchannel_logout_uri: {
1155
+ type: string;
1156
+ format: string;
1157
+ description: string;
1158
+ };
1159
+ backchannel_logout_session_required: {
1160
+ type: string;
1161
+ description: string;
1162
+ };
1120
1163
  token_endpoint_auth_method: {
1121
1164
  type: string;
1122
1165
  description: string;
@@ -1176,6 +1219,8 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
1176
1219
  software_version: z.ZodOptional<z.ZodString>;
1177
1220
  software_statement: z.ZodOptional<z.ZodString>;
1178
1221
  post_logout_redirect_uris: z.ZodOptional<z.ZodArray<z.ZodURL>>;
1222
+ backchannel_logout_uri: z.ZodOptional<z.ZodURL>;
1223
+ backchannel_logout_session_required: z.ZodOptional<z.ZodBoolean>;
1179
1224
  token_endpoint_auth_method: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
1180
1225
  none: "none";
1181
1226
  client_secret_basic: "client_secret_basic";
@@ -1385,6 +1430,8 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
1385
1430
  software_version: z.ZodOptional<z.ZodString>;
1386
1431
  software_statement: z.ZodOptional<z.ZodString>;
1387
1432
  post_logout_redirect_uris: z.ZodOptional<z.ZodArray<z.ZodURL>>;
1433
+ backchannel_logout_uri: z.ZodOptional<z.ZodURL>;
1434
+ backchannel_logout_session_required: z.ZodOptional<z.ZodBoolean>;
1388
1435
  token_endpoint_auth_method: z.ZodOptional<z.ZodDefault<z.ZodEnum<{
1389
1436
  none: "none";
1390
1437
  client_secret_basic: "client_secret_basic";
@@ -1670,6 +1717,8 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
1670
1717
  software_version: z.ZodOptional<z.ZodString>;
1671
1718
  software_statement: z.ZodOptional<z.ZodString>;
1672
1719
  post_logout_redirect_uris: z.ZodOptional<z.ZodArray<z.ZodURL>>;
1720
+ backchannel_logout_uri: z.ZodOptional<z.ZodURL>;
1721
+ backchannel_logout_session_required: z.ZodOptional<z.ZodBoolean>;
1673
1722
  grant_types: z.ZodOptional<z.ZodArray<z.ZodEnum<{
1674
1723
  authorization_code: "authorization_code";
1675
1724
  client_credentials: "client_credentials";
@@ -1736,6 +1785,8 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
1736
1785
  software_version: z.ZodOptional<z.ZodString>;
1737
1786
  software_statement: z.ZodOptional<z.ZodString>;
1738
1787
  post_logout_redirect_uris: z.ZodOptional<z.ZodArray<z.ZodURL>>;
1788
+ backchannel_logout_uri: z.ZodOptional<z.ZodURL>;
1789
+ backchannel_logout_session_required: z.ZodOptional<z.ZodBoolean>;
1739
1790
  grant_types: z.ZodOptional<z.ZodArray<z.ZodEnum<{
1740
1791
  authorization_code: "authorization_code";
1741
1792
  client_credentials: "client_credentials";
@@ -2057,6 +2108,14 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
2057
2108
  type: "string[]";
2058
2109
  required: false;
2059
2110
  };
2111
+ backchannelLogoutUri: {
2112
+ type: "string";
2113
+ required: false;
2114
+ };
2115
+ backchannelLogoutSessionRequired: {
2116
+ type: "boolean";
2117
+ required: false;
2118
+ };
2060
2119
  tokenEndpointAuthMethod: {
2061
2120
  type: "string";
2062
2121
  required: false;
@@ -2220,6 +2279,10 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
2220
2279
  createdAt: {
2221
2280
  type: "date";
2222
2281
  };
2282
+ revoked: {
2283
+ type: "date";
2284
+ required: false;
2285
+ };
2223
2286
  scopes: {
2224
2287
  type: "string[]";
2225
2288
  required: true;
@@ -2267,6 +2330,15 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
2267
2330
  };
2268
2331
  };
2269
2332
  };
2333
+ oauthClientAssertion: {
2334
+ modelName: string;
2335
+ fields: {
2336
+ expiresAt: {
2337
+ type: "date";
2338
+ required: true;
2339
+ };
2340
+ };
2341
+ };
2270
2342
  };
2271
2343
  rateLimit: ({
2272
2344
  pathMatcher: (path: string) => path is "/oauth2/token";
@@ -287,12 +287,27 @@ function basicToClientCredentials(authorization) {
287
287
  }
288
288
  }
289
289
  /**
290
+ * Whether a client is allowed to use a given grant type.
291
+ *
292
+ * A client's registered `grantTypes` defaults to the documented default
293
+ * `["authorization_code"]` when unset (see client registration). Refresh tokens
294
+ * are only ever issued through the authorization_code flow, so a client allowed
295
+ * to use `authorization_code` is implicitly allowed to use `refresh_token`.
296
+ *
297
+ * @internal
298
+ */
299
+ function clientAllowsGrant(client, grantType) {
300
+ const allowedGrants = client.grantTypes && client.grantTypes.length > 0 ? client.grantTypes : ["authorization_code"];
301
+ if (grantType === "refresh_token" && allowedGrants.includes("authorization_code")) return true;
302
+ return allowedGrants.includes(grantType);
303
+ }
304
+ /**
290
305
  * Validates client credentials failing on mismatches
291
306
  * and incorrectly provided information
292
307
  *
293
308
  * @internal
294
309
  */
295
- async function validateClientCredentials(ctx, options, clientId, clientSecret, scopes, preVerifiedClient) {
310
+ async function validateClientCredentials(ctx, options, clientId, clientSecret, scopes, preVerifiedClient, grantType) {
296
311
  const client = preVerifiedClient ?? await getClient(ctx, options, clientId);
297
312
  if (!client) throw new APIError("BAD_REQUEST", {
298
313
  error_description: "missing client",
@@ -327,6 +342,10 @@ async function validateClientCredentials(ctx, options, clientId, clientSecret, s
327
342
  error: "invalid_scope"
328
343
  });
329
344
  }
345
+ if (grantType && !clientAllowsGrant(client, grantType)) throw new APIError("BAD_REQUEST", {
346
+ error_description: `client is not authorized to use grant type ${grantType}`,
347
+ error: "unauthorized_client"
348
+ });
330
349
  return client;
331
350
  }
332
351
  /**
@@ -363,7 +382,7 @@ async function extractClientCredentials(ctx, opts, expectedAudience) {
363
382
  error_description: "client_assertion cannot be combined with client_secret or Basic auth",
364
383
  error: "invalid_client"
365
384
  });
366
- const { verifyClientAssertion: verify } = await import("./client-assertion-DLMKVgoj.mjs").then((n) => n.t);
385
+ const { verifyClientAssertion: verify } = await import("./client-assertion-DmT1B6_6.mjs").then((n) => n.t);
367
386
  const result = await verify(ctx, opts, body.client_assertion, body.client_assertion_type, body.client_id, expectedAudience);
368
387
  return {
369
388
  method: "private_key_jwt",
@@ -452,6 +471,12 @@ function getSignedQueryIssuedAt(oauthQuery) {
452
471
  if (!Number.isFinite(issuedAt) || issuedAt <= 0) return null;
453
472
  return new Date(issuedAt);
454
473
  }
474
+ function isSessionFreshForSignedQuery(sessionCreatedAt, signedQueryIssuedAt) {
475
+ if (!signedQueryIssuedAt) return false;
476
+ const normalized = normalizeTimestampValue(sessionCreatedAt);
477
+ if (!normalized) return false;
478
+ return normalized.getTime() >= signedQueryIssuedAt.getTime();
479
+ }
455
480
  function removePromptFromQuery(query, prompt) {
456
481
  const nextQuery = new URLSearchParams(query);
457
482
  const prompts = nextQuery.get("prompt")?.split(" ");
@@ -462,6 +487,11 @@ function removePromptFromQuery(query, prompt) {
462
487
  }
463
488
  return nextQuery;
464
489
  }
490
+ function removeMaxAgeFromQuery(query) {
491
+ const nextQuery = new URLSearchParams(query);
492
+ nextQuery.delete("max_age");
493
+ return nextQuery;
494
+ }
465
495
  var PKCERequirementErrors = /* @__PURE__ */ function(PKCERequirementErrors) {
466
496
  PKCERequirementErrors["PUBLIC_CLIENT"] = "pkce is required for public clients";
467
497
  PKCERequirementErrors["OFFLINE_ACCESS_SCOPE"] = "pkce is required when requesting offline_access scope";
@@ -489,4 +519,4 @@ function isPKCERequired(client, requestedScopes) {
489
519
  return false;
490
520
  }
491
521
  //#endregion
492
- export { toAudienceClaim as C, verifyOAuthQueryParams as D, validateClientCredentials as E, storeToken as S, toResourceList as T, resolveSessionAuthTime as _, getClient as a, signedQueryIssuedAtParam as b, getSignedQueryIssuedAt as c, mergeDiscoveryMetadata as d, normalizeTimestampValue as f, removePromptFromQuery as g, postLoginClearedParam as h, extractClientCredentials as i, getStoredToken as l, parsePrompt as m, decryptStoredClientSecret as n, getJwtPlugin as o, parseClientMetadata as p, destructureCredentials as r, getOAuthProviderPlugin as s, checkResource as t, isPKCERequired as u, resolveSubjectIdentifier as v, toClientDiscoveryArray as w, storeClientSecret as x, searchParamsToQuery as y };
522
+ export { verifyOAuthQueryParams as A, signedQueryIssuedAtParam as C, toClientDiscoveryArray as D, toAudienceClaim as E, toResourceList as O, searchParamsToQuery as S, storeToken as T, postLoginClearedParam as _, extractClientCredentials as a, resolveSessionAuthTime as b, getOAuthProviderPlugin as c, isPKCERequired as d, isSessionFreshForSignedQuery as f, parsePrompt as g, parseClientMetadata as h, destructureCredentials as i, validateClientCredentials as k, getSignedQueryIssuedAt as l, normalizeTimestampValue as m, clientAllowsGrant as n, getClient as o, mergeDiscoveryMetadata as p, decryptStoredClientSecret as r, getJwtPlugin as s, checkResource as t, getStoredToken as u, removeMaxAgeFromQuery as v, storeClientSecret as w, resolveSubjectIdentifier as x, removePromptFromQuery as y };
@@ -1,5 +1,5 @@
1
1
  //#endregion
2
2
  //#region src/version.ts
3
- const PACKAGE_VERSION = "1.7.0-beta.4";
3
+ const PACKAGE_VERSION = "1.7.0-beta.5";
4
4
  //#endregion
5
5
  export { PACKAGE_VERSION as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/oauth-provider",
3
- "version": "1.7.0-beta.4",
3
+ "version": "1.7.0-beta.5",
4
4
  "description": "An oauth provider plugin for Better Auth",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -64,15 +64,15 @@
64
64
  "@modelcontextprotocol/sdk": "^1.27.1",
65
65
  "listhen": "^1.9.0",
66
66
  "tsdown": "0.21.1",
67
- "@better-auth/core": "1.7.0-beta.4",
68
- "better-auth": "1.7.0-beta.4"
67
+ "@better-auth/core": "1.7.0-beta.5",
68
+ "better-auth": "1.7.0-beta.5"
69
69
  },
70
70
  "peerDependencies": {
71
71
  "@better-auth/utils": "0.4.1",
72
- "@better-fetch/fetch": "1.1.21",
73
- "better-call": "1.3.5",
74
- "@better-auth/core": "^1.7.0-beta.4",
75
- "better-auth": "^1.7.0-beta.4"
72
+ "@better-fetch/fetch": "1.2.2",
73
+ "better-call": "1.3.6",
74
+ "@better-auth/core": "^1.7.0-beta.5",
75
+ "better-auth": "^1.7.0-beta.5"
76
76
  },
77
77
  "scripts": {
78
78
  "build": "tsdown",