@better-auth/oauth-provider 1.7.6 → 1.7.8

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.
@@ -1091,6 +1091,58 @@ interface OAuthOptions<Scopes extends readonly Scope[] = InternallySupportedScop
1091
1091
  * ```
1092
1092
  */
1093
1093
  scopes?: Scopes;
1094
+ /**
1095
+ * Validates an OAuth authorization request's redirect URI. Without this
1096
+ * option, the URI must match one registered for the client, except that
1097
+ * a registered native HTTP loopback URI may use a different port.
1098
+ *
1099
+ * The callback runs for every client and also controls whether early
1100
+ * authorization errors may be sent to the requested URI. Returning `true`
1101
+ * accepts the URI even when `defaultResult` is `false`; returning `false`
1102
+ * or throwing rejects it. Client registration is unchanged.
1103
+ *
1104
+ * The preview example assumes only trusted clients can register its
1105
+ * production callback URI.
1106
+ *
1107
+ * @example
1108
+ * ```ts
1109
+ * oauthProvider({
1110
+ * validateRedirectUri: (uri, registeredUris, defaultResult) => {
1111
+ * if (defaultResult) return true;
1112
+ * if (!registeredUris.includes("https://app.example.com/api/auth/callback")) {
1113
+ * return false;
1114
+ * }
1115
+ * if (uri.includes("#")) return false;
1116
+ * try {
1117
+ * const url = new URL(uri);
1118
+ * return (
1119
+ * url.protocol === "https:" &&
1120
+ * url.username === "" &&
1121
+ * url.password === "" &&
1122
+ * url.hostname.endsWith(".preview.example.com") &&
1123
+ * url.port === "" &&
1124
+ * url.pathname === "/api/auth/callback" &&
1125
+ * url.search === ""
1126
+ * );
1127
+ * } catch {
1128
+ * return false;
1129
+ * }
1130
+ * },
1131
+ * })
1132
+ * ```
1133
+ *
1134
+ * Custom acceptance relaxes the exact matching required by RFC 9700 §2.1.
1135
+ * Accept only callback hosts you control. For pairwise subject identifiers,
1136
+ * custom-validated URIs use the sector of the client's first registered URI.
1137
+ *
1138
+ * @see https://www.better-auth.com/docs/plugins/oauth-provider#custom-redirect-uri-validation
1139
+ *
1140
+ * @param redirectUri - The redirect_uri from the authorization request
1141
+ * @param registeredUris - Registered redirect URIs for the client
1142
+ * @param defaultResult - Result of built-in redirect URI matching
1143
+ * @returns `true` to accept the URI, or `false` to reject it
1144
+ */
1145
+ validateRedirectUri?: (redirectUri: string, registeredUris: readonly string[], defaultResult: boolean) => Awaitable<boolean>;
1094
1146
  /**
1095
1147
  * Protected resources the AS issues access tokens for. Promotes the
1096
1148
  * resource model into a first-class persisted entity with per-resource
@@ -1377,6 +1429,27 @@ interface OAuthOptions<Scopes extends readonly Scope[] = InternallySupportedScop
1377
1429
  * @default true
1378
1430
  */
1379
1431
  clientRegistrationRequirePKCE?: boolean;
1432
+ /**
1433
+ * Default `application_type` for dynamic client registrations that omit the
1434
+ * field.
1435
+ *
1436
+ * - `"web"`: the OIDC Registration §2 default. Omitted `application_type` is
1437
+ * treated as `web`, so custom-scheme redirect URIs are rejected.
1438
+ * - `"native"`: omitted `application_type` is treated as `native`.
1439
+ * - `"infer"`: omitted `application_type` is treated as `native` when any
1440
+ * `redirect_uris` entry uses a non-http(s) scheme; otherwise `web`. Every
1441
+ * redirect URI is then validated against the native rules. Lets native MCP
1442
+ * clients that omit `application_type` (for example Cursor, which also
1443
+ * registers https and loopback callbacks) register without loosening
1444
+ * web-client redirect policy.
1445
+ *
1446
+ * An `application_type` the client actually sends is never overridden.
1447
+ * Applies only to dynamic client registration; managed clients and Client ID
1448
+ * Metadata Documents are unaffected.
1449
+ *
1450
+ * @default "web"
1451
+ */
1452
+ clientRegistrationDefaultApplicationType?: "web" | "native" | "infer";
1380
1453
  /**
1381
1454
  * How long a dynamically created confidential client
1382
1455
  * should last for.
@@ -1428,6 +1501,16 @@ interface OAuthOptions<Scopes extends readonly Scope[] = InternallySupportedScop
1428
1501
  action: "create" | "read" | "update" | "delete" | "list" | "rotate" | "configure-client-credentials-scopes";
1429
1502
  user?: User & Record<string, unknown>;
1430
1503
  session?: Session & Record<string, unknown>;
1504
+ /**
1505
+ * The `client_id` from the request, for actions on an existing client.
1506
+ * Absent for `create`, `list`, and scope configuration during creation.
1507
+ * The client may not exist, and this value does not establish ownership.
1508
+ * Client CRUD enforces ownership except when `adminUpdateOAuthClient`
1509
+ * changes only `client_credentials_scopes`: the `update` and
1510
+ * `configure-client-credentials-scopes` decisions can authorize access
1511
+ * to another owner's client.
1512
+ */
1513
+ clientId?: string;
1431
1514
  }) => Awaitable<boolean | undefined>;
1432
1515
  /**
1433
1516
  * Grant types supported by the token endpoint
@@ -1732,7 +1815,7 @@ interface OAuthOptions<Scopes extends readonly Scope[] = InternallySupportedScop
1732
1815
  }) => Awaitable<Record<string, unknown>>;
1733
1816
  /**
1734
1817
  * Overwrite specific /.well-known/openid-configuration
1735
- * values so they are not available publically.
1818
+ * values so they are not available publicly.
1736
1819
  * This may be important if not all clients need specific scopes.
1737
1820
  */
1738
1821
  advertisedMetadata?: {
@@ -1,4 +1,4 @@
1
- import { B as Prompt, E as OAuthConsent, F as OAuthResource, H as Scope, O as OAuthExtensionGrantHandlerInput, R as OAuthTokenResponse, a as GrantType, j as OAuthOptions, k as OAuthMetadataExtensionInput, l as TokenEndpointAuthMethod, n as AuthServerMetadata, o as OAuthClient, u as TokenType, w as OAuthClientRegistrationResponse, y as OAuthClientAdministrativeResponse } from "./oauth-1Ud-hvZY.mjs";
1
+ import { B as Prompt, E as OAuthConsent, F as OAuthResource, H as Scope, O as OAuthExtensionGrantHandlerInput, R as OAuthTokenResponse, a as GrantType, j as OAuthOptions, k as OAuthMetadataExtensionInput, l as TokenEndpointAuthMethod, n as AuthServerMetadata, o as OAuthClient, u as TokenType, w as OAuthClientRegistrationResponse, y as OAuthClientAdministrativeResponse } from "./oauth-C_RnL2nt.mjs";
2
2
  import * as _$better_call0 from "better-call";
3
3
  import * as z from "zod";
4
4
  import * as _$jose from "jose";
@@ -1785,6 +1785,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
1785
1785
  jwks_uri: z.ZodOptional<z.ZodString>;
1786
1786
  grant_types: z.ZodOptional<z.ZodArray<z.ZodString>>;
1787
1787
  client_credentials_scopes: z.ZodOptional<z.ZodArray<z.ZodString>>;
1788
+ resources: z.ZodOptional<z.ZodArray<z.ZodString>>;
1788
1789
  response_types: z.ZodOptional<z.ZodArray<z.ZodEnum<{
1789
1790
  code: "code";
1790
1791
  }>>>;
@@ -2280,6 +2281,7 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
2280
2281
  client_secret_expires_at: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
2281
2282
  skip_consent: z.ZodOptional<z.ZodBoolean>;
2282
2283
  enable_end_session: z.ZodOptional<z.ZodBoolean>;
2284
+ disabled: z.ZodOptional<z.ZodBoolean>;
2283
2285
  dpop_bound_access_tokens: z.ZodOptional<z.ZodBoolean>;
2284
2286
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
2285
2287
  }, z.core.$strip>;
@@ -356,6 +356,11 @@ function getTrustedClientCache(options) {
356
356
  trustedClientCaches.set(options, cache);
357
357
  return cache;
358
358
  }
359
+ /**
360
+ * Verify the signature and expiration of an OAuth query issued by this provider.
361
+ * Use the provider's current auth secret on the server before displaying a
362
+ * consent page. A valid signature does not replace client or session checks.
363
+ */
359
364
  async function verifyOAuthQueryParams(oauth_query, secret) {
360
365
  const queryParams = new URLSearchParams(oauth_query);
361
366
  const sig = queryParams.get("sig");
@@ -707,7 +712,7 @@ async function extractClientCredentials(ctx, opts, expectedAudience) {
707
712
  confirmation: result.confirmation
708
713
  };
709
714
  }
710
- const { verifyClientAssertion: verify } = await import("./authorize-CLuqtSXQ.mjs").then((n) => n.o);
715
+ const { verifyClientAssertion: verify } = await import("./authorize-C95F-9E1.mjs").then((n) => n.o);
711
716
  return {
712
717
  kind: "pre_verified",
713
718
  method: "private_key_jwt",
@@ -1,5 +1,5 @@
1
1
  //#endregion
2
2
  //#region src/version.ts
3
- const PACKAGE_VERSION = "1.7.6";
3
+ const PACKAGE_VERSION = "1.7.8";
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.6",
3
+ "version": "1.7.8",
4
4
  "description": "An oauth provider plugin for Better Auth",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -71,16 +71,16 @@
71
71
  "devDependencies": {
72
72
  "listhen": "^1.9.0",
73
73
  "tsdown": "0.21.10",
74
- "@better-auth/core": "1.7.6",
75
- "@better-auth/memory-adapter": "1.7.6",
76
- "better-auth": "1.7.6"
74
+ "@better-auth/core": "1.7.8",
75
+ "@better-auth/memory-adapter": "1.7.8",
76
+ "better-auth": "1.7.8"
77
77
  },
78
78
  "peerDependencies": {
79
- "@better-auth/utils": "0.4.2",
79
+ "@better-auth/utils": "^0.4.2 || ^0.5.0",
80
80
  "@better-fetch/fetch": "1.3.2",
81
- "better-call": "1.4.0",
82
- "@better-auth/core": "^1.7.6",
83
- "better-auth": "^1.7.6"
81
+ "better-call": "1.4.2",
82
+ "@better-auth/core": "^1.7.8",
83
+ "better-auth": "^1.7.8"
84
84
  },
85
85
  "scripts": {
86
86
  "build": "tsdown",