@better-auth/oauth-provider 1.6.11 → 1.6.12

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.
@@ -1,9 +1,16 @@
1
- import { s as ResourceServerMetadata } from "./oauth-BqWgUea8.mjs";
1
+ import { s as ResourceServerMetadata } from "./oauth-D74mBkw6.mjs";
2
2
  import { JWTPayload, JWTVerifyOptions } from "jose";
3
- import { Auth } from "better-auth/types";
3
+ import { BetterAuthOptions } from "better-auth/types";
4
4
 
5
5
  //#region src/client-resource.d.ts
6
- declare const oauthProviderResourceClient: <T extends Auth | undefined>(auth?: T) => {
6
+ type ResourceClientAuth = {
7
+ options: {
8
+ baseURL?: BetterAuthOptions["baseURL"];
9
+ basePath?: BetterAuthOptions["basePath"];
10
+ };
11
+ $context: Promise<unknown>;
12
+ };
13
+ declare const oauthProviderResourceClient: <T extends ResourceClientAuth | undefined = undefined>(auth?: T) => {
7
14
  id: "oauth-provider-resource-client";
8
15
  version: string;
9
16
  getActions(): {
@@ -43,7 +50,7 @@ interface VerifyAccessTokenRemote {
43
50
  */
44
51
  force?: boolean;
45
52
  }
46
- type VerifyAccessTokenOutput<T> = T extends Auth ? (token: string | undefined, opts?: VerifyAccessTokenAuthOpts) => Promise<JWTPayload> : (token: string | undefined, opts: VerifyAccessTokenNoAuthOpts) => Promise<JWTPayload>;
53
+ type VerifyAccessTokenOutput<T> = T extends undefined ? (token: string | undefined, opts: VerifyAccessTokenNoAuthOpts) => Promise<JWTPayload> : (token: string | undefined, opts?: VerifyAccessTokenAuthOpts) => Promise<JWTPayload>;
47
54
  type VerifyAccessTokenAuthOpts = {
48
55
  verifyOptions?: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience">>;
49
56
  scopes?: string[];
@@ -64,12 +71,12 @@ type VerifyAccessTokenNoAuthOpts = {
64
71
  remoteVerify: VerifyAccessTokenRemote; /** Maps non-url (ie urn, client) resources to resource_metadata */
65
72
  resourceMetadataMappings?: Record<string, string>;
66
73
  };
67
- type ProtectedResourceMetadataOutput<T> = T extends Auth ? (overrides?: Partial<ResourceServerMetadata>, opts?: {
74
+ type ProtectedResourceMetadataOutput<T> = T extends undefined ? (overrides: ResourceServerMetadata, opts?: {
68
75
  silenceWarnings?: {
69
76
  oidcScopes?: boolean;
70
77
  };
71
78
  externalScopes?: string[];
72
- }) => Promise<ResourceServerMetadata> : (overrides: ResourceServerMetadata, opts?: {
79
+ }) => Promise<ResourceServerMetadata> : (overrides?: Partial<ResourceServerMetadata>, opts?: {
73
80
  silenceWarnings?: {
74
81
  oidcScopes?: boolean;
75
82
  };
@@ -1,5 +1,5 @@
1
- import { S as handleMcpErrors, a as getOAuthProviderPlugin, i as getJwtPlugin } from "./utils-LAthGy-x.mjs";
2
- import { t as PACKAGE_VERSION } from "./version-CRjaDWWg.mjs";
1
+ import { S as handleMcpErrors, a as getOAuthProviderPlugin, i as getJwtPlugin } from "./utils-DoYEeMrg.mjs";
2
+ import { t as PACKAGE_VERSION } from "./version-DZ0lABPc.mjs";
3
3
  import { verifyAccessToken } from "better-auth/oauth2";
4
4
  import { APIError } from "better-call";
5
5
  import { logger } from "@better-auth/core/env";
package/dist/client.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { n as oauthProvider } from "./oauth-C4GaGx2I.mjs";
1
+ import { n as oauthProvider } from "./oauth-CUqnBdrR.mjs";
2
2
  import * as _better_fetch_fetch0 from "@better-fetch/fetch";
3
3
 
4
4
  //#region src/client.d.ts
package/dist/client.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { t as PACKAGE_VERSION } from "./version-CRjaDWWg.mjs";
1
+ import { t as PACKAGE_VERSION } from "./version-DZ0lABPc.mjs";
2
2
  import { safeJSONParse } from "@better-auth/core/utils/json";
3
3
  //#region src/client.ts
4
4
  function parseSignedQuery(search) {
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { _ as Scope, a as OAuthClient, b as Awaitable, c as TokenEndpointAuthMethod, d as OAuthConsent, f as OAuthOpaqueAccessToken, g as SchemaClient, h as Prompt, i as GrantType, l as AuthorizePrompt, m as OAuthRefreshToken, n as AuthServerMetadata, o as OIDCMetadata, p as OAuthOptions, r as BearerMethodsSupported, s as ResourceServerMetadata, t as AuthMethod, u as OAuthAuthorizationQuery, v as StoreTokenType, y as VerificationValue } from "./oauth-BqWgUea8.mjs";
2
- import { n as oauthProvider, t as getOAuthProviderState } from "./oauth-C4GaGx2I.mjs";
1
+ import { _ as Scope, a as OAuthClient, b as Awaitable, c as TokenEndpointAuthMethod, d as OAuthConsent, f as OAuthOpaqueAccessToken, g as SchemaClient, h as Prompt, i as GrantType, l as AuthorizePrompt, m as OAuthRefreshToken, n as AuthServerMetadata, o as OIDCMetadata, p as OAuthOptions, r as BearerMethodsSupported, s as ResourceServerMetadata, t as AuthMethod, u as OAuthAuthorizationQuery, v as StoreTokenType, y as VerificationValue } from "./oauth-D74mBkw6.mjs";
2
+ import { n as oauthProvider, t as getOAuthProviderState } from "./oauth-CUqnBdrR.mjs";
3
3
  import { verifyAccessToken } from "better-auth/oauth2";
4
4
  import { JWSAlgorithms, JwtOptions } from "better-auth/plugins";
5
5
  import { JWTPayload } from "jose";
@@ -21,6 +21,7 @@ verifyOptions: Parameters<typeof verifyAccessToken>[1], handler: (req: Request,
21
21
  //#region src/metadata.d.ts
22
22
  declare function authServerMetadata(ctx: GenericEndpointContext, opts?: JwtOptions, overrides?: {
23
23
  scopes_supported?: AuthServerMetadata["scopes_supported"];
24
+ dynamic_client_registration_supported?: boolean;
24
25
  public_client_supported?: boolean;
25
26
  grant_types_supported?: GrantType[];
26
27
  jwt_disabled?: boolean;
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { C as mcpHandler, _ as signedQueryIssuedAtParam, b as validateClientCredentials, c as isPKCERequired, d as parsePrompt, f as postLoginClearedParam, g as searchParamsToQuery, h as resolveSubjectIdentifier, i as getJwtPlugin, l as normalizeTimestampValue, m as resolveSessionAuthTime, n as decryptStoredClientSecret, o as getSignedQueryIssuedAt, p as removePromptFromQuery, r as getClient, s as getStoredToken, t as basicToClientCredentials, u as parseClientMetadata, v as storeClientSecret, x as verifyOAuthQueryParams, y as storeToken } from "./utils-LAthGy-x.mjs";
2
- import { t as PACKAGE_VERSION } from "./version-CRjaDWWg.mjs";
1
+ import { C as mcpHandler, _ as signedQueryIssuedAtParam, b as validateClientCredentials, c as isPKCERequired, d as parsePrompt, f as postLoginClearedParam, g as searchParamsToQuery, h as resolveSubjectIdentifier, i as getJwtPlugin, l as normalizeTimestampValue, m as resolveSessionAuthTime, n as decryptStoredClientSecret, o as getSignedQueryIssuedAt, p as removePromptFromQuery, r as getClient, s as getStoredToken, t as basicToClientCredentials, u as parseClientMetadata, v as storeClientSecret, x as verifyOAuthQueryParams, y as storeToken } from "./utils-DoYEeMrg.mjs";
2
+ import { t as PACKAGE_VERSION } from "./version-DZ0lABPc.mjs";
3
3
  import { APIError, createAuthEndpoint, createAuthMiddleware, getOAuthState, getSessionFromCtx, sessionMiddleware } from "better-auth/api";
4
4
  import { generateCodeChallenge, getJwks, verifyJwsAccessToken } from "better-auth/oauth2";
5
5
  import { APIError as APIError$1 } from "better-call";
@@ -605,11 +605,7 @@ async function createUserTokens(ctx, opts, params) {
605
605
  async function checkVerificationValue(ctx, opts, code, client_id, redirect_uri) {
606
606
  const verification = await ctx.context.internalAdapter.consumeVerificationValue(await storeToken(opts.storeTokens, code, "authorization_code"));
607
607
  if (!verification) throw new APIError("UNAUTHORIZED", {
608
- error_description: "Invalid code",
609
- error: "invalid_grant"
610
- });
611
- if (!verification.expiresAt || verification.expiresAt < /* @__PURE__ */ new Date()) throw new APIError("UNAUTHORIZED", {
612
- error_description: "code expired",
608
+ error_description: "invalid code",
613
609
  error: "invalid_grant"
614
610
  });
615
611
  let rawValue;
@@ -2228,12 +2224,12 @@ async function updateConsentEndpoint(ctx, opts) {
2228
2224
  error_description: "no consent",
2229
2225
  error: "not_found"
2230
2226
  });
2227
+ if (consent.userId !== session.user.id) throw new APIError("UNAUTHORIZED");
2231
2228
  const client = await getClient(ctx, opts, consent.clientId);
2232
- if (!consent) throw new APIError("NOT_FOUND", {
2233
- error_description: "no consent",
2229
+ if (!client) throw new APIError("NOT_FOUND", {
2230
+ error_description: "client not found",
2234
2231
  error: "not_found"
2235
2232
  });
2236
- if (consent.userId !== session.user.id) throw new APIError("UNAUTHORIZED");
2237
2233
  const allowedScopes = client?.scopes ?? opts.scopes ?? [];
2238
2234
  const updates = ctx.body.update;
2239
2235
  const scopes = updates.scopes;
@@ -2831,6 +2827,47 @@ const oauthProvider = (options) => {
2831
2827
  if (opts.grantTypes && opts.grantTypes.includes("refresh_token") && !opts.grantTypes.includes("authorization_code")) throw new BetterAuthError("refresh_token grant requires authorization_code grant");
2832
2828
  if (opts.disableJwtPlugin && (opts.storeClientSecret === "hashed" || typeof opts.storeClientSecret === "object" && "hash" in opts.storeClientSecret)) throw new BetterAuthError("unable to store hashed secrets because id tokens will be signed with secret");
2833
2829
  if (!opts.disableJwtPlugin && (opts.storeClientSecret === "encrypted" || typeof opts.storeClientSecret === "object" && ("encrypt" in opts.storeClientSecret || "decrypt" in opts.storeClientSecret))) throw new BetterAuthError("encryption method not recommended, please use 'hashed' or the 'hash' function");
2830
+ const handleIssuerMetadataRequest = async (request, ctx) => {
2831
+ const requestPathname = new URL(request.url).pathname;
2832
+ const requestPath = ctx.options.advanced?.skipTrailingSlashes ? requestPathname.replace(/\/+$/, "") || "/" : requestPathname;
2833
+ const issuer = opts.disableJwtPlugin ? ctx.baseURL : getJwtPlugin(ctx)?.options?.jwt?.issuer ?? ctx.baseURL;
2834
+ let issuerPath = "/";
2835
+ try {
2836
+ issuerPath = new URL(issuer).pathname.replace(/\/$/, "") || "";
2837
+ } catch {
2838
+ issuerPath = new URL(ctx.baseURL).pathname.replace(/\/$/, "") || "";
2839
+ }
2840
+ const endpointCtx = { context: ctx };
2841
+ const authServerMetadataPaths = new Set([`/.well-known/oauth-authorization-server${issuerPath}`, `${issuerPath}/.well-known/oauth-authorization-server`]);
2842
+ const openIdConfigPath = `${issuerPath}/.well-known/openid-configuration`;
2843
+ const isAuthServerMetadataRequest = authServerMetadataPaths.has(requestPath);
2844
+ const isOpenIdConfigRequest = opts.scopes?.includes("openid") && requestPath === openIdConfigPath;
2845
+ const createMetadataResponse = (metadata) => {
2846
+ const response = metadataResponse(metadata);
2847
+ if (request.method === "HEAD") return new Response(null, {
2848
+ status: response.status,
2849
+ headers: response.headers
2850
+ });
2851
+ return response;
2852
+ };
2853
+ if (isAuthServerMetadataRequest || isOpenIdConfigRequest) {
2854
+ if (request.method !== "GET" && request.method !== "HEAD") return { response: new Response(null, {
2855
+ status: 405,
2856
+ headers: { Allow: "GET, HEAD" }
2857
+ }) };
2858
+ }
2859
+ if (isAuthServerMetadataRequest) {
2860
+ if (opts.scopes?.includes("openid")) return { response: createMetadataResponse(oidcServerMetadata(endpointCtx, opts)) };
2861
+ return { response: createMetadataResponse(authServerMetadata(endpointCtx, opts.disableJwtPlugin ? void 0 : getJwtPlugin(ctx)?.options, {
2862
+ scopes_supported: opts.advertisedMetadata?.scopes_supported ?? opts.scopes,
2863
+ dynamic_client_registration_supported: opts.allowDynamicClientRegistration,
2864
+ public_client_supported: opts.allowUnauthenticatedClientRegistration,
2865
+ grant_types_supported: opts.grantTypes,
2866
+ jwt_disabled: opts.disableJwtPlugin
2867
+ })) };
2868
+ }
2869
+ if (isOpenIdConfigRequest) return { response: createMetadataResponse(oidcServerMetadata(endpointCtx, opts)) };
2870
+ };
2834
2871
  return {
2835
2872
  id: "oauth-provider",
2836
2873
  version: PACKAGE_VERSION,
@@ -2852,6 +2889,7 @@ const oauthProvider = (options) => {
2852
2889
  if (!opts.silenceWarnings?.openidConfig && ctx.options.basePath !== issuerPath && opts.scopes?.includes("openid")) logger.warn(`Please ensure '${issuerPath}${issuerPath.endsWith("/") ? "" : "/"}.well-known/openid-configuration' exists. Upon completion, clear with silenceWarnings.openidConfig.`);
2853
2890
  }
2854
2891
  },
2892
+ onRequest: handleIssuerMetadataRequest,
2855
2893
  hooks: {
2856
2894
  before: [{
2857
2895
  matcher(ctx) {
@@ -2908,6 +2946,7 @@ const oauthProvider = (options) => {
2908
2946
  if (opts.scopes && opts.scopes.includes("openid")) return oidcServerMetadata(ctx, opts);
2909
2947
  else return authServerMetadata(ctx, opts.disableJwtPlugin ? void 0 : getJwtPlugin(ctx.context)?.options, {
2910
2948
  scopes_supported: opts.advertisedMetadata?.scopes_supported ?? opts.scopes,
2949
+ dynamic_client_registration_supported: opts.allowDynamicClientRegistration,
2911
2950
  public_client_supported: opts.allowUnauthenticatedClientRegistration,
2912
2951
  grant_types_supported: opts.grantTypes,
2913
2952
  jwt_disabled: opts.disableJwtPlugin
@@ -4030,7 +4069,7 @@ function authServerMetadata(ctx, opts, overrides) {
4030
4069
  authorization_endpoint: `${baseURL}/oauth2/authorize`,
4031
4070
  token_endpoint: `${baseURL}/oauth2/token`,
4032
4071
  jwks_uri: overrides?.jwt_disabled ? void 0 : opts?.jwks?.remoteUrl ?? `${baseURL}${opts?.jwks?.jwksPath ?? "/jwks"}`,
4033
- registration_endpoint: `${baseURL}/oauth2/register`,
4072
+ registration_endpoint: overrides?.dynamic_client_registration_supported ? `${baseURL}/oauth2/register` : void 0,
4034
4073
  introspection_endpoint: `${baseURL}/oauth2/introspect`,
4035
4074
  revocation_endpoint: `${baseURL}/oauth2/revoke`,
4036
4075
  response_types_supported: overrides?.grant_types_supported && !overrides.grant_types_supported.includes("authorization_code") ? [] : ["code"],
@@ -4057,6 +4096,7 @@ function oidcServerMetadata(ctx, opts) {
4057
4096
  return {
4058
4097
  ...authServerMetadata(ctx, jwtPluginOptions, {
4059
4098
  scopes_supported: opts.advertisedMetadata?.scopes_supported ?? opts.scopes,
4099
+ dynamic_client_registration_supported: opts.allowDynamicClientRegistration,
4060
4100
  public_client_supported: opts.allowUnauthenticatedClientRegistration,
4061
4101
  grant_types_supported: opts.grantTypes,
4062
4102
  jwt_disabled: opts.disableJwtPlugin
@@ -1,4 +1,4 @@
1
- import { _ as Scope, a as OAuthClient, d as OAuthConsent, n as AuthServerMetadata, o as OIDCMetadata, p as OAuthOptions } from "./oauth-BqWgUea8.mjs";
1
+ import { _ as Scope, a as OAuthClient, d as OAuthConsent, n as AuthServerMetadata, o as OIDCMetadata, p as OAuthOptions } from "./oauth-D74mBkw6.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";
@@ -30,6 +30,11 @@ declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
30
30
  version: string;
31
31
  options: NoInfer<O>;
32
32
  init: (ctx: better_auth0.AuthContext) => void;
33
+ onRequest: (request: Request, ctx: better_auth0.AuthContext) => Promise<{
34
+ response: Response;
35
+ } | {
36
+ request: Request;
37
+ } | void>;
33
38
  hooks: {
34
39
  before: {
35
40
  matcher(ctx: better_auth0.HookEndpointContext): any;
@@ -1380,9 +1380,11 @@ interface AuthServerMetadata {
1380
1380
  /**
1381
1381
  * The URL of the dynamic client registration endpoint.
1382
1382
  *
1383
+ * This field is only present when `allowDynamicClientRegistration` is enabled.
1384
+ *
1383
1385
  * @default `/oauth2/register`
1384
1386
  */
1385
- registration_endpoint: string;
1387
+ registration_endpoint?: string;
1386
1388
  /**
1387
1389
  * Supported scopes.
1388
1390
  */
@@ -254,11 +254,13 @@ function basicToClientCredentials(authorization) {
254
254
  if (authorization.startsWith("Basic ")) {
255
255
  const encoded = authorization.replace("Basic ", "");
256
256
  const decoded = new TextDecoder().decode(base64.decode(encoded));
257
- if (!decoded.includes(":")) throw new APIError$1("BAD_REQUEST", {
257
+ const separatorIndex = decoded.indexOf(":");
258
+ if (separatorIndex === -1) throw new APIError$1("BAD_REQUEST", {
258
259
  error_description: "invalid authorization header format",
259
260
  error: "invalid_client"
260
261
  });
261
- const [id, secret] = decoded.split(":", 2);
262
+ const id = decoded.slice(0, separatorIndex);
263
+ const secret = decoded.slice(separatorIndex + 1);
262
264
  if (!id || !secret) throw new APIError$1("BAD_REQUEST", {
263
265
  error_description: "invalid authorization header format",
264
266
  error: "invalid_client"
@@ -1,5 +1,5 @@
1
1
  //#endregion
2
2
  //#region src/version.ts
3
- const PACKAGE_VERSION = "1.6.11";
3
+ const PACKAGE_VERSION = "1.6.12";
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.6.11",
3
+ "version": "1.6.12",
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.6.11",
68
- "better-auth": "1.6.11"
67
+ "@better-auth/core": "1.6.12",
68
+ "better-auth": "1.6.12"
69
69
  },
70
70
  "peerDependencies": {
71
- "@better-auth/utils": "0.4.0",
71
+ "@better-auth/utils": "0.4.1",
72
72
  "@better-fetch/fetch": "1.1.21",
73
73
  "better-call": "1.3.5",
74
- "@better-auth/core": "^1.6.11",
75
- "better-auth": "^1.6.11"
74
+ "@better-auth/core": "^1.6.12",
75
+ "better-auth": "^1.6.12"
76
76
  },
77
77
  "scripts": {
78
78
  "build": "tsdown",