@better-auth/oauth-provider 1.5.5 → 1.5.7-beta.1

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,4 +1,4 @@
1
- import { a as ResourceServerMetadata } from "./oauth-Chk8ejPr.mjs";
1
+ import { a as ResourceServerMetadata } from "./oauth-DrFFxaBJ.mjs";
2
2
  import { JWTPayload, JWTVerifyOptions } from "jose";
3
3
  import { Auth } from "better-auth/types";
4
4
 
@@ -1,9 +1,8 @@
1
- import { a as getJwtPlugin, h as handleMcpErrors, o as getOAuthProviderPlugin } from "./utils-DgozotLg.mjs";
1
+ import { a as getJwtPlugin, g as handleMcpErrors, o as getOAuthProviderPlugin } from "./utils-BpUSdl43.mjs";
2
2
  import { verifyAccessToken } from "better-auth/oauth2";
3
3
  import { APIError } from "better-call";
4
4
  import { logger } from "@better-auth/core/env";
5
5
  import { BetterAuthError } from "@better-auth/core/error";
6
-
7
6
  //#region src/client-resource.ts
8
7
  const oauthProviderResourceClient = (auth) => {
9
8
  let oauthProviderPlugin;
@@ -16,10 +15,10 @@ const oauthProviderResourceClient = (auth) => {
16
15
  if (!jwtPlugin) jwtPlugin = auth && !(await getOauthProviderPlugin())?.options?.disableJwtPlugin ? getJwtPlugin(await auth.$context) : void 0;
17
16
  return jwtPlugin?.options;
18
17
  };
18
+ const authServerBaseUrl = typeof auth?.options.baseURL === "string" ? auth.options.baseURL : void 0;
19
19
  const getAuthorizationServer = async () => {
20
20
  return (await getJwtPluginOptions())?.jwt?.issuer ?? authServerBaseUrl;
21
21
  };
22
- const authServerBaseUrl = auth?.options.baseURL;
23
22
  const authServerBasePath = auth?.options.basePath;
24
23
  return {
25
24
  id: "oauth-provider-resource-client",
@@ -83,7 +82,7 @@ const oauthProviderResourceClient = (auth) => {
83
82
  }
84
83
  };
85
84
  };
86
-
87
85
  //#endregion
88
86
  export { oauthProviderResourceClient };
87
+
89
88
  //# sourceMappingURL=client-resource.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"client-resource.mjs","names":[],"sources":["../src/client-resource.ts"],"sourcesContent":["import { logger } from \"@better-auth/core/env\";\nimport { BetterAuthError } from \"@better-auth/core/error\";\nimport { verifyAccessToken } from \"better-auth/oauth2\";\nimport type { Auth, BetterAuthClientPlugin } from \"better-auth/types\";\nimport { APIError } from \"better-call\";\nimport type { JWTPayload, JWTVerifyOptions } from \"jose\";\nimport { handleMcpErrors } from \"./mcp\";\nimport type { ResourceServerMetadata } from \"./types/oauth\";\nimport { getJwtPlugin, getOAuthProviderPlugin } from \"./utils\";\n\nexport const oauthProviderResourceClient = <T extends Auth | undefined>(\n\tauth?: T,\n) => {\n\tlet oauthProviderPlugin:\n\t\t| ReturnType<typeof getOAuthProviderPlugin>\n\t\t| undefined;\n\tconst getOauthProviderPlugin = async () => {\n\t\tif (!oauthProviderPlugin) {\n\t\t\toauthProviderPlugin = auth\n\t\t\t\t? getOAuthProviderPlugin(await auth.$context)\n\t\t\t\t: undefined;\n\t\t}\n\t\treturn oauthProviderPlugin;\n\t};\n\tlet jwtPlugin: ReturnType<typeof getJwtPlugin> | undefined;\n\tconst getJwtPluginOptions = async () => {\n\t\tif (!jwtPlugin) {\n\t\t\tjwtPlugin =\n\t\t\t\tauth && !(await getOauthProviderPlugin())?.options?.disableJwtPlugin\n\t\t\t\t\t? getJwtPlugin(await auth.$context)\n\t\t\t\t\t: undefined;\n\t\t}\n\t\treturn jwtPlugin?.options;\n\t};\n\tconst getAuthorizationServer = async () => {\n\t\tconst jwtPluginOptions = await getJwtPluginOptions();\n\t\treturn jwtPluginOptions?.jwt?.issuer ?? authServerBaseUrl;\n\t};\n\tconst authServerBaseUrl = auth?.options.baseURL;\n\tconst authServerBasePath = auth?.options.basePath;\n\n\treturn {\n\t\tid: \"oauth-provider-resource-client\",\n\t\tgetActions() {\n\t\t\treturn {\n\t\t\t\t/**\n\t\t\t\t * Performs verification of an access token for your APIs. Can perform\n\t\t\t\t * local verification using `jwksUrl` by default. Can also be configured\n\t\t\t\t * for remote introspection using `remoteVerify` if a confidential client\n\t\t\t\t * is set up for this API.\n\t\t\t\t *\n\t\t\t\t * The optional auth parameter can fill known values automatically.\n\t\t\t\t */\n\t\t\t\tverifyAccessToken: (async (\n\t\t\t\t\ttoken: string | undefined,\n\t\t\t\t\topts?: {\n\t\t\t\t\t\tverifyOptions?: JWTVerifyOptions &\n\t\t\t\t\t\t\tRequired<Pick<JWTVerifyOptions, \"audience\" | \"issuer\">>;\n\t\t\t\t\t\tscopes?: string[];\n\t\t\t\t\t\tjwksUrl?: string;\n\t\t\t\t\t\tremoteVerify?: VerifyAccessTokenRemote;\n\t\t\t\t\t\t/** Maps non-url (ie urn, client) resources to resource_metadata */\n\t\t\t\t\t\tresourceMetadataMappings?: Record<string, string>;\n\t\t\t\t\t},\n\t\t\t\t): Promise<JWTPayload> => {\n\t\t\t\t\tconst jwtPluginOptions = await getJwtPluginOptions();\n\t\t\t\t\tconst audience = opts?.verifyOptions?.audience ?? authServerBaseUrl;\n\t\t\t\t\tconst issuer =\n\t\t\t\t\t\topts?.verifyOptions?.issuer ??\n\t\t\t\t\t\tjwtPluginOptions?.jwt?.issuer ??\n\t\t\t\t\t\tauthServerBaseUrl;\n\t\t\t\t\tif (!audience) {\n\t\t\t\t\t\tthrow Error(\"please define opts.verifyOptions.audience\");\n\t\t\t\t\t}\n\t\t\t\t\tif (!issuer) {\n\t\t\t\t\t\tthrow Error(\"please define opts.verifyOptions.issuer\");\n\t\t\t\t\t}\n\t\t\t\t\tconst jwksUrl =\n\t\t\t\t\t\topts?.jwksUrl ??\n\t\t\t\t\t\tjwtPluginOptions?.jwks?.remoteUrl ??\n\t\t\t\t\t\t(authServerBaseUrl\n\t\t\t\t\t\t\t? `${authServerBaseUrl + (authServerBasePath ?? \"\")}${jwtPluginOptions?.jwks?.jwksPath ?? \"/jwks\"}`\n\t\t\t\t\t\t\t: undefined);\n\t\t\t\t\tconst introspectUrl =\n\t\t\t\t\t\topts?.remoteVerify?.introspectUrl ??\n\t\t\t\t\t\t(authServerBaseUrl\n\t\t\t\t\t\t\t? `${authServerBaseUrl}${authServerBasePath ?? \"\"}/oauth2/introspect`\n\t\t\t\t\t\t\t: undefined);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (!token?.length) {\n\t\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\t\tmessage: \"missing authorization header\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn await verifyAccessToken(token, {\n\t\t\t\t\t\t\t...opts,\n\t\t\t\t\t\t\tjwksUrl,\n\t\t\t\t\t\t\tverifyOptions: {\n\t\t\t\t\t\t\t\t...opts?.verifyOptions,\n\t\t\t\t\t\t\t\taudience,\n\t\t\t\t\t\t\t\tissuer,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tremoteVerify:\n\t\t\t\t\t\t\t\topts?.remoteVerify && introspectUrl\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t...opts.remoteVerify,\n\t\t\t\t\t\t\t\t\t\t\tintrospectUrl,\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthrow handleMcpErrors(error, audience, {\n\t\t\t\t\t\t\tresourceMetadataMappings: opts?.resourceMetadataMappings,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}) as VerifyAccessTokenOutput<T>,\n\t\t\t\t/**\n\t\t\t\t * An authorization server does not typically publish\n\t\t\t\t * the `/.well-known/oauth-protected-resource` themselves.\n\t\t\t\t * Thus, we provide a client-only endpoint to help set up\n\t\t\t\t * your protected resource metadata.\n\t\t\t\t *\n\t\t\t\t * The optional auth parameter can fill known values automatically.\n\t\t\t\t *\n\t\t\t\t * @see https://datatracker.ietf.org/doc/html/rfc8414#section-2\n\t\t\t\t */\n\t\t\t\tgetProtectedResourceMetadata: (async (\n\t\t\t\t\toverrides: Partial<ResourceServerMetadata> | undefined,\n\t\t\t\t\topts:\n\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\tsilenceWarnings?: {\n\t\t\t\t\t\t\t\t\toidcScopes?: boolean;\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\texternalScopes?: string[];\n\t\t\t\t\t\t }\n\t\t\t\t\t\t| undefined,\n\t\t\t\t): Promise<ResourceServerMetadata> => {\n\t\t\t\t\tconst resource = overrides?.resource ?? authServerBaseUrl;\n\t\t\t\t\tconst oauthProviderOptions = (await getOauthProviderPlugin())\n\t\t\t\t\t\t?.options;\n\t\t\t\t\tif (!resource) {\n\t\t\t\t\t\tthrow Error(\"missing required resource\");\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\toauthProviderOptions?.scopes &&\n\t\t\t\t\t\topts?.externalScopes &&\n\t\t\t\t\t\t(overrides?.authorization_servers?.length ?? 0) <= 1\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new BetterAuthError(\n\t\t\t\t\t\t\t\"external scopes should not be provided with one authorization server\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\t// Resource server should not mention specific scopes\n\t\t\t\t\tif (overrides?.scopes_supported) {\n\t\t\t\t\t\tconst allValidScopes = new Set([\n\t\t\t\t\t\t\t...(oauthProviderOptions?.scopes ?? []),\n\t\t\t\t\t\t\t...(opts?.externalScopes ?? []),\n\t\t\t\t\t\t]);\n\t\t\t\t\t\tfor (const sc of overrides.scopes_supported) {\n\t\t\t\t\t\t\tif (sc === \"openid\") {\n\t\t\t\t\t\t\t\tthrow new BetterAuthError(\n\t\t\t\t\t\t\t\t\t\"Only the Auth Server should utilize the openid scope\",\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif ([\"profile\", \"email\", \"phone\", \"address\"].includes(sc)) {\n\t\t\t\t\t\t\t\tif (!opts?.silenceWarnings?.oidcScopes) {\n\t\t\t\t\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t\t\t\t\t`\"${sc}\" is typically restricted for the authorization server, a resource server typically shouldn't handle this scope`,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!allValidScopes.has(sc)) {\n\t\t\t\t\t\t\t\tthrow new BetterAuthError(\n\t\t\t\t\t\t\t\t\t`Unsupported scope ${sc}. If external, please add to \"externalScopes\"`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst authorizationServer = await getAuthorizationServer();\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tresource,\n\t\t\t\t\t\tauthorization_servers: authorizationServer\n\t\t\t\t\t\t\t? [authorizationServer]\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t...overrides,\n\t\t\t\t\t};\n\t\t\t\t}) as ProtectedResourceMetadataOutput<T>,\n\t\t\t};\n\t\t},\n\t} satisfies BetterAuthClientPlugin;\n};\n\nexport interface VerifyAccessTokenRemote {\n\t/** Full url of the introspect endpoint. Should end with `/oauth2/introspect` */\n\tintrospectUrl: string;\n\t/** Client Secret */\n\tclientId: string;\n\t/** Client Secret */\n\tclientSecret: string;\n\t/**\n\t * Forces remote verification of a token.\n\t * This ensures attached session (if applicable)\n\t * is also still active.\n\t */\n\tforce?: boolean;\n}\n\ntype VerifyAccessTokenOutput<T> = T extends Auth\n\t? (\n\t\t\ttoken: string | undefined,\n\t\t\topts?: VerifyAccessTokenAuthOpts,\n\t\t) => Promise<JWTPayload>\n\t: (\n\t\t\ttoken: string | undefined,\n\t\t\topts: VerifyAccessTokenNoAuthOpts,\n\t\t) => Promise<JWTPayload>;\ntype VerifyAccessTokenAuthOpts = {\n\tverifyOptions?: JWTVerifyOptions &\n\t\tRequired<Pick<JWTVerifyOptions, \"audience\">>;\n\tscopes?: string[];\n\tjwksUrl?: string;\n\tremoteVerify?: VerifyAccessTokenRemote;\n\t/** Maps non-url (ie urn, client) resources to resource_metadata */\n\tresourceMetadataMappings?: Record<string, string>;\n};\ntype VerifyAccessTokenNoAuthOpts =\n\t| {\n\t\t\tverifyOptions: JWTVerifyOptions &\n\t\t\t\tRequired<Pick<JWTVerifyOptions, \"audience\" | \"issuer\">>;\n\t\t\tscopes?: string[];\n\t\t\tjwksUrl: string;\n\t\t\tremoteVerify?: VerifyAccessTokenRemote;\n\t\t\t/** Maps non-url (ie urn, client) resources to resource_metadata */\n\t\t\tresourceMetadataMappings?: Record<string, string>;\n\t }\n\t| {\n\t\t\tverifyOptions: JWTVerifyOptions &\n\t\t\t\tRequired<Pick<JWTVerifyOptions, \"audience\" | \"issuer\">>;\n\t\t\tscopes?: string[];\n\t\t\tjwksUrl?: string;\n\t\t\tremoteVerify: VerifyAccessTokenRemote;\n\t\t\t/** Maps non-url (ie urn, client) resources to resource_metadata */\n\t\t\tresourceMetadataMappings?: Record<string, string>;\n\t };\n\ntype ProtectedResourceMetadataOutput<T> = T extends Auth\n\t? (\n\t\t\toverrides?: Partial<ResourceServerMetadata>,\n\t\t\topts?: {\n\t\t\t\tsilenceWarnings?: {\n\t\t\t\t\toidcScopes?: boolean;\n\t\t\t\t};\n\t\t\t\texternalScopes?: string[];\n\t\t\t},\n\t\t) => Promise<ResourceServerMetadata>\n\t: (\n\t\t\toverrides: ResourceServerMetadata,\n\t\t\topts?: {\n\t\t\t\tsilenceWarnings?: {\n\t\t\t\t\toidcScopes?: boolean;\n\t\t\t\t};\n\t\t\t\texternalScopes?: string[];\n\t\t\t},\n\t\t) => Promise<ResourceServerMetadata>;\n"],"mappings":";;;;;;;AAUA,MAAa,+BACZ,SACI;CACJ,IAAI;CAGJ,MAAM,yBAAyB,YAAY;AAC1C,MAAI,CAAC,oBACJ,uBAAsB,OACnB,uBAAuB,MAAM,KAAK,SAAS,GAC3C;AAEJ,SAAO;;CAER,IAAI;CACJ,MAAM,sBAAsB,YAAY;AACvC,MAAI,CAAC,UACJ,aACC,QAAQ,EAAE,MAAM,wBAAwB,GAAG,SAAS,mBACjD,aAAa,MAAM,KAAK,SAAS,GACjC;AAEL,SAAO,WAAW;;CAEnB,MAAM,yBAAyB,YAAY;AAE1C,UADyB,MAAM,qBAAqB,GAC3B,KAAK,UAAU;;CAEzC,MAAM,oBAAoB,MAAM,QAAQ;CACxC,MAAM,qBAAqB,MAAM,QAAQ;AAEzC,QAAO;EACN,IAAI;EACJ,aAAa;AACZ,UAAO;IASN,oBAAoB,OACnB,OACA,SASyB;KACzB,MAAM,mBAAmB,MAAM,qBAAqB;KACpD,MAAM,WAAW,MAAM,eAAe,YAAY;KAClD,MAAM,SACL,MAAM,eAAe,UACrB,kBAAkB,KAAK,UACvB;AACD,SAAI,CAAC,SACJ,OAAM,MAAM,4CAA4C;AAEzD,SAAI,CAAC,OACJ,OAAM,MAAM,0CAA0C;KAEvD,MAAM,UACL,MAAM,WACN,kBAAkB,MAAM,cACvB,oBACE,GAAG,qBAAqB,sBAAsB,MAAM,kBAAkB,MAAM,YAAY,YACxF;KACJ,MAAM,gBACL,MAAM,cAAc,kBACnB,oBACE,GAAG,oBAAoB,sBAAsB,GAAG,sBAChD;AAEJ,SAAI;AACH,UAAI,CAAC,OAAO,OACX,OAAM,IAAI,SAAS,gBAAgB,EAClC,SAAS,gCACT,CAAC;AAEH,aAAO,MAAM,kBAAkB,OAAO;OACrC,GAAG;OACH;OACA,eAAe;QACd,GAAG,MAAM;QACT;QACA;QACA;OACD,cACC,MAAM,gBAAgB,gBACnB;QACA,GAAG,KAAK;QACR;QACA,GACA;OACJ,CAAC;cACM,OAAO;AACf,YAAM,gBAAgB,OAAO,UAAU,EACtC,0BAA0B,MAAM,0BAChC,CAAC;;;IAaJ,+BAA+B,OAC9B,WACA,SAQqC;KACrC,MAAM,WAAW,WAAW,YAAY;KACxC,MAAM,wBAAwB,MAAM,wBAAwB,GACzD;AACH,SAAI,CAAC,SACJ,OAAM,MAAM,4BAA4B;AAEzC,SACC,sBAAsB,UACtB,MAAM,mBACL,WAAW,uBAAuB,UAAU,MAAM,EAEnD,OAAM,IAAI,gBACT,uEACA;AAGF,SAAI,WAAW,kBAAkB;MAChC,MAAM,iBAAiB,IAAI,IAAI,CAC9B,GAAI,sBAAsB,UAAU,EAAE,EACtC,GAAI,MAAM,kBAAkB,EAAE,CAC9B,CAAC;AACF,WAAK,MAAM,MAAM,UAAU,kBAAkB;AAC5C,WAAI,OAAO,SACV,OAAM,IAAI,gBACT,uDACA;AAEF,WAAI;QAAC;QAAW;QAAS;QAAS;QAAU,CAAC,SAAS,GAAG,EACxD;YAAI,CAAC,MAAM,iBAAiB,WAC3B,QAAO,KACN,IAAI,GAAG,iHACP;;AAGH,WAAI,CAAC,eAAe,IAAI,GAAG,CAC1B,OAAM,IAAI,gBACT,qBAAqB,GAAG,+CACxB;;;KAKJ,MAAM,sBAAsB,MAAM,wBAAwB;AAE1D,YAAO;MACN;MACA,uBAAuB,sBACpB,CAAC,oBAAoB,GACrB;MACH,GAAG;MACH;;IAEF;;EAEF"}
1
+ {"version":3,"file":"client-resource.mjs","names":[],"sources":["../src/client-resource.ts"],"sourcesContent":["import { logger } from \"@better-auth/core/env\";\nimport { BetterAuthError } from \"@better-auth/core/error\";\nimport { verifyAccessToken } from \"better-auth/oauth2\";\nimport type { Auth, BetterAuthClientPlugin } from \"better-auth/types\";\nimport { APIError } from \"better-call\";\nimport type { JWTPayload, JWTVerifyOptions } from \"jose\";\nimport { handleMcpErrors } from \"./mcp\";\nimport type { ResourceServerMetadata } from \"./types/oauth\";\nimport { getJwtPlugin, getOAuthProviderPlugin } from \"./utils\";\n\nexport const oauthProviderResourceClient = <T extends Auth | undefined>(\n\tauth?: T,\n) => {\n\tlet oauthProviderPlugin:\n\t\t| ReturnType<typeof getOAuthProviderPlugin>\n\t\t| undefined;\n\tconst getOauthProviderPlugin = async () => {\n\t\tif (!oauthProviderPlugin) {\n\t\t\toauthProviderPlugin = auth\n\t\t\t\t? getOAuthProviderPlugin(await auth.$context)\n\t\t\t\t: undefined;\n\t\t}\n\t\treturn oauthProviderPlugin;\n\t};\n\tlet jwtPlugin: ReturnType<typeof getJwtPlugin> | undefined;\n\tconst getJwtPluginOptions = async () => {\n\t\tif (!jwtPlugin) {\n\t\t\tjwtPlugin =\n\t\t\t\tauth && !(await getOauthProviderPlugin())?.options?.disableJwtPlugin\n\t\t\t\t\t? getJwtPlugin(await auth.$context)\n\t\t\t\t\t: undefined;\n\t\t}\n\t\treturn jwtPlugin?.options;\n\t};\n\tconst authServerBaseUrl =\n\t\ttypeof auth?.options.baseURL === \"string\"\n\t\t\t? auth.options.baseURL\n\t\t\t: undefined;\n\tconst getAuthorizationServer = async (): Promise<string | undefined> => {\n\t\tconst jwtPluginOptions = await getJwtPluginOptions();\n\t\treturn jwtPluginOptions?.jwt?.issuer ?? authServerBaseUrl;\n\t};\n\tconst authServerBasePath = auth?.options.basePath;\n\n\treturn {\n\t\tid: \"oauth-provider-resource-client\",\n\t\tgetActions() {\n\t\t\treturn {\n\t\t\t\t/**\n\t\t\t\t * Performs verification of an access token for your APIs. Can perform\n\t\t\t\t * local verification using `jwksUrl` by default. Can also be configured\n\t\t\t\t * for remote introspection using `remoteVerify` if a confidential client\n\t\t\t\t * is set up for this API.\n\t\t\t\t *\n\t\t\t\t * The optional auth parameter can fill known values automatically.\n\t\t\t\t */\n\t\t\t\tverifyAccessToken: (async (\n\t\t\t\t\ttoken: string | undefined,\n\t\t\t\t\topts?: {\n\t\t\t\t\t\tverifyOptions?: JWTVerifyOptions &\n\t\t\t\t\t\t\tRequired<Pick<JWTVerifyOptions, \"audience\" | \"issuer\">>;\n\t\t\t\t\t\tscopes?: string[];\n\t\t\t\t\t\tjwksUrl?: string;\n\t\t\t\t\t\tremoteVerify?: VerifyAccessTokenRemote;\n\t\t\t\t\t\t/** Maps non-url (ie urn, client) resources to resource_metadata */\n\t\t\t\t\t\tresourceMetadataMappings?: Record<string, string>;\n\t\t\t\t\t},\n\t\t\t\t): Promise<JWTPayload> => {\n\t\t\t\t\tconst jwtPluginOptions = await getJwtPluginOptions();\n\t\t\t\t\tconst audience = opts?.verifyOptions?.audience ?? authServerBaseUrl;\n\t\t\t\t\tconst issuer =\n\t\t\t\t\t\topts?.verifyOptions?.issuer ??\n\t\t\t\t\t\tjwtPluginOptions?.jwt?.issuer ??\n\t\t\t\t\t\tauthServerBaseUrl;\n\t\t\t\t\tif (!audience) {\n\t\t\t\t\t\tthrow Error(\"please define opts.verifyOptions.audience\");\n\t\t\t\t\t}\n\t\t\t\t\tif (!issuer) {\n\t\t\t\t\t\tthrow Error(\"please define opts.verifyOptions.issuer\");\n\t\t\t\t\t}\n\t\t\t\t\tconst jwksUrl =\n\t\t\t\t\t\topts?.jwksUrl ??\n\t\t\t\t\t\tjwtPluginOptions?.jwks?.remoteUrl ??\n\t\t\t\t\t\t(authServerBaseUrl\n\t\t\t\t\t\t\t? `${authServerBaseUrl + (authServerBasePath ?? \"\")}${jwtPluginOptions?.jwks?.jwksPath ?? \"/jwks\"}`\n\t\t\t\t\t\t\t: undefined);\n\t\t\t\t\tconst introspectUrl =\n\t\t\t\t\t\topts?.remoteVerify?.introspectUrl ??\n\t\t\t\t\t\t(authServerBaseUrl\n\t\t\t\t\t\t\t? `${authServerBaseUrl}${authServerBasePath ?? \"\"}/oauth2/introspect`\n\t\t\t\t\t\t\t: undefined);\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tif (!token?.length) {\n\t\t\t\t\t\t\tthrow new APIError(\"UNAUTHORIZED\", {\n\t\t\t\t\t\t\t\tmessage: \"missing authorization header\",\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn await verifyAccessToken(token, {\n\t\t\t\t\t\t\t...opts,\n\t\t\t\t\t\t\tjwksUrl,\n\t\t\t\t\t\t\tverifyOptions: {\n\t\t\t\t\t\t\t\t...opts?.verifyOptions,\n\t\t\t\t\t\t\t\taudience,\n\t\t\t\t\t\t\t\tissuer,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tremoteVerify:\n\t\t\t\t\t\t\t\topts?.remoteVerify && introspectUrl\n\t\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\t\t...opts.remoteVerify,\n\t\t\t\t\t\t\t\t\t\t\tintrospectUrl,\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t});\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthrow handleMcpErrors(error, audience, {\n\t\t\t\t\t\t\tresourceMetadataMappings: opts?.resourceMetadataMappings,\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}) as VerifyAccessTokenOutput<T>,\n\t\t\t\t/**\n\t\t\t\t * An authorization server does not typically publish\n\t\t\t\t * the `/.well-known/oauth-protected-resource` themselves.\n\t\t\t\t * Thus, we provide a client-only endpoint to help set up\n\t\t\t\t * your protected resource metadata.\n\t\t\t\t *\n\t\t\t\t * The optional auth parameter can fill known values automatically.\n\t\t\t\t *\n\t\t\t\t * @see https://datatracker.ietf.org/doc/html/rfc8414#section-2\n\t\t\t\t */\n\t\t\t\tgetProtectedResourceMetadata: (async (\n\t\t\t\t\toverrides: Partial<ResourceServerMetadata> | undefined,\n\t\t\t\t\topts:\n\t\t\t\t\t\t| {\n\t\t\t\t\t\t\t\tsilenceWarnings?: {\n\t\t\t\t\t\t\t\t\toidcScopes?: boolean;\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\texternalScopes?: string[];\n\t\t\t\t\t\t }\n\t\t\t\t\t\t| undefined,\n\t\t\t\t): Promise<ResourceServerMetadata> => {\n\t\t\t\t\tconst resource = overrides?.resource ?? authServerBaseUrl;\n\t\t\t\t\tconst oauthProviderOptions = (await getOauthProviderPlugin())\n\t\t\t\t\t\t?.options;\n\t\t\t\t\tif (!resource) {\n\t\t\t\t\t\tthrow Error(\"missing required resource\");\n\t\t\t\t\t}\n\t\t\t\t\tif (\n\t\t\t\t\t\toauthProviderOptions?.scopes &&\n\t\t\t\t\t\topts?.externalScopes &&\n\t\t\t\t\t\t(overrides?.authorization_servers?.length ?? 0) <= 1\n\t\t\t\t\t) {\n\t\t\t\t\t\tthrow new BetterAuthError(\n\t\t\t\t\t\t\t\"external scopes should not be provided with one authorization server\",\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\t// Resource server should not mention specific scopes\n\t\t\t\t\tif (overrides?.scopes_supported) {\n\t\t\t\t\t\tconst allValidScopes = new Set([\n\t\t\t\t\t\t\t...(oauthProviderOptions?.scopes ?? []),\n\t\t\t\t\t\t\t...(opts?.externalScopes ?? []),\n\t\t\t\t\t\t]);\n\t\t\t\t\t\tfor (const sc of overrides.scopes_supported) {\n\t\t\t\t\t\t\tif (sc === \"openid\") {\n\t\t\t\t\t\t\t\tthrow new BetterAuthError(\n\t\t\t\t\t\t\t\t\t\"Only the Auth Server should utilize the openid scope\",\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif ([\"profile\", \"email\", \"phone\", \"address\"].includes(sc)) {\n\t\t\t\t\t\t\t\tif (!opts?.silenceWarnings?.oidcScopes) {\n\t\t\t\t\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t\t\t\t\t`\"${sc}\" is typically restricted for the authorization server, a resource server typically shouldn't handle this scope`,\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (!allValidScopes.has(sc)) {\n\t\t\t\t\t\t\t\tthrow new BetterAuthError(\n\t\t\t\t\t\t\t\t\t`Unsupported scope ${sc}. If external, please add to \"externalScopes\"`,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst authorizationServer = await getAuthorizationServer();\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tresource,\n\t\t\t\t\t\tauthorization_servers: authorizationServer\n\t\t\t\t\t\t\t? [authorizationServer]\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t...overrides,\n\t\t\t\t\t};\n\t\t\t\t}) as ProtectedResourceMetadataOutput<T>,\n\t\t\t};\n\t\t},\n\t} satisfies BetterAuthClientPlugin;\n};\n\nexport interface VerifyAccessTokenRemote {\n\t/** Full url of the introspect endpoint. Should end with `/oauth2/introspect` */\n\tintrospectUrl: string;\n\t/** Client Secret */\n\tclientId: string;\n\t/** Client Secret */\n\tclientSecret: string;\n\t/**\n\t * Forces remote verification of a token.\n\t * This ensures attached session (if applicable)\n\t * is also still active.\n\t */\n\tforce?: boolean;\n}\n\ntype VerifyAccessTokenOutput<T> = T extends Auth\n\t? (\n\t\t\ttoken: string | undefined,\n\t\t\topts?: VerifyAccessTokenAuthOpts,\n\t\t) => Promise<JWTPayload>\n\t: (\n\t\t\ttoken: string | undefined,\n\t\t\topts: VerifyAccessTokenNoAuthOpts,\n\t\t) => Promise<JWTPayload>;\ntype VerifyAccessTokenAuthOpts = {\n\tverifyOptions?: JWTVerifyOptions &\n\t\tRequired<Pick<JWTVerifyOptions, \"audience\">>;\n\tscopes?: string[];\n\tjwksUrl?: string;\n\tremoteVerify?: VerifyAccessTokenRemote;\n\t/** Maps non-url (ie urn, client) resources to resource_metadata */\n\tresourceMetadataMappings?: Record<string, string>;\n};\ntype VerifyAccessTokenNoAuthOpts =\n\t| {\n\t\t\tverifyOptions: JWTVerifyOptions &\n\t\t\t\tRequired<Pick<JWTVerifyOptions, \"audience\" | \"issuer\">>;\n\t\t\tscopes?: string[];\n\t\t\tjwksUrl: string;\n\t\t\tremoteVerify?: VerifyAccessTokenRemote;\n\t\t\t/** Maps non-url (ie urn, client) resources to resource_metadata */\n\t\t\tresourceMetadataMappings?: Record<string, string>;\n\t }\n\t| {\n\t\t\tverifyOptions: JWTVerifyOptions &\n\t\t\t\tRequired<Pick<JWTVerifyOptions, \"audience\" | \"issuer\">>;\n\t\t\tscopes?: string[];\n\t\t\tjwksUrl?: string;\n\t\t\tremoteVerify: VerifyAccessTokenRemote;\n\t\t\t/** Maps non-url (ie urn, client) resources to resource_metadata */\n\t\t\tresourceMetadataMappings?: Record<string, string>;\n\t };\n\ntype ProtectedResourceMetadataOutput<T> = T extends Auth\n\t? (\n\t\t\toverrides?: Partial<ResourceServerMetadata>,\n\t\t\topts?: {\n\t\t\t\tsilenceWarnings?: {\n\t\t\t\t\toidcScopes?: boolean;\n\t\t\t\t};\n\t\t\t\texternalScopes?: string[];\n\t\t\t},\n\t\t) => Promise<ResourceServerMetadata>\n\t: (\n\t\t\toverrides: ResourceServerMetadata,\n\t\t\topts?: {\n\t\t\t\tsilenceWarnings?: {\n\t\t\t\t\toidcScopes?: boolean;\n\t\t\t\t};\n\t\t\t\texternalScopes?: string[];\n\t\t\t},\n\t\t) => Promise<ResourceServerMetadata>;\n"],"mappings":";;;;;;AAUA,MAAa,+BACZ,SACI;CACJ,IAAI;CAGJ,MAAM,yBAAyB,YAAY;AAC1C,MAAI,CAAC,oBACJ,uBAAsB,OACnB,uBAAuB,MAAM,KAAK,SAAS,GAC3C,KAAA;AAEJ,SAAO;;CAER,IAAI;CACJ,MAAM,sBAAsB,YAAY;AACvC,MAAI,CAAC,UACJ,aACC,QAAQ,EAAE,MAAM,wBAAwB,GAAG,SAAS,mBACjD,aAAa,MAAM,KAAK,SAAS,GACjC,KAAA;AAEL,SAAO,WAAW;;CAEnB,MAAM,oBACL,OAAO,MAAM,QAAQ,YAAY,WAC9B,KAAK,QAAQ,UACb,KAAA;CACJ,MAAM,yBAAyB,YAAyC;AAEvE,UADyB,MAAM,qBAAqB,GAC3B,KAAK,UAAU;;CAEzC,MAAM,qBAAqB,MAAM,QAAQ;AAEzC,QAAO;EACN,IAAI;EACJ,aAAa;AACZ,UAAO;IASN,oBAAoB,OACnB,OACA,SASyB;KACzB,MAAM,mBAAmB,MAAM,qBAAqB;KACpD,MAAM,WAAW,MAAM,eAAe,YAAY;KAClD,MAAM,SACL,MAAM,eAAe,UACrB,kBAAkB,KAAK,UACvB;AACD,SAAI,CAAC,SACJ,OAAM,MAAM,4CAA4C;AAEzD,SAAI,CAAC,OACJ,OAAM,MAAM,0CAA0C;KAEvD,MAAM,UACL,MAAM,WACN,kBAAkB,MAAM,cACvB,oBACE,GAAG,qBAAqB,sBAAsB,MAAM,kBAAkB,MAAM,YAAY,YACxF,KAAA;KACJ,MAAM,gBACL,MAAM,cAAc,kBACnB,oBACE,GAAG,oBAAoB,sBAAsB,GAAG,sBAChD,KAAA;AAEJ,SAAI;AACH,UAAI,CAAC,OAAO,OACX,OAAM,IAAI,SAAS,gBAAgB,EAClC,SAAS,gCACT,CAAC;AAEH,aAAO,MAAM,kBAAkB,OAAO;OACrC,GAAG;OACH;OACA,eAAe;QACd,GAAG,MAAM;QACT;QACA;QACA;OACD,cACC,MAAM,gBAAgB,gBACnB;QACA,GAAG,KAAK;QACR;QACA,GACA,KAAA;OACJ,CAAC;cACM,OAAO;AACf,YAAM,gBAAgB,OAAO,UAAU,EACtC,0BAA0B,MAAM,0BAChC,CAAC;;;IAaJ,+BAA+B,OAC9B,WACA,SAQqC;KACrC,MAAM,WAAW,WAAW,YAAY;KACxC,MAAM,wBAAwB,MAAM,wBAAwB,GACzD;AACH,SAAI,CAAC,SACJ,OAAM,MAAM,4BAA4B;AAEzC,SACC,sBAAsB,UACtB,MAAM,mBACL,WAAW,uBAAuB,UAAU,MAAM,EAEnD,OAAM,IAAI,gBACT,uEACA;AAGF,SAAI,WAAW,kBAAkB;MAChC,MAAM,iBAAiB,IAAI,IAAI,CAC9B,GAAI,sBAAsB,UAAU,EAAE,EACtC,GAAI,MAAM,kBAAkB,EAAE,CAC9B,CAAC;AACF,WAAK,MAAM,MAAM,UAAU,kBAAkB;AAC5C,WAAI,OAAO,SACV,OAAM,IAAI,gBACT,uDACA;AAEF,WAAI;QAAC;QAAW;QAAS;QAAS;QAAU,CAAC,SAAS,GAAG;YACpD,CAAC,MAAM,iBAAiB,WAC3B,QAAO,KACN,IAAI,GAAG,iHACP;;AAGH,WAAI,CAAC,eAAe,IAAI,GAAG,CAC1B,OAAM,IAAI,gBACT,qBAAqB,GAAG,+CACxB;;;KAKJ,MAAM,sBAAsB,MAAM,wBAAwB;AAE1D,YAAO;MACN;MACA,uBAAuB,sBACpB,CAAC,oBAAoB,GACrB,KAAA;MACH,GAAG;MACH;;IAEF;;EAEF"}
package/dist/client.d.mts CHANGED
@@ -1,5 +1,4 @@
1
- import "./oauth-Chk8ejPr.mjs";
2
- import { n as oauthProvider } from "./oauth-wm0HlZm9.mjs";
1
+ import { n as oauthProvider } from "./oauth-CiaEIjBG.mjs";
3
2
  import * as _better_fetch_fetch0 from "@better-fetch/fetch";
4
3
 
5
4
  //#region src/client.d.ts
package/dist/client.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  import { safeJSONParse } from "@better-auth/core/utils/json";
2
-
3
2
  //#region src/client.ts
4
3
  function parseSignedQuery(search) {
5
4
  const params = new URLSearchParams(search);
@@ -23,17 +22,16 @@ const oauthProviderClient = () => {
23
22
  const headers = ctx.headers;
24
23
  const body = typeof ctx.body === "string" ? headers.get("content-type") === "application/x-www-form-urlencoded" ? Object.fromEntries(new URLSearchParams(ctx.body)) : safeJSONParse(ctx.body ?? "{}") : ctx.body;
25
24
  if (body?.oauth_query) return;
26
- const pathname = typeof ctx.url === "string" ? new URL(ctx.url).pathname : ctx.url.pathname;
27
- if (pathname.endsWith("/sign-in/email") || pathname.endsWith("/sign-in/social") || pathname.endsWith("/sign-in/oauth2") || pathname.endsWith("/oauth2/consent") || pathname.endsWith("/oauth2/continue")) ctx.body = JSON.stringify({
25
+ if (typeof window !== "undefined" && window?.location?.search && !(ctx.method === "GET" || ctx.method === "DELETE")) ctx.body = JSON.stringify({
28
26
  ...body,
29
- oauth_query: typeof window !== "undefined" ? parseSignedQuery(window?.location?.search) : void 0
27
+ oauth_query: parseSignedQuery(window.location.search)
30
28
  });
31
29
  } }
32
30
  }],
33
31
  $InferServerPlugin: {}
34
32
  };
35
33
  };
36
-
37
34
  //#endregion
38
35
  export { oauthProviderClient };
36
+
39
37
  //# sourceMappingURL=client.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import { safeJSONParse } from \"@better-auth/core/utils/json\";\nimport type { BetterAuthClientPlugin } from \"better-auth/types\";\nimport type { oauthProvider } from \"./oauth\";\n\nfunction parseSignedQuery(search: string) {\n\tconst params = new URLSearchParams(search);\n\tif (params.has(\"sig\")) {\n\t\tconst signedParams = new URLSearchParams();\n\t\tfor (const [key, value] of params.entries()) {\n\t\t\tsignedParams.append(key, value);\n\t\t\tif (key === \"sig\") break;\n\t\t}\n\t\treturn signedParams.toString();\n\t}\n}\n\nexport const oauthProviderClient = () => {\n\treturn {\n\t\tid: \"oauth-provider-client\",\n\t\tfetchPlugins: [\n\t\t\t{\n\t\t\t\tid: \"oauth-provider-signin\",\n\t\t\t\tname: \"oauth-provider-signin\",\n\t\t\t\tdescription: \"Adds the current page query to oauth requests\",\n\t\t\t\thooks: {\n\t\t\t\t\tasync onRequest(ctx) {\n\t\t\t\t\t\tconst headers = ctx.headers;\n\t\t\t\t\t\tconst body =\n\t\t\t\t\t\t\ttypeof ctx.body === \"string\"\n\t\t\t\t\t\t\t\t? headers.get(\"content-type\") ===\n\t\t\t\t\t\t\t\t\t\"application/x-www-form-urlencoded\"\n\t\t\t\t\t\t\t\t\t? Object.fromEntries(new URLSearchParams(ctx.body))\n\t\t\t\t\t\t\t\t\t: safeJSONParse<Record<string, unknown>>(ctx.body ?? \"{}\")\n\t\t\t\t\t\t\t\t: ctx.body;\n\t\t\t\t\t\tif (body?.oauth_query) return;\n\t\t\t\t\t\tconst pathname =\n\t\t\t\t\t\t\ttypeof ctx.url === \"string\"\n\t\t\t\t\t\t\t\t? new URL(ctx.url).pathname\n\t\t\t\t\t\t\t\t: ctx.url.pathname;\n\t\t\t\t\t\t// Should only need to run for /sign-in/email, /sign-in/social, /sign-in/oauth2, /oauth2/consent, /oauth2/continue\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tpathname.endsWith(\"/sign-in/email\") ||\n\t\t\t\t\t\t\tpathname.endsWith(\"/sign-in/social\") ||\n\t\t\t\t\t\t\tpathname.endsWith(\"/sign-in/oauth2\") ||\n\t\t\t\t\t\t\tpathname.endsWith(\"/oauth2/consent\") ||\n\t\t\t\t\t\t\tpathname.endsWith(\"/oauth2/continue\")\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tctx.body = JSON.stringify({\n\t\t\t\t\t\t\t\t...body,\n\t\t\t\t\t\t\t\toauth_query:\n\t\t\t\t\t\t\t\t\ttypeof window !== \"undefined\"\n\t\t\t\t\t\t\t\t\t\t? parseSignedQuery(window?.location?.search)\n\t\t\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t$InferServerPlugin: {} as ReturnType<typeof oauthProvider>,\n\t} satisfies BetterAuthClientPlugin;\n};\n"],"mappings":";;;AAIA,SAAS,iBAAiB,QAAgB;CACzC,MAAM,SAAS,IAAI,gBAAgB,OAAO;AAC1C,KAAI,OAAO,IAAI,MAAM,EAAE;EACtB,MAAM,eAAe,IAAI,iBAAiB;AAC1C,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,SAAS,EAAE;AAC5C,gBAAa,OAAO,KAAK,MAAM;AAC/B,OAAI,QAAQ,MAAO;;AAEpB,SAAO,aAAa,UAAU;;;AAIhC,MAAa,4BAA4B;AACxC,QAAO;EACN,IAAI;EACJ,cAAc,CACb;GACC,IAAI;GACJ,MAAM;GACN,aAAa;GACb,OAAO,EACN,MAAM,UAAU,KAAK;IACpB,MAAM,UAAU,IAAI;IACpB,MAAM,OACL,OAAO,IAAI,SAAS,WACjB,QAAQ,IAAI,eAAe,KAC5B,sCACE,OAAO,YAAY,IAAI,gBAAgB,IAAI,KAAK,CAAC,GACjD,cAAuC,IAAI,QAAQ,KAAK,GACzD,IAAI;AACR,QAAI,MAAM,YAAa;IACvB,MAAM,WACL,OAAO,IAAI,QAAQ,WAChB,IAAI,IAAI,IAAI,IAAI,CAAC,WACjB,IAAI,IAAI;AAEZ,QACC,SAAS,SAAS,iBAAiB,IACnC,SAAS,SAAS,kBAAkB,IACpC,SAAS,SAAS,kBAAkB,IACpC,SAAS,SAAS,kBAAkB,IACpC,SAAS,SAAS,mBAAmB,CAErC,KAAI,OAAO,KAAK,UAAU;KACzB,GAAG;KACH,aACC,OAAO,WAAW,cACf,iBAAiB,QAAQ,UAAU,OAAO,GAC1C;KACJ,CAAC;MAGJ;GACD,CACD;EACD,oBAAoB,EAAE;EACtB"}
1
+ {"version":3,"file":"client.mjs","names":[],"sources":["../src/client.ts"],"sourcesContent":["import { safeJSONParse } from \"@better-auth/core/utils/json\";\nimport type { BetterAuthClientPlugin } from \"better-auth/types\";\nimport type { oauthProvider } from \"./oauth\";\n\nfunction parseSignedQuery(search: string) {\n\tconst params = new URLSearchParams(search);\n\tif (params.has(\"sig\")) {\n\t\tconst signedParams = new URLSearchParams();\n\t\tfor (const [key, value] of params.entries()) {\n\t\t\tsignedParams.append(key, value);\n\t\t\tif (key === \"sig\") break;\n\t\t}\n\t\treturn signedParams.toString();\n\t}\n}\n\nexport const oauthProviderClient = () => {\n\treturn {\n\t\tid: \"oauth-provider-client\",\n\t\tfetchPlugins: [\n\t\t\t{\n\t\t\t\tid: \"oauth-provider-signin\",\n\t\t\t\tname: \"oauth-provider-signin\",\n\t\t\t\tdescription: \"Adds the current page query to oauth requests\",\n\t\t\t\thooks: {\n\t\t\t\t\tasync onRequest(ctx) {\n\t\t\t\t\t\tconst headers = ctx.headers;\n\t\t\t\t\t\tconst body =\n\t\t\t\t\t\t\ttypeof ctx.body === \"string\"\n\t\t\t\t\t\t\t\t? headers.get(\"content-type\") ===\n\t\t\t\t\t\t\t\t\t\"application/x-www-form-urlencoded\"\n\t\t\t\t\t\t\t\t\t? Object.fromEntries(new URLSearchParams(ctx.body))\n\t\t\t\t\t\t\t\t\t: safeJSONParse<Record<string, unknown>>(ctx.body ?? \"{}\")\n\t\t\t\t\t\t\t\t: ctx.body;\n\t\t\t\t\t\tif (body?.oauth_query) return;\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\ttypeof window !== \"undefined\" &&\n\t\t\t\t\t\t\twindow?.location?.search &&\n\t\t\t\t\t\t\t!(ctx.method === \"GET\" || ctx.method === \"DELETE\")\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tctx.body = JSON.stringify({\n\t\t\t\t\t\t\t\t...body,\n\t\t\t\t\t\t\t\toauth_query: parseSignedQuery(window.location.search),\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t],\n\t\t$InferServerPlugin: {} as ReturnType<typeof oauthProvider>,\n\t} satisfies BetterAuthClientPlugin;\n};\n"],"mappings":";;AAIA,SAAS,iBAAiB,QAAgB;CACzC,MAAM,SAAS,IAAI,gBAAgB,OAAO;AAC1C,KAAI,OAAO,IAAI,MAAM,EAAE;EACtB,MAAM,eAAe,IAAI,iBAAiB;AAC1C,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,SAAS,EAAE;AAC5C,gBAAa,OAAO,KAAK,MAAM;AAC/B,OAAI,QAAQ,MAAO;;AAEpB,SAAO,aAAa,UAAU;;;AAIhC,MAAa,4BAA4B;AACxC,QAAO;EACN,IAAI;EACJ,cAAc,CACb;GACC,IAAI;GACJ,MAAM;GACN,aAAa;GACb,OAAO,EACN,MAAM,UAAU,KAAK;IACpB,MAAM,UAAU,IAAI;IACpB,MAAM,OACL,OAAO,IAAI,SAAS,WACjB,QAAQ,IAAI,eAAe,KAC5B,sCACE,OAAO,YAAY,IAAI,gBAAgB,IAAI,KAAK,CAAC,GACjD,cAAuC,IAAI,QAAQ,KAAK,GACzD,IAAI;AACR,QAAI,MAAM,YAAa;AACvB,QACC,OAAO,WAAW,eAClB,QAAQ,UAAU,UAClB,EAAE,IAAI,WAAW,SAAS,IAAI,WAAW,UAEzC,KAAI,OAAO,KAAK,UAAU;KACzB,GAAG;KACH,aAAa,iBAAiB,OAAO,SAAS,OAAO;KACrD,CAAC;MAGJ;GACD,CACD;EACD,oBAAoB,EAAE;EACtB"}
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { _ as Awaitable, a as ResourceServerMetadata, c as OAuthConsent, d as OAuthRefreshToken, f as Prompt, g as VerificationValue, h as StoreTokenType, i as OIDCMetadata, l as OAuthOpaqueAccessToken, m as Scope, n as GrantType, o as AuthorizePrompt, p as SchemaClient, r as OAuthClient, s as OAuthAuthorizationQuery, t as AuthServerMetadata, u as OAuthOptions } from "./oauth-Chk8ejPr.mjs";
2
- import { n as oauthProvider, t as getOAuthProviderState } from "./oauth-wm0HlZm9.mjs";
1
+ import { _ as Awaitable, a as ResourceServerMetadata, c as OAuthConsent, d as OAuthRefreshToken, f as Prompt, g as VerificationValue, h as StoreTokenType, i as OIDCMetadata, l as OAuthOpaqueAccessToken, m as Scope, n as GrantType, o as AuthorizePrompt, p as SchemaClient, r as OAuthClient, s as OAuthAuthorizationQuery, t as AuthServerMetadata, u as OAuthOptions } from "./oauth-DrFFxaBJ.mjs";
2
+ import { n as oauthProvider, t as getOAuthProviderState } from "./oauth-CiaEIjBG.mjs";
3
3
  import { verifyAccessToken } from "better-auth/oauth2";
4
4
  import { JWSAlgorithms, JwtOptions } from "better-auth/plugins";
5
5
  import { JWTPayload } from "jose";
package/dist/index.mjs CHANGED
@@ -1,9 +1,9 @@
1
- import { a as getJwtPlugin, c as isPKCERequired, d as resolveSubjectIdentifier, f as storeClientSecret, g as mcpHandler, i as getClient, l as parseClientMetadata, m as validateClientCredentials, n as decryptStoredClientSecret, p as storeToken, r as deleteFromPrompt, s as getStoredToken, t as basicToClientCredentials, u as parsePrompt } from "./utils-DgozotLg.mjs";
1
+ import { _ as mcpHandler, a as getJwtPlugin, c as isPKCERequired, d as resolveSubjectIdentifier, f as storeClientSecret, h as verifyOAuthQueryParams, i as getClient, l as parseClientMetadata, m as validateClientCredentials, n as decryptStoredClientSecret, p as storeToken, r as deleteFromPrompt, s as getStoredToken, t as basicToClientCredentials, u as parsePrompt } from "./utils-BpUSdl43.mjs";
2
2
  import { APIError, createAuthEndpoint, createAuthMiddleware, getOAuthState, getSessionFromCtx, sessionMiddleware } from "better-auth/api";
3
3
  import { generateCodeChallenge, getJwks, verifyJwsAccessToken } from "better-auth/oauth2";
4
4
  import { APIError as APIError$1 } from "better-call";
5
5
  import { isBrowserFetchRequest } from "@better-auth/core/utils/fetch-metadata";
6
- import { constantTimeEqual, generateRandomString, makeSignature } from "better-auth/crypto";
6
+ import { generateRandomString, makeSignature } from "better-auth/crypto";
7
7
  import { defineRequestState } from "@better-auth/core/context";
8
8
  import { logger } from "@better-auth/core/env";
9
9
  import { BetterAuthError } from "@better-auth/core/error";
@@ -12,7 +12,6 @@ import { mergeSchema } from "better-auth/db";
12
12
  import * as z from "zod";
13
13
  import { signJWT, toExpJWT } from "better-auth/plugins";
14
14
  import { SignJWT, compactVerify, createLocalJWKSet, decodeJwt } from "jose";
15
-
16
15
  //#region src/consent.ts
17
16
  async function consentEndpoint(ctx, opts) {
18
17
  const _query = (await oAuthState.get())?.query;
@@ -97,7 +96,6 @@ async function consentEndpoint(ctx, opts) {
97
96
  url
98
97
  };
99
98
  }
100
-
101
99
  //#endregion
102
100
  //#region src/continue.ts
103
101
  async function continueEndpoint(ctx, opts) {
@@ -151,7 +149,6 @@ async function postLogin(ctx, opts) {
151
149
  url
152
150
  };
153
151
  }
154
-
155
152
  //#endregion
156
153
  //#region src/userinfo.ts
157
154
  /**
@@ -224,7 +221,6 @@ async function userInfoEndpoint(ctx, opts) {
224
221
  ...additionalInfoUserClaims
225
222
  };
226
223
  }
227
-
228
224
  //#endregion
229
225
  //#region src/token.ts
230
226
  /**
@@ -723,7 +719,6 @@ async function handleRefreshTokenGrant(ctx, opts) {
723
719
  const authTime = refreshToken.authTime != null ? new Date(refreshToken.authTime) : void 0;
724
720
  return createUserTokens(ctx, opts, client, requestedScopes ?? scopes, user, refreshToken.referenceId, refreshToken.sessionId, void 0, { refreshToken }, authTime);
725
721
  }
726
-
727
722
  //#endregion
728
723
  //#region src/introspect.ts
729
724
  /**
@@ -984,7 +979,6 @@ async function introspectEndpoint(ctx, opts) {
984
979
  }
985
980
  }
986
981
  }
987
-
988
982
  //#endregion
989
983
  //#region src/logout.ts
990
984
  /**
@@ -1096,7 +1090,13 @@ async function rpInitiatedLogoutEndpoint(ctx, opts) {
1096
1090
  }
1097
1091
  }
1098
1092
  }
1099
-
1093
+ //#endregion
1094
+ //#region src/middleware/index.ts
1095
+ const publicSessionMiddleware = (opts) => createAuthMiddleware(async (ctx) => {
1096
+ if (!opts.allowPublicClientPrelogin) throw new APIError("BAD_REQUEST");
1097
+ const query = ctx.body.oauth_query;
1098
+ if (!await verifyOAuthQueryParams(query, ctx.context.secret)) throw new APIError("UNAUTHORIZED", { error: "invalid_signature" });
1099
+ });
1100
1100
  //#endregion
1101
1101
  //#region src/register.ts
1102
1102
  async function registerEndpoint(ctx, opts) {
@@ -1290,7 +1290,7 @@ function schemaToOAuth(input) {
1290
1290
  software_id: softwareId ?? void 0,
1291
1291
  software_version: softwareVersion ?? void 0,
1292
1292
  software_statement: softwareStatement ?? void 0,
1293
- redirect_uris: redirectUris ?? void 0,
1293
+ redirect_uris: redirectUris ?? [],
1294
1294
  post_logout_redirect_uris: postLogoutRedirectUris ?? void 0,
1295
1295
  token_endpoint_auth_method: tokenEndpointAuthMethod ?? void 0,
1296
1296
  grant_types: grantTypes ?? void 0,
@@ -1305,7 +1305,6 @@ function schemaToOAuth(input) {
1305
1305
  reference_id: referenceId ?? void 0
1306
1306
  };
1307
1307
  }
1308
-
1309
1308
  //#endregion
1310
1309
  //#region src/types/zod.ts
1311
1310
  const DANGEROUS_SCHEMES = [
@@ -1346,7 +1345,6 @@ const SafeUrlSchema = z.url().superRefine((val, ctx) => {
1346
1345
  });
1347
1346
  }
1348
1347
  });
1349
-
1350
1348
  //#endregion
1351
1349
  //#region src/oauthClient/endpoints.ts
1352
1350
  async function getClientEndpoint(ctx, opts) {
@@ -1377,8 +1375,8 @@ async function getClientEndpoint(ctx, opts) {
1377
1375
  * Provides public client fields for any logged-in user.
1378
1376
  * This is commonly used to display information on login flow pages.
1379
1377
  */
1380
- async function getClientPublicEndpoint(ctx, opts) {
1381
- const client = await getClient(ctx, opts, ctx.query.client_id);
1378
+ async function getClientPublicEndpoint(ctx, opts, clientId) {
1379
+ const client = await getClient(ctx, opts, clientId);
1382
1380
  if (!client) throw new APIError("NOT_FOUND", {
1383
1381
  error_description: "client not found",
1384
1382
  error: "not_found"
@@ -1576,7 +1574,6 @@ async function rotateClientSecretEndpoint(ctx, opts) {
1576
1574
  clientSecret: (opts.prefix?.clientSecret ?? "") + clientSecret
1577
1575
  });
1578
1576
  }
1579
-
1580
1577
  //#endregion
1581
1578
  //#region src/oauthClient/index.ts
1582
1579
  const adminCreateOAuthClient = (opts) => createAuthEndpoint("/admin/oauth2/create-client", {
@@ -1942,9 +1939,22 @@ const getOAuthClientPublic = (opts) => createAuthEndpoint("/oauth2/public-client
1942
1939
  method: "GET",
1943
1940
  use: [sessionMiddleware],
1944
1941
  query: z.object({ client_id: z.string() }),
1945
- metadata: { openapi: { description: "Gets publically available client fields" } }
1942
+ metadata: { openapi: { description: "Gets publicly available client fields" } }
1943
+ }, async (ctx) => {
1944
+ const clientId = ctx.query.client_id;
1945
+ return getClientPublicEndpoint(ctx, opts, clientId);
1946
+ });
1947
+ const getOAuthClientPublicPrelogin = (opts) => createAuthEndpoint("/oauth2/public-client-prelogin", {
1948
+ method: "POST",
1949
+ use: [publicSessionMiddleware(opts)],
1950
+ body: z.object({
1951
+ client_id: z.string(),
1952
+ oauth_query: z.string().optional()
1953
+ }),
1954
+ metadata: { openapi: { description: "Gets publicly available client fields (prior to login)" } }
1946
1955
  }, async (ctx) => {
1947
- return getClientPublicEndpoint(ctx, opts);
1956
+ const clientId = ctx.body.client_id;
1957
+ return getClientPublicEndpoint(ctx, opts, clientId);
1948
1958
  });
1949
1959
  const getOAuthClients = (opts) => createAuthEndpoint("/oauth2/get-clients", {
1950
1960
  method: "GET",
@@ -2045,7 +2055,6 @@ const deleteOAuthClient = (opts) => createAuthEndpoint("/oauth2/delete-client",
2045
2055
  }, async (ctx) => {
2046
2056
  return deleteClientEndpoint(ctx, opts);
2047
2057
  });
2048
-
2049
2058
  //#endregion
2050
2059
  //#region src/oauthConsent/endpoints.ts
2051
2060
  async function getConsent(ctx, opts, id) {
@@ -2145,7 +2154,6 @@ async function updateConsentEndpoint(ctx, opts) {
2145
2154
  }
2146
2155
  });
2147
2156
  }
2148
-
2149
2157
  //#endregion
2150
2158
  //#region src/oauthConsent/index.ts
2151
2159
  const getOAuthConsent = (opts) => createAuthEndpoint("/oauth2/get-consent", {
@@ -2182,7 +2190,6 @@ const deleteOAuthConsent = (opts) => createAuthEndpoint("/oauth2/delete-consent"
2182
2190
  }, async (ctx) => {
2183
2191
  return deleteConsentEndpoint(ctx, opts);
2184
2192
  });
2185
-
2186
2193
  //#endregion
2187
2194
  //#region src/revoke.ts
2188
2195
  /**
@@ -2380,7 +2387,6 @@ async function revokeEndpoint(ctx, opts) {
2380
2387
  }
2381
2388
  }
2382
2389
  }
2383
-
2384
2390
  //#endregion
2385
2391
  //#region src/schema.ts
2386
2392
  const schema = {
@@ -2644,7 +2650,6 @@ const schema = {
2644
2650
  }
2645
2651
  }
2646
2652
  };
2647
-
2648
2653
  //#endregion
2649
2654
  //#region src/oauth.ts
2650
2655
  const oAuthState = defineRequestState(() => null);
@@ -2732,15 +2737,11 @@ const oauthProvider = (options) => {
2732
2737
  },
2733
2738
  handler: createAuthMiddleware(async (ctx) => {
2734
2739
  const query = ctx.body.oauth_query;
2735
- let queryParams = new URLSearchParams(query);
2736
- const sig = queryParams.get("sig");
2737
- const exp = Number(queryParams.get("exp"));
2740
+ if (!await verifyOAuthQueryParams(query, ctx.context.secret)) throw new APIError("BAD_REQUEST", { error: "invalid_signature" });
2741
+ const queryParams = new URLSearchParams(query);
2738
2742
  queryParams.delete("sig");
2739
- queryParams = new URLSearchParams(queryParams);
2740
- const verifySig = await makeSignature(queryParams.toString(), ctx.context.secret);
2741
- if (!sig || !constantTimeEqual(sig, verifySig) || /* @__PURE__ */ new Date(exp * 1e3) < /* @__PURE__ */ new Date()) throw new APIError("BAD_REQUEST", { error: "invalid_signature" });
2742
2743
  queryParams.delete("exp");
2743
- await oAuthState.set({ query: new URLSearchParams(queryParams).toString() });
2744
+ await oAuthState.set({ query: queryParams.toString() });
2744
2745
  if (ctx.path === "/sign-in/social" || ctx.path === "/sign-in/oauth2") {
2745
2746
  if (ctx.body.additionalData?.query) return;
2746
2747
  if (!ctx.body.additionalData) ctx.body.additionalData = {};
@@ -3564,6 +3565,7 @@ const oauthProvider = (options) => {
3564
3565
  createOAuthClient: createOAuthClient(opts),
3565
3566
  getOAuthClient: getOAuthClient(opts),
3566
3567
  getOAuthClientPublic: getOAuthClientPublic(opts),
3568
+ getOAuthClientPublicPrelogin: getOAuthClientPublicPrelogin(opts),
3567
3569
  getOAuthClients: getOAuthClients(opts),
3568
3570
  adminUpdateOAuthClient: adminUpdateOAuthClient(opts),
3569
3571
  updateOAuthClient: updateOAuthClient(opts),
@@ -3609,7 +3611,6 @@ const oauthProvider = (options) => {
3609
3611
  ]
3610
3612
  };
3611
3613
  };
3612
-
3613
3614
  //#endregion
3614
3615
  //#region src/authorize.ts
3615
3616
  /**
@@ -3633,6 +3634,9 @@ const handleRedirect = (ctx, uri) => {
3633
3634
  };
3634
3635
  else throw ctx.redirect(uri);
3635
3636
  };
3637
+ function redirectWithPromptNoneError(ctx, opts, query, error, description) {
3638
+ return handleRedirect(ctx, formatErrorURL(query.redirect_uri, error, description, query.state, getIssuer(ctx, opts)));
3639
+ }
3636
3640
  /**
3637
3641
  * Validates that the issuer URL
3638
3642
  * - MUST use HTTPS scheme (HTTP allowed for localhost in dev)
@@ -3684,6 +3688,7 @@ async function authorizeEndpoint(ctx, opts, settings) {
3684
3688
  if (!query.client_id) throw ctx.redirect(getErrorURL(ctx, "invalid_client", "client_id is required"));
3685
3689
  if (!query.response_type) throw ctx.redirect(getErrorURL(ctx, "invalid_request", "response_type is required"));
3686
3690
  const promptSet = ctx.query?.prompt ? parsePrompt(ctx.query?.prompt) : void 0;
3691
+ const promptNone = promptSet?.has("none") ?? false;
3687
3692
  if (promptSet?.has("select_account") && !opts.selectAccount?.page) throw ctx.redirect(getErrorURL(ctx, `unsupported_prompt_select_account`, "unsupported prompt type"));
3688
3693
  if (!(query.response_type === "code")) throw ctx.redirect(getErrorURL(ctx, "unsupported_response_type", "unsupported response type"));
3689
3694
  const client = await getClient(ctx, opts, query.client_id);
@@ -3711,7 +3716,10 @@ async function authorizeEndpoint(ctx, opts, settings) {
3711
3716
  if (!["S256"].includes(query.code_challenge_method)) throw ctx.redirect(formatErrorURL(query.redirect_uri, "invalid_request", "invalid code_challenge method, only S256 is supported", query.state, getIssuer(ctx, opts)));
3712
3717
  }
3713
3718
  const session = await getSessionFromCtx(ctx);
3714
- if (!session || promptSet?.has("login") || promptSet?.has("create")) return redirectWithPromptCode(ctx, opts, promptSet?.has("create") ? "create" : "login");
3719
+ if (!session || promptSet?.has("login") || promptSet?.has("create")) {
3720
+ if (promptNone) return redirectWithPromptNoneError(ctx, opts, query, "login_required", "authentication required");
3721
+ return redirectWithPromptCode(ctx, opts, promptSet?.has("create") ? "create" : "login");
3722
+ }
3715
3723
  if (settings?.isAuthorize && promptSet?.has("select_account")) return redirectWithPromptCode(ctx, opts, "select_account");
3716
3724
  if (settings?.isAuthorize && opts.selectAccount) {
3717
3725
  if (await opts.selectAccount.shouldRedirect({
@@ -3719,7 +3727,10 @@ async function authorizeEndpoint(ctx, opts, settings) {
3719
3727
  user: session.user,
3720
3728
  session: session.session,
3721
3729
  scopes: requestedScopes
3722
- })) return redirectWithPromptCode(ctx, opts, "select_account");
3730
+ })) {
3731
+ if (promptNone) return redirectWithPromptNoneError(ctx, opts, query, "account_selection_required", "End-User account selection is required");
3732
+ return redirectWithPromptCode(ctx, opts, "select_account");
3733
+ }
3723
3734
  }
3724
3735
  if (opts.signup?.shouldRedirect) {
3725
3736
  const signupRedirect = await opts.signup.shouldRedirect({
@@ -3728,7 +3739,10 @@ async function authorizeEndpoint(ctx, opts, settings) {
3728
3739
  session: session.session,
3729
3740
  scopes: requestedScopes
3730
3741
  });
3731
- if (signupRedirect) return redirectWithPromptCode(ctx, opts, "create", typeof signupRedirect === "string" ? signupRedirect : void 0);
3742
+ if (signupRedirect) {
3743
+ if (promptNone) return redirectWithPromptNoneError(ctx, opts, query, "interaction_required", "End-User interaction is required");
3744
+ return redirectWithPromptCode(ctx, opts, "create", typeof signupRedirect === "string" ? signupRedirect : void 0);
3745
+ }
3732
3746
  }
3733
3747
  if (!settings?.postLogin && opts.postLogin) {
3734
3748
  if (await opts.postLogin.shouldRedirect({
@@ -3736,7 +3750,10 @@ async function authorizeEndpoint(ctx, opts, settings) {
3736
3750
  user: session.user,
3737
3751
  session: session.session,
3738
3752
  scopes: requestedScopes
3739
- })) return redirectWithPromptCode(ctx, opts, "post_login");
3753
+ })) {
3754
+ if (promptNone) return redirectWithPromptNoneError(ctx, opts, query, "interaction_required", "End-User interaction is required");
3755
+ return redirectWithPromptCode(ctx, opts, "post_login");
3756
+ }
3740
3757
  }
3741
3758
  if (promptSet?.has("consent")) return redirectWithPromptCode(ctx, opts, "consent");
3742
3759
  const referenceId = await opts.postLogin?.consentReferenceId?.({
@@ -3769,7 +3786,10 @@ async function authorizeEndpoint(ctx, opts, settings) {
3769
3786
  }] : []
3770
3787
  ]
3771
3788
  });
3772
- if (!consent || !requestedScopes.every((val) => consent.scopes.includes(val))) return redirectWithPromptCode(ctx, opts, "consent");
3789
+ if (!consent || !requestedScopes.every((val) => consent.scopes.includes(val))) {
3790
+ if (promptNone) return redirectWithPromptNoneError(ctx, opts, query, "consent_required", "End-User consent is required");
3791
+ return redirectWithPromptCode(ctx, opts, "consent");
3792
+ }
3773
3793
  return redirectWithAuthorizationCode(ctx, opts, {
3774
3794
  query,
3775
3795
  clientId: client.clientId,
@@ -3825,7 +3845,6 @@ async function signParams(ctx, opts) {
3825
3845
  params.append("sig", signature);
3826
3846
  return params.toString();
3827
3847
  }
3828
-
3829
3848
  //#endregion
3830
3849
  //#region src/metadata.ts
3831
3850
  function authServerMetadata(ctx, opts, overrides) {
@@ -3877,7 +3896,8 @@ function oidcServerMetadata(ctx, opts) {
3877
3896
  "login",
3878
3897
  "consent",
3879
3898
  "create",
3880
- "select_account"
3899
+ "select_account",
3900
+ "none"
3881
3901
  ]
3882
3902
  };
3883
3903
  }
@@ -3923,7 +3943,7 @@ const oauthProviderOpenIdConfigMetadata = (auth, opts) => {
3923
3943
  });
3924
3944
  };
3925
3945
  };
3926
-
3927
3946
  //#endregion
3928
3947
  export { authServerMetadata, getOAuthProviderState, mcpHandler, oauthProvider, oauthProviderAuthServerMetadata, oauthProviderOpenIdConfigMetadata, oidcServerMetadata };
3948
+
3929
3949
  //# sourceMappingURL=index.mjs.map