@better-auth/oauth-provider 1.4.8-beta.7
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/LICENSE.md +17 -0
- package/dist/client-resource.d.mts +81 -0
- package/dist/client-resource.mjs +75 -0
- package/dist/client.d.mts +19 -0
- package/dist/client.mjs +38 -0
- package/dist/index.d.mts +65 -0
- package/dist/index.mjs +3867 -0
- package/dist/oauth-Cex7QJsW.d.mts +2008 -0
- package/dist/oauth-kjs13QN6.d.mts +1482 -0
- package/dist/utils-CSiY9oUk.mjs +286 -0
- package/package.json +82 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
Copyright (c) 2024 - present, Bereket Engida
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
|
5
|
+
and associated documentation files (the "Software"), to deal in the Software without restriction,
|
|
6
|
+
including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
|
7
|
+
sublicense, and/or sell copies of the Software, and to permit persons to whom the Software
|
|
8
|
+
is furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in all copies or
|
|
11
|
+
substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
|
14
|
+
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
15
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
16
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
17
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { a as ResourceServerMetadata } from "./oauth-kjs13QN6.mjs";
|
|
2
|
+
import { JWTPayload, JWTVerifyOptions } from "jose";
|
|
3
|
+
import { Auth } from "better-auth/types";
|
|
4
|
+
|
|
5
|
+
//#region src/client-resource.d.ts
|
|
6
|
+
declare const oauthProviderResourceClient: <T extends Auth | undefined>(auth?: T) => {
|
|
7
|
+
id: "oauth-provider-resource-client";
|
|
8
|
+
getActions(): {
|
|
9
|
+
/**
|
|
10
|
+
* Performs verification of an access token for your APIs. Can perform
|
|
11
|
+
* local verification using `jwksUrl` by default. Can also be configured
|
|
12
|
+
* for remote introspection using `remoteVerify` if a confidential client
|
|
13
|
+
* is set up for this API.
|
|
14
|
+
*
|
|
15
|
+
* The optional auth parameter can fill known values automatically.
|
|
16
|
+
*/
|
|
17
|
+
verifyAccessToken: VerifyAccessTokenOutput<T>;
|
|
18
|
+
/**
|
|
19
|
+
* An authorization server does not typically publish
|
|
20
|
+
* the `/.well-known/oauth-protected-resource` themselves.
|
|
21
|
+
* Thus, we provide a client-only endpoint to help set up
|
|
22
|
+
* your protected resource metadata.
|
|
23
|
+
*
|
|
24
|
+
* The optional auth parameter can fill known values automatically.
|
|
25
|
+
*
|
|
26
|
+
* @see https://datatracker.ietf.org/doc/html/rfc8414#section-2
|
|
27
|
+
*/
|
|
28
|
+
getProtectedResourceMetadata: ProtectedResourceMetadataOutput<T>;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
interface VerifyAccessTokenRemote {
|
|
32
|
+
/** Full url of the introspect endpoint. Should end with `/oauth2/introspect` */
|
|
33
|
+
introspectUrl: string;
|
|
34
|
+
/** Client Secret */
|
|
35
|
+
clientId: string;
|
|
36
|
+
/** Client Secret */
|
|
37
|
+
clientSecret: string;
|
|
38
|
+
/**
|
|
39
|
+
* Forces remote verification of a token.
|
|
40
|
+
* This ensures attached session (if applicable)
|
|
41
|
+
* is also still active.
|
|
42
|
+
*/
|
|
43
|
+
force?: boolean;
|
|
44
|
+
}
|
|
45
|
+
type VerifyAccessTokenOutput<T> = T extends Auth ? (token: string | undefined, opts?: VerifyAccessTokenAuthOpts) => Promise<JWTPayload> : (token: string | undefined, opts: VerifyAccessTokenNoAuthOpts) => Promise<JWTPayload>;
|
|
46
|
+
type VerifyAccessTokenAuthOpts = {
|
|
47
|
+
verifyOptions?: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience">>;
|
|
48
|
+
scopes?: string[];
|
|
49
|
+
jwksUrl?: string;
|
|
50
|
+
remoteVerify?: VerifyAccessTokenRemote;
|
|
51
|
+
/** Maps non-url (ie urn, client) resources to resource_metadata */
|
|
52
|
+
resourceMetadataMappings?: Record<string, string>;
|
|
53
|
+
};
|
|
54
|
+
type VerifyAccessTokenNoAuthOpts = {
|
|
55
|
+
verifyOptions: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience" | "issuer">>;
|
|
56
|
+
scopes?: string[];
|
|
57
|
+
jwksUrl: string;
|
|
58
|
+
remoteVerify?: VerifyAccessTokenRemote;
|
|
59
|
+
/** Maps non-url (ie urn, client) resources to resource_metadata */
|
|
60
|
+
resourceMetadataMappings?: Record<string, string>;
|
|
61
|
+
} | {
|
|
62
|
+
verifyOptions: JWTVerifyOptions & Required<Pick<JWTVerifyOptions, "audience" | "issuer">>;
|
|
63
|
+
scopes?: string[];
|
|
64
|
+
jwksUrl?: string;
|
|
65
|
+
remoteVerify: VerifyAccessTokenRemote;
|
|
66
|
+
/** Maps non-url (ie urn, client) resources to resource_metadata */
|
|
67
|
+
resourceMetadataMappings?: Record<string, string>;
|
|
68
|
+
};
|
|
69
|
+
type ProtectedResourceMetadataOutput<T> = T extends Auth ? (overrides?: Partial<ResourceServerMetadata>, opts?: {
|
|
70
|
+
silenceWarnings?: {
|
|
71
|
+
oidcScopes?: boolean;
|
|
72
|
+
};
|
|
73
|
+
externalScopes?: string[];
|
|
74
|
+
}) => Promise<ResourceServerMetadata> : (overrides: ResourceServerMetadata, opts?: {
|
|
75
|
+
silenceWarnings?: {
|
|
76
|
+
oidcScopes?: boolean;
|
|
77
|
+
};
|
|
78
|
+
externalScopes?: string[];
|
|
79
|
+
}) => Promise<ResourceServerMetadata>;
|
|
80
|
+
//#endregion
|
|
81
|
+
export { VerifyAccessTokenRemote, oauthProviderResourceClient };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { a as getJwtPlugin, f as handleMcpErrors, o as getOAuthProviderPlugin } from "./utils-CSiY9oUk.mjs";
|
|
2
|
+
import { verifyAccessToken } from "better-auth/oauth2";
|
|
3
|
+
import { APIError } from "better-call";
|
|
4
|
+
import { BetterAuthError } from "@better-auth/core/error";
|
|
5
|
+
import { logger } from "@better-auth/core/env";
|
|
6
|
+
|
|
7
|
+
//#region src/client-resource.ts
|
|
8
|
+
const oauthProviderResourceClient = (auth) => {
|
|
9
|
+
const oauthProviderOptions = (auth ? getOAuthProviderPlugin(auth) : void 0)?.options;
|
|
10
|
+
const jwtPluginOptions = (auth && !oauthProviderOptions?.disableJwtPlugin ? getJwtPlugin(auth) : void 0)?.options;
|
|
11
|
+
const authServerBaseUrl = auth?.options.baseURL;
|
|
12
|
+
const authServerBasePath = auth?.options.basePath;
|
|
13
|
+
const authorizationServer = jwtPluginOptions?.jwt?.issuer ?? authServerBaseUrl;
|
|
14
|
+
return {
|
|
15
|
+
id: "oauth-provider-resource-client",
|
|
16
|
+
getActions() {
|
|
17
|
+
return {
|
|
18
|
+
verifyAccessToken: (async (token, opts) => {
|
|
19
|
+
const audience = opts?.verifyOptions?.audience ?? authServerBaseUrl;
|
|
20
|
+
const issuer = opts?.verifyOptions?.issuer ?? jwtPluginOptions?.jwt?.issuer ?? authServerBaseUrl;
|
|
21
|
+
if (!audience) throw Error("please define opts.verifyOptions.audience");
|
|
22
|
+
if (!issuer) throw Error("please define opts.verifyOptions.issuer");
|
|
23
|
+
const jwksUrl = opts?.jwksUrl ?? jwtPluginOptions?.jwks?.remoteUrl ?? (authServerBaseUrl ? `${authServerBaseUrl + (authServerBasePath ?? "")}/jwks` : void 0);
|
|
24
|
+
const introspectUrl = opts?.remoteVerify?.introspectUrl ?? (authServerBaseUrl ? `${authServerBaseUrl}${authServerBasePath ?? ""}/oauth2/introspect` : void 0);
|
|
25
|
+
try {
|
|
26
|
+
if (!token?.length) throw new APIError("UNAUTHORIZED", { message: "missing authorization header" });
|
|
27
|
+
return await verifyAccessToken(token, {
|
|
28
|
+
...opts,
|
|
29
|
+
jwksUrl,
|
|
30
|
+
verifyOptions: {
|
|
31
|
+
...opts?.verifyOptions,
|
|
32
|
+
audience,
|
|
33
|
+
issuer
|
|
34
|
+
},
|
|
35
|
+
remoteVerify: opts?.remoteVerify && introspectUrl ? {
|
|
36
|
+
...opts.remoteVerify,
|
|
37
|
+
introspectUrl
|
|
38
|
+
} : void 0
|
|
39
|
+
});
|
|
40
|
+
} catch (error) {
|
|
41
|
+
throw handleMcpErrors(error, audience, { resourceMetadataMappings: opts?.resourceMetadataMappings });
|
|
42
|
+
}
|
|
43
|
+
}),
|
|
44
|
+
getProtectedResourceMetadata: (async (overrides, opts) => {
|
|
45
|
+
const resource = overrides?.resource ?? authServerBaseUrl;
|
|
46
|
+
if (!resource) throw Error("missing required resource");
|
|
47
|
+
if (oauthProviderOptions?.scopes && opts?.externalScopes && (overrides?.authorization_servers?.length ?? 0) <= 1) throw new BetterAuthError("external scopes should not be provided with one authorization server");
|
|
48
|
+
if (overrides?.scopes_supported) {
|
|
49
|
+
const allValidScopes = new Set([...oauthProviderOptions?.scopes ?? [], ...opts?.externalScopes ?? []]);
|
|
50
|
+
for (const sc of overrides.scopes_supported) {
|
|
51
|
+
if (sc === "openid") throw new BetterAuthError("Only the Auth Server should utilize the openid scope");
|
|
52
|
+
if ([
|
|
53
|
+
"profile",
|
|
54
|
+
"email",
|
|
55
|
+
"phone",
|
|
56
|
+
"address"
|
|
57
|
+
].includes(sc)) {
|
|
58
|
+
if (!opts?.silenceWarnings?.oidcScopes) logger.warn(`"${sc}" is typically restricted for the authorization server, a resource server typically shouldn't handle this scope`);
|
|
59
|
+
}
|
|
60
|
+
if (!allValidScopes.has(sc)) throw new BetterAuthError(`Unsupported scope ${sc}. If external, please add to "externalScopes"`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
resource,
|
|
65
|
+
authorization_servers: authorizationServer ? [authorizationServer] : void 0,
|
|
66
|
+
...overrides
|
|
67
|
+
};
|
|
68
|
+
})
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
export { oauthProviderResourceClient };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import "./oauth-kjs13QN6.mjs";
|
|
2
|
+
import { t as oauthProvider } from "./oauth-Cex7QJsW.mjs";
|
|
3
|
+
import * as _better_fetch_fetch0 from "@better-fetch/fetch";
|
|
4
|
+
|
|
5
|
+
//#region src/client.d.ts
|
|
6
|
+
declare const oauthProviderClient: () => {
|
|
7
|
+
id: "oauth-provider-client";
|
|
8
|
+
fetchPlugins: {
|
|
9
|
+
id: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
hooks: {
|
|
13
|
+
onRequest<T extends Record<string, any>>(ctx: _better_fetch_fetch0.RequestContext<T>): Promise<void>;
|
|
14
|
+
};
|
|
15
|
+
}[];
|
|
16
|
+
$InferServerPlugin: ReturnType<typeof oauthProvider>;
|
|
17
|
+
};
|
|
18
|
+
//#endregion
|
|
19
|
+
export { oauthProviderClient };
|
package/dist/client.mjs
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { safeJSONParse } from "@better-auth/core/utils";
|
|
2
|
+
|
|
3
|
+
//#region src/client.ts
|
|
4
|
+
function parseSignedQuery(search) {
|
|
5
|
+
const params = new URLSearchParams(search);
|
|
6
|
+
if (params.has("sig")) {
|
|
7
|
+
const signedParams = new URLSearchParams();
|
|
8
|
+
for (const [key, value] of params.entries()) {
|
|
9
|
+
signedParams.append(key, value);
|
|
10
|
+
if (key === "sig") break;
|
|
11
|
+
}
|
|
12
|
+
return signedParams.toString();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
const oauthProviderClient = () => {
|
|
16
|
+
return {
|
|
17
|
+
id: "oauth-provider-client",
|
|
18
|
+
fetchPlugins: [{
|
|
19
|
+
id: "oauth-provider-signin",
|
|
20
|
+
name: "oauth-provider-signin",
|
|
21
|
+
description: "Adds the current page query to oauth requests",
|
|
22
|
+
hooks: { async onRequest(ctx) {
|
|
23
|
+
const headers = ctx.headers;
|
|
24
|
+
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
|
+
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({
|
|
28
|
+
...body,
|
|
29
|
+
oauth_query: typeof window !== "undefined" ? parseSignedQuery(window?.location?.search) : void 0
|
|
30
|
+
});
|
|
31
|
+
} }
|
|
32
|
+
}],
|
|
33
|
+
$InferServerPlugin: {}
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
//#endregion
|
|
38
|
+
export { oauthProviderClient };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
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-kjs13QN6.mjs";
|
|
2
|
+
import { t as oauthProvider } from "./oauth-Cex7QJsW.mjs";
|
|
3
|
+
import { verifyAccessToken } from "better-auth/oauth2";
|
|
4
|
+
import { JWSAlgorithms, JwtOptions } from "better-auth/plugins/jwt";
|
|
5
|
+
import { JWTPayload } from "jose";
|
|
6
|
+
import { GenericEndpointContext } from "@better-auth/core";
|
|
7
|
+
|
|
8
|
+
//#region src/mcp.d.ts
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A request middleware handler that checks and responds with
|
|
12
|
+
* a WWW-Authenticate header for unauthenticated responses.
|
|
13
|
+
*
|
|
14
|
+
* @external
|
|
15
|
+
*/
|
|
16
|
+
declare const mcpHandler: (/** Resource is the same url as the audience */
|
|
17
|
+
verifyOptions: Parameters<typeof verifyAccessToken>[1], handler: (req: Request, jwt: JWTPayload) => Awaitable<Response>, opts?: {
|
|
18
|
+
/** Maps non-url (ie urn, client) resources to resource_metadata */
|
|
19
|
+
resourceMetadataMappings: Record<string, string>;
|
|
20
|
+
}) => (req: Request) => Promise<Response>;
|
|
21
|
+
//#endregion
|
|
22
|
+
//#region src/metadata.d.ts
|
|
23
|
+
declare function authServerMetadata(ctx: GenericEndpointContext, opts?: JwtOptions, overrides?: {
|
|
24
|
+
scopes_supported?: AuthServerMetadata["scopes_supported"];
|
|
25
|
+
public_client_supported?: boolean;
|
|
26
|
+
grant_types_supported?: GrantType[];
|
|
27
|
+
jwt_disabled?: boolean;
|
|
28
|
+
}): AuthServerMetadata;
|
|
29
|
+
declare function oidcServerMetadata(ctx: GenericEndpointContext, opts: OAuthOptions<Scope[]> & {
|
|
30
|
+
claims?: string[];
|
|
31
|
+
}): Omit<OIDCMetadata, "id_token_signing_alg_values_supported"> & {
|
|
32
|
+
id_token_signing_alg_values_supported: JWSAlgorithms[] | ["HS256"];
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Provides an exportable `/.well-known/oauth-authorization-server`.
|
|
36
|
+
*
|
|
37
|
+
* Useful when basePath prevents the endpoint from being located at the root
|
|
38
|
+
* and must be provided manually.
|
|
39
|
+
*
|
|
40
|
+
* @external
|
|
41
|
+
*/
|
|
42
|
+
declare const oauthProviderAuthServerMetadata: <Auth extends {
|
|
43
|
+
api: {
|
|
44
|
+
getOAuthServerConfig: (...args: any) => any;
|
|
45
|
+
};
|
|
46
|
+
}>(auth: Auth, opts?: {
|
|
47
|
+
headers?: HeadersInit;
|
|
48
|
+
}) => (_request: Request) => Promise<Response>;
|
|
49
|
+
/**
|
|
50
|
+
* Provides an exportable `/.well-known/openid-configuration`.
|
|
51
|
+
*
|
|
52
|
+
* Useful when basePath prevents the endpoint from being located at the root
|
|
53
|
+
* and must be provided manually.
|
|
54
|
+
*
|
|
55
|
+
* @external
|
|
56
|
+
*/
|
|
57
|
+
declare const oauthProviderOpenIdConfigMetadata: <Auth extends {
|
|
58
|
+
api: {
|
|
59
|
+
getOpenIdConfig: (...args: any) => any;
|
|
60
|
+
};
|
|
61
|
+
}>(auth: Auth, opts?: {
|
|
62
|
+
headers?: HeadersInit;
|
|
63
|
+
}) => (_request: Request) => Promise<Response>;
|
|
64
|
+
//#endregion
|
|
65
|
+
export { AuthServerMetadata, AuthorizePrompt, OAuthAuthorizationQuery, OAuthClient, OAuthConsent, OAuthOpaqueAccessToken, OAuthOptions, OAuthRefreshToken, OIDCMetadata, Prompt, ResourceServerMetadata, SchemaClient, Scope, StoreTokenType, VerificationValue, authServerMetadata, mcpHandler, oauthProvider, oauthProviderAuthServerMetadata, oauthProviderOpenIdConfigMetadata, oidcServerMetadata };
|