@better-auth/oauth-provider 1.5.0-beta.2 → 1.5.0-beta.4
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 +15 -12
- package/dist/client-resource.mjs +17 -4
- package/dist/client.d.mts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +17 -12
- package/dist/{oauth-C1OnEiU-.d.mts → oauth-BW67CKnu.d.mts} +9 -5
- package/dist/{utils-CSiY9oUk.mjs → utils-CAYiYjbw.mjs} +13 -3
- package/package.json +7 -7
package/LICENSE.md
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
The MIT License (MIT)
|
|
2
2
|
Copyright (c) 2024 - present, Bereket Engida
|
|
3
3
|
|
|
4
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
-
and associated documentation files (the
|
|
6
|
-
including without limitation the rights to
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
this software and associated documentation files (the “Software”), to deal in
|
|
6
|
+
the Software without restriction, including without limitation the rights to
|
|
7
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
subject to the following conditions:
|
|
9
10
|
|
|
10
|
-
The above copyright notice and this permission notice shall be included in all
|
|
11
|
-
substantial portions of the Software.
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
12
13
|
|
|
13
|
-
THE SOFTWARE IS PROVIDED
|
|
14
|
-
BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
17
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
18
|
+
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
19
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
20
|
+
DEALINGS IN THE SOFTWARE.
|
package/dist/client-resource.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getJwtPlugin,
|
|
1
|
+
import { a as getJwtPlugin, o as getOAuthProviderPlugin, p as handleMcpErrors } from "./utils-CAYiYjbw.mjs";
|
|
2
2
|
import { verifyAccessToken } from "better-auth/oauth2";
|
|
3
3
|
import { APIError } from "better-call";
|
|
4
4
|
import { BetterAuthError } from "@better-auth/core/error";
|
|
@@ -6,16 +6,27 @@ import { logger } from "@better-auth/core/env";
|
|
|
6
6
|
|
|
7
7
|
//#region src/client-resource.ts
|
|
8
8
|
const oauthProviderResourceClient = (auth) => {
|
|
9
|
-
|
|
10
|
-
const
|
|
9
|
+
let oauthProviderPlugin;
|
|
10
|
+
const getOauthProviderPlugin = async () => {
|
|
11
|
+
if (!oauthProviderPlugin) oauthProviderPlugin = auth ? getOAuthProviderPlugin(await auth.$context) : void 0;
|
|
12
|
+
return oauthProviderPlugin;
|
|
13
|
+
};
|
|
14
|
+
let jwtPlugin;
|
|
15
|
+
const getJwtPluginOptions = async () => {
|
|
16
|
+
if (!jwtPlugin) jwtPlugin = auth && !(await getOauthProviderPlugin())?.options?.disableJwtPlugin ? getJwtPlugin(await auth.$context) : void 0;
|
|
17
|
+
return jwtPlugin?.options;
|
|
18
|
+
};
|
|
19
|
+
const getAuthorizationServer = async () => {
|
|
20
|
+
return (await getJwtPluginOptions())?.jwt?.issuer ?? authServerBaseUrl;
|
|
21
|
+
};
|
|
11
22
|
const authServerBaseUrl = auth?.options.baseURL;
|
|
12
23
|
const authServerBasePath = auth?.options.basePath;
|
|
13
|
-
const authorizationServer = jwtPluginOptions?.jwt?.issuer ?? authServerBaseUrl;
|
|
14
24
|
return {
|
|
15
25
|
id: "oauth-provider-resource-client",
|
|
16
26
|
getActions() {
|
|
17
27
|
return {
|
|
18
28
|
verifyAccessToken: (async (token, opts) => {
|
|
29
|
+
const jwtPluginOptions = await getJwtPluginOptions();
|
|
19
30
|
const audience = opts?.verifyOptions?.audience ?? authServerBaseUrl;
|
|
20
31
|
const issuer = opts?.verifyOptions?.issuer ?? jwtPluginOptions?.jwt?.issuer ?? authServerBaseUrl;
|
|
21
32
|
if (!audience) throw Error("please define opts.verifyOptions.audience");
|
|
@@ -43,6 +54,7 @@ const oauthProviderResourceClient = (auth) => {
|
|
|
43
54
|
}),
|
|
44
55
|
getProtectedResourceMetadata: (async (overrides, opts) => {
|
|
45
56
|
const resource = overrides?.resource ?? authServerBaseUrl;
|
|
57
|
+
const oauthProviderOptions = (await getOauthProviderPlugin())?.options;
|
|
46
58
|
if (!resource) throw Error("missing required resource");
|
|
47
59
|
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
60
|
if (overrides?.scopes_supported) {
|
|
@@ -60,6 +72,7 @@ const oauthProviderResourceClient = (auth) => {
|
|
|
60
72
|
if (!allValidScopes.has(sc)) throw new BetterAuthError(`Unsupported scope ${sc}. If external, please add to "externalScopes"`);
|
|
61
73
|
}
|
|
62
74
|
}
|
|
75
|
+
const authorizationServer = await getAuthorizationServer();
|
|
63
76
|
return {
|
|
64
77
|
resource,
|
|
65
78
|
authorization_servers: authorizationServer ? [authorizationServer] : void 0,
|
package/dist/client.d.mts
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
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-BrFoF22H.mjs";
|
|
2
|
-
import { t as oauthProvider } from "./oauth-
|
|
2
|
+
import { t as oauthProvider } from "./oauth-BW67CKnu.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,4 +1,4 @@
|
|
|
1
|
-
import { a as getJwtPlugin, c as
|
|
1
|
+
import { a as getJwtPlugin, c as parseClientMetadata, d as storeToken, f as validateClientCredentials, i as getClient, l as parsePrompt, m as mcpHandler, n as decryptStoredClientSecret, r as deleteFromPrompt, s as getStoredToken, t as basicToClientCredentials, u as storeClientSecret } from "./utils-CAYiYjbw.mjs";
|
|
2
2
|
import { generateCodeChallenge, getJwks, verifyJwsAccessToken } from "better-auth/oauth2";
|
|
3
3
|
import { APIError } from "better-call";
|
|
4
4
|
import { BetterAuthError } from "@better-auth/core/error";
|
|
@@ -516,7 +516,7 @@ async function createJwtAccessToken(ctx, opts, user, client, audience, scopes, r
|
|
|
516
516
|
scopes,
|
|
517
517
|
resource: ctx.body.resource,
|
|
518
518
|
referenceId,
|
|
519
|
-
metadata:
|
|
519
|
+
metadata: parseClientMetadata(client.metadata)
|
|
520
520
|
}) : {};
|
|
521
521
|
const jwtPluginOptions = getJwtPlugin(ctx.context).options;
|
|
522
522
|
return signJWT(ctx, {
|
|
@@ -547,7 +547,7 @@ async function createIdToken(ctx, opts, user, client, scopes, nonce, sessionId)
|
|
|
547
547
|
const customClaims = opts.customIdTokenClaims ? await opts.customIdTokenClaims({
|
|
548
548
|
user,
|
|
549
549
|
scopes,
|
|
550
|
-
metadata:
|
|
550
|
+
metadata: parseClientMetadata(client.metadata)
|
|
551
551
|
}) : {};
|
|
552
552
|
const jwtPluginOptions = opts.disableJwtPlugin ? void 0 : getJwtPlugin(ctx.context).options;
|
|
553
553
|
const payload = {
|
|
@@ -857,7 +857,7 @@ async function handleClientCredentialsGrant(ctx, opts) {
|
|
|
857
857
|
const customClaims = opts.customAccessTokenClaims ? await opts.customAccessTokenClaims({
|
|
858
858
|
scopes: requestedScopes,
|
|
859
859
|
resource: ctx.body.resource,
|
|
860
|
-
metadata:
|
|
860
|
+
metadata: parseClientMetadata(client.metadata)
|
|
861
861
|
}) : {};
|
|
862
862
|
const accessToken = audience && !opts.disableJwtPlugin ? await signJWT(ctx, {
|
|
863
863
|
options: jwtPluginOptions,
|
|
@@ -1069,7 +1069,7 @@ async function validateOpaqueAccessToken(ctx, opts, token, clientId) {
|
|
|
1069
1069
|
user,
|
|
1070
1070
|
scopes: accessToken.scopes,
|
|
1071
1071
|
referenceId: accessToken?.referenceId,
|
|
1072
|
-
metadata: client?.metadata
|
|
1072
|
+
metadata: parseClientMetadata(client?.metadata)
|
|
1073
1073
|
}) : {};
|
|
1074
1074
|
const jwtPluginOptions = (opts.disableJwtPlugin ? void 0 : getJwtPlugin(ctx.context))?.options;
|
|
1075
1075
|
return {
|
|
@@ -1420,14 +1420,19 @@ async function createOAuthClientEndpoint(ctx, opts, settings) {
|
|
|
1420
1420
|
* @returns
|
|
1421
1421
|
*/
|
|
1422
1422
|
function oauthToSchema(input) {
|
|
1423
|
-
const { client_id: clientId, client_secret: clientSecret, client_secret_expires_at: _expiresAt, scope: _scope, user_id: userId, client_id_issued_at: _createdAt, client_name: name, client_uri: uri, logo_uri: icon, contacts, tos_uri: tos, policy_uri: policy, jwks: _jwks, jwks_uri: _jwksUri, software_id: softwareId, software_version: softwareVersion, software_statement: softwareStatement, redirect_uris: redirectUris, post_logout_redirect_uris: postLogoutRedirectUris, token_endpoint_auth_method: tokenEndpointAuthMethod, grant_types: grantTypes, response_types: responseTypes, public: _public, type, disabled, skip_consent: skipConsent, enable_end_session: enableEndSession, reference_id: referenceId, ...rest } = input;
|
|
1423
|
+
const { client_id: clientId, client_secret: clientSecret, client_secret_expires_at: _expiresAt, scope: _scope, user_id: userId, client_id_issued_at: _createdAt, client_name: name, client_uri: uri, logo_uri: icon, contacts, tos_uri: tos, policy_uri: policy, jwks: _jwks, jwks_uri: _jwksUri, software_id: softwareId, software_version: softwareVersion, software_statement: softwareStatement, redirect_uris: redirectUris, post_logout_redirect_uris: postLogoutRedirectUris, token_endpoint_auth_method: tokenEndpointAuthMethod, grant_types: grantTypes, response_types: responseTypes, public: _public, type, disabled, skip_consent: skipConsent, enable_end_session: enableEndSession, reference_id: referenceId, metadata: inputMetadata, ...rest } = input;
|
|
1424
1424
|
const expiresAt = _expiresAt ? /* @__PURE__ */ new Date(_expiresAt * 1e3) : void 0;
|
|
1425
1425
|
const createdAt = _createdAt ? /* @__PURE__ */ new Date(_createdAt * 1e3) : void 0;
|
|
1426
|
+
const scopes = _scope?.split(" ");
|
|
1427
|
+
const metadataObj = {
|
|
1428
|
+
...rest && Object.keys(rest).length ? rest : {},
|
|
1429
|
+
...inputMetadata && typeof inputMetadata === "object" ? inputMetadata : {}
|
|
1430
|
+
};
|
|
1426
1431
|
return {
|
|
1427
1432
|
clientId,
|
|
1428
1433
|
clientSecret,
|
|
1429
1434
|
disabled,
|
|
1430
|
-
scopes
|
|
1435
|
+
scopes,
|
|
1431
1436
|
userId,
|
|
1432
1437
|
createdAt,
|
|
1433
1438
|
expiresAt,
|
|
@@ -1450,7 +1455,7 @@ function oauthToSchema(input) {
|
|
|
1450
1455
|
skipConsent,
|
|
1451
1456
|
enableEndSession,
|
|
1452
1457
|
referenceId,
|
|
1453
|
-
metadata:
|
|
1458
|
+
metadata: Object.keys(metadataObj).length ? JSON.stringify(metadataObj) : void 0
|
|
1454
1459
|
};
|
|
1455
1460
|
}
|
|
1456
1461
|
/**
|
|
@@ -1465,7 +1470,7 @@ function schemaToOAuth(input) {
|
|
|
1465
1470
|
const _createdAt = createdAt ? Math.round(createdAt.getTime() / 1e3) : void 0;
|
|
1466
1471
|
const _scopes = scopes?.join(" ");
|
|
1467
1472
|
return {
|
|
1468
|
-
...
|
|
1473
|
+
...parseClientMetadata(metadata),
|
|
1469
1474
|
client_id: clientId,
|
|
1470
1475
|
client_secret: clientSecret ?? void 0,
|
|
1471
1476
|
client_secret_expires_at: clientSecret ? _expiresAt ?? 0 : void 0,
|
|
@@ -2857,12 +2862,12 @@ const oauthProvider = (options) => {
|
|
|
2857
2862
|
if (opts.disableJwtPlugin && (opts.storeClientSecret === "hashed" || typeof opts.storeClientSecret === "object" && "hash" in opts.storeClientSecret)) throw new BetterAuthError("unable to store hashed secrets because id tokens will be signed with secret");
|
|
2858
2863
|
if (!opts.disableJwtPlugin && (opts.storeClientSecret === "encrypted" || typeof opts.storeClientSecret === "object" && ("encrypt" in opts.storeClientSecret || "decrypt" in opts.storeClientSecret))) throw new BetterAuthError("encryption method not recommended, please use 'hashed' or the 'hash' function");
|
|
2859
2864
|
return {
|
|
2860
|
-
id: "
|
|
2865
|
+
id: "oauth-provider",
|
|
2861
2866
|
options: opts,
|
|
2862
2867
|
init: (ctx) => {
|
|
2863
2868
|
if (ctx.options.session && !ctx.options.session.storeSessionInDatabase) throw new BetterAuthError("OAuth Provider requires `session.storeSessionInDatabase: true` when using secondaryStorage");
|
|
2864
2869
|
if (!opts.disableJwtPlugin) {
|
|
2865
|
-
const issuer = getJwtPlugin(ctx)
|
|
2870
|
+
const issuer = (getJwtPlugin(ctx)?.options)?.jwt?.issuer ?? ctx.baseURL;
|
|
2866
2871
|
const issuerPath = new URL(issuer).pathname;
|
|
2867
2872
|
if (!opts.silenceWarnings?.oauthAuthServerConfig && !(ctx.options.basePath === "/" && issuerPath === "/")) logger.warn(`Please ensure '/.well-known/oauth-authorization-server${issuerPath === "/" ? "" : issuerPath}' exists. Upon completion, clear with silenceWarnings.oauthAuthServerConfig.`);
|
|
2868
2873
|
if (!opts.silenceWarnings?.openidConfig && ctx.options.basePath !== issuerPath && opts.scopes?.includes("openid")) logger.warn(`Please ensure '${issuerPath}${issuerPath.endsWith("/") ? "" : "/"}.well-known/openid-configuration' exists. Upon completion, clear with silenceWarnings.openidConfig.`);
|
|
@@ -2915,7 +2920,7 @@ const oauthProvider = (options) => {
|
|
|
2915
2920
|
metadata: { SERVER_ONLY: true }
|
|
2916
2921
|
}, async (ctx) => {
|
|
2917
2922
|
if (opts.scopes && opts.scopes.includes("openid")) return oidcServerMetadata(ctx, opts);
|
|
2918
|
-
else return authServerMetadata(ctx, opts.disableJwtPlugin ? void 0 : getJwtPlugin(ctx.context)
|
|
2923
|
+
else return authServerMetadata(ctx, opts.disableJwtPlugin ? void 0 : getJwtPlugin(ctx.context)?.options, { scopes_supported: opts.advertisedMetadata?.scopes_supported ?? opts.scopes });
|
|
2919
2924
|
}),
|
|
2920
2925
|
getOpenIdConfig: createAuthEndpoint("/.well-known/openid-configuration", {
|
|
2921
2926
|
method: "GET",
|
|
@@ -7,7 +7,13 @@ import * as jose0 from "jose";
|
|
|
7
7
|
import * as better_auth0 from "better-auth";
|
|
8
8
|
|
|
9
9
|
//#region src/oauth.d.ts
|
|
10
|
-
|
|
10
|
+
declare module "@better-auth/core" {
|
|
11
|
+
interface BetterAuthPluginRegistry<Auth, Context> {
|
|
12
|
+
"oauth-provider": {
|
|
13
|
+
creator: typeof oauthProvider;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
}
|
|
11
17
|
/**
|
|
12
18
|
* oAuth 2.1 provider plugin for Better Auth.
|
|
13
19
|
*
|
|
@@ -16,10 +22,8 @@ import * as better_auth0 from "better-auth";
|
|
|
16
22
|
* @returns A Better Auth plugin.
|
|
17
23
|
*/
|
|
18
24
|
declare const oauthProvider: <O extends OAuthOptions<Scope[]>>(options: O) => {
|
|
19
|
-
id: "
|
|
20
|
-
options: O
|
|
21
|
-
claims?: string[];
|
|
22
|
-
};
|
|
25
|
+
id: "oauth-provider";
|
|
26
|
+
options: NoInfer<O>;
|
|
23
27
|
init: (ctx: better_auth0.AuthContext) => void;
|
|
24
28
|
hooks: {
|
|
25
29
|
before: {
|
|
@@ -80,14 +80,14 @@ var TTLCache = class {
|
|
|
80
80
|
* @internal
|
|
81
81
|
*/
|
|
82
82
|
const getOAuthProviderPlugin = (ctx) => {
|
|
83
|
-
return ctx.
|
|
83
|
+
return ctx.getPlugin("oauth-provider");
|
|
84
84
|
};
|
|
85
85
|
/**
|
|
86
86
|
* Gets the JWT Plugin
|
|
87
87
|
* @internal
|
|
88
88
|
*/
|
|
89
89
|
const getJwtPlugin = (ctx) => {
|
|
90
|
-
const plugin = ctx.
|
|
90
|
+
const plugin = ctx.getPlugin("jwt");
|
|
91
91
|
if (!plugin) throw new BetterAuthError("jwt_config", "jwt plugin not found");
|
|
92
92
|
return plugin;
|
|
93
93
|
};
|
|
@@ -256,6 +256,16 @@ async function validateClientCredentials(ctx, options, clientId, clientSecret, s
|
|
|
256
256
|
return client;
|
|
257
257
|
}
|
|
258
258
|
/**
|
|
259
|
+
* Parse client metadata that may be stored as JSON string or already parsed object.
|
|
260
|
+
* Handles database adapters that auto-parse JSON columns.
|
|
261
|
+
*
|
|
262
|
+
* @internal
|
|
263
|
+
*/
|
|
264
|
+
function parseClientMetadata(metadata) {
|
|
265
|
+
if (!metadata) return void 0;
|
|
266
|
+
return typeof metadata === "string" ? JSON.parse(metadata) : metadata;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
259
269
|
* Parse space-separated prompt string into a set of prompts
|
|
260
270
|
*
|
|
261
271
|
* @param prompt
|
|
@@ -283,4 +293,4 @@ function deleteFromPrompt(query, prompt) {
|
|
|
283
293
|
}
|
|
284
294
|
|
|
285
295
|
//#endregion
|
|
286
|
-
export { getJwtPlugin as a,
|
|
296
|
+
export { getJwtPlugin as a, parseClientMetadata as c, storeToken as d, validateClientCredentials as f, getClient as i, parsePrompt as l, mcpHandler as m, decryptStoredClientSecret as n, getOAuthProviderPlugin as o, handleMcpErrors as p, deleteFromPrompt as r, getStoredToken as s, basicToClientCredentials as t, storeClientSecret as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/oauth-provider",
|
|
3
|
-
"version": "1.5.0-beta.
|
|
3
|
+
"version": "1.5.0-beta.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "An oauth provider plugin for Better Auth",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
}
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
42
|
+
"@modelcontextprotocol/sdk": "^1.25.2",
|
|
43
43
|
"listhen": "^1.9.0",
|
|
44
44
|
"tsdown": "^0.17.2",
|
|
45
|
-
"@better-auth/core": "1.5.0-beta.
|
|
46
|
-
"better-auth": "1.5.0-beta.
|
|
45
|
+
"@better-auth/core": "1.5.0-beta.4",
|
|
46
|
+
"better-auth": "1.5.0-beta.4"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"jose": "^6.1.0",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"@better-auth/utils": "0.3.0",
|
|
54
54
|
"@better-fetch/fetch": "1.1.21",
|
|
55
|
-
"better-call": "1.1.
|
|
56
|
-
"@better-auth/core": "1.5.0-beta.
|
|
57
|
-
"better-auth": "1.5.0-beta.
|
|
55
|
+
"better-call": "1.1.8",
|
|
56
|
+
"@better-auth/core": "1.5.0-beta.4",
|
|
57
|
+
"better-auth": "1.5.0-beta.4"
|
|
58
58
|
},
|
|
59
59
|
"files": [
|
|
60
60
|
"dist"
|