@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.
- package/dist/client-resource.d.mts +1 -1
- package/dist/client-resource.mjs +3 -4
- package/dist/client-resource.mjs.map +1 -1
- package/dist/client.d.mts +1 -2
- package/dist/client.mjs +3 -5
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +58 -38
- package/dist/index.mjs.map +1 -1
- package/dist/oauth-CiaEIjBG.d.mts +1879 -0
- package/dist/{oauth-Chk8ejPr.d.mts → oauth-DrFFxaBJ.d.mts} +6 -1
- package/dist/{utils-DgozotLg.mjs → utils-BpUSdl43.mjs} +12 -6
- package/dist/utils-BpUSdl43.mjs.map +1 -0
- package/package.json +7 -7
- package/dist/oauth-wm0HlZm9.d.mts +0 -2067
- package/dist/utils-DgozotLg.mjs.map +0 -1
package/dist/client-resource.mjs
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { a as getJwtPlugin,
|
|
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
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
|
-
|
|
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:
|
|
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
|
package/dist/client.mjs.map
CHANGED
|
@@ -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\
|
|
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-
|
|
2
|
-
import { n as oauthProvider, t as getOAuthProviderState } from "./oauth-
|
|
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,
|
|
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 {
|
|
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 ??
|
|
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,
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
2736
|
-
const
|
|
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:
|
|
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"))
|
|
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
|
-
}))
|
|
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)
|
|
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
|
-
}))
|
|
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)))
|
|
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
|