@better-auth/oauth-provider 1.5.0-beta.1 → 1.5.0-beta.3
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.d.mts +1 -1
- package/dist/client-resource.mjs +18 -5
- package/dist/client.d.mts +2 -2
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +22 -166
- package/dist/{oauth-Cex7QJsW.d.mts → oauth-BW67CKnu.d.mts} +11 -7
- package/dist/{oauth-kjs13QN6.d.mts → oauth-BrFoF22H.d.mts} +1 -1
- package/dist/{utils-CSiY9oUk.mjs → utils-CAYiYjbw.mjs} +13 -3
- package/package.json +6 -6
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,21 +6,32 @@ 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");
|
|
22
33
|
if (!issuer) throw Error("please define opts.verifyOptions.issuer");
|
|
23
|
-
const jwksUrl = opts?.jwksUrl ?? jwtPluginOptions?.jwks?.remoteUrl ?? (authServerBaseUrl ? `${authServerBaseUrl + (authServerBasePath ?? "")}/jwks` : void 0);
|
|
34
|
+
const jwksUrl = opts?.jwksUrl ?? jwtPluginOptions?.jwks?.remoteUrl ?? (authServerBaseUrl ? `${authServerBaseUrl + (authServerBasePath ?? "")}${jwtPluginOptions?.jwks?.jwksPath ?? "/jwks"}` : void 0);
|
|
24
35
|
const introspectUrl = opts?.remoteVerify?.introspectUrl ?? (authServerBaseUrl ? `${authServerBaseUrl}${authServerBasePath ?? ""}/oauth2/introspect` : void 0);
|
|
25
36
|
try {
|
|
26
37
|
if (!token?.length) throw new APIError("UNAUTHORIZED", { message: "missing authorization header" });
|
|
@@ -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
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./oauth-
|
|
2
|
-
import { t as oauthProvider } from "./oauth-
|
|
1
|
+
import "./oauth-BrFoF22H.mjs";
|
|
2
|
+
import { t as oauthProvider } from "./oauth-BW67CKnu.mjs";
|
|
3
3
|
import * as _better_fetch_fetch0 from "@better-fetch/fetch";
|
|
4
4
|
|
|
5
5
|
//#region src/client.d.ts
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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 { t as oauthProvider } 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-BrFoF22H.mjs";
|
|
2
|
+
import { t as oauthProvider } from "./oauth-BW67CKnu.mjs";
|
|
3
3
|
import { verifyAccessToken } from "better-auth/oauth2";
|
|
4
|
-
import { JWSAlgorithms, JwtOptions } from "better-auth/plugins
|
|
4
|
+
import { JWSAlgorithms, JwtOptions } from "better-auth/plugins";
|
|
5
5
|
import { JWTPayload } from "jose";
|
|
6
6
|
import { GenericEndpointContext } from "@better-auth/core";
|
|
7
7
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
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";
|
|
5
|
-
import { createHash } from "@better-auth/utils/hash";
|
|
6
5
|
import { constantTimeEqual, generateRandomString, makeSignature } from "better-auth/crypto";
|
|
7
6
|
import { defineRequestState } from "@better-auth/core/context";
|
|
8
7
|
import { logger } from "@better-auth/core/env";
|
|
@@ -10,11 +9,8 @@ import { APIError as APIError$1, createAuthEndpoint, createAuthMiddleware, getOA
|
|
|
10
9
|
import { parseSetCookieHeader } from "better-auth/cookies";
|
|
11
10
|
import { mergeSchema } from "better-auth/db";
|
|
12
11
|
import * as z from "zod";
|
|
13
|
-
import { signJWT, toExpJWT } from "better-auth/plugins
|
|
12
|
+
import { signJWT, toExpJWT } from "better-auth/plugins";
|
|
14
13
|
import { SignJWT, compactVerify, createLocalJWKSet, decodeJwt } from "jose";
|
|
15
|
-
import "@better-auth/utils";
|
|
16
|
-
import "@better-auth/utils/hex";
|
|
17
|
-
import { createRandomStringGenerator } from "@better-auth/utils/random";
|
|
18
14
|
|
|
19
15
|
//#region src/metadata.ts
|
|
20
16
|
function authServerMetadata(ctx, opts, overrides) {
|
|
@@ -24,7 +20,7 @@ function authServerMetadata(ctx, opts, overrides) {
|
|
|
24
20
|
issuer: opts?.jwt?.issuer ?? baseURL,
|
|
25
21
|
authorization_endpoint: `${baseURL}/oauth2/authorize`,
|
|
26
22
|
token_endpoint: `${baseURL}/oauth2/token`,
|
|
27
|
-
jwks_uri: overrides?.jwt_disabled ? void 0 : opts?.jwks?.remoteUrl ?? `${baseURL}/jwks`,
|
|
23
|
+
jwks_uri: overrides?.jwt_disabled ? void 0 : opts?.jwks?.remoteUrl ?? `${baseURL}${opts?.jwks?.jwksPath ?? "/jwks"}`,
|
|
28
24
|
registration_endpoint: `${baseURL}/oauth2/register`,
|
|
29
25
|
introspection_endpoint: `${baseURL}/oauth2/introspect`,
|
|
30
26
|
revocation_endpoint: `${baseURL}/oauth2/revoke`,
|
|
@@ -520,7 +516,7 @@ async function createJwtAccessToken(ctx, opts, user, client, audience, scopes, r
|
|
|
520
516
|
scopes,
|
|
521
517
|
resource: ctx.body.resource,
|
|
522
518
|
referenceId,
|
|
523
|
-
metadata:
|
|
519
|
+
metadata: parseClientMetadata(client.metadata)
|
|
524
520
|
}) : {};
|
|
525
521
|
const jwtPluginOptions = getJwtPlugin(ctx.context).options;
|
|
526
522
|
return signJWT(ctx, {
|
|
@@ -551,7 +547,7 @@ async function createIdToken(ctx, opts, user, client, scopes, nonce, sessionId)
|
|
|
551
547
|
const customClaims = opts.customIdTokenClaims ? await opts.customIdTokenClaims({
|
|
552
548
|
user,
|
|
553
549
|
scopes,
|
|
554
|
-
metadata:
|
|
550
|
+
metadata: parseClientMetadata(client.metadata)
|
|
555
551
|
}) : {};
|
|
556
552
|
const jwtPluginOptions = opts.disableJwtPlugin ? void 0 : getJwtPlugin(ctx.context).options;
|
|
557
553
|
const payload = {
|
|
@@ -861,7 +857,7 @@ async function handleClientCredentialsGrant(ctx, opts) {
|
|
|
861
857
|
const customClaims = opts.customAccessTokenClaims ? await opts.customAccessTokenClaims({
|
|
862
858
|
scopes: requestedScopes,
|
|
863
859
|
resource: ctx.body.resource,
|
|
864
|
-
metadata:
|
|
860
|
+
metadata: parseClientMetadata(client.metadata)
|
|
865
861
|
}) : {};
|
|
866
862
|
const accessToken = audience && !opts.disableJwtPlugin ? await signJWT(ctx, {
|
|
867
863
|
options: jwtPluginOptions,
|
|
@@ -1073,7 +1069,7 @@ async function validateOpaqueAccessToken(ctx, opts, token, clientId) {
|
|
|
1073
1069
|
user,
|
|
1074
1070
|
scopes: accessToken.scopes,
|
|
1075
1071
|
referenceId: accessToken?.referenceId,
|
|
1076
|
-
metadata: client?.metadata
|
|
1072
|
+
metadata: parseClientMetadata(client?.metadata)
|
|
1077
1073
|
}) : {};
|
|
1078
1074
|
const jwtPluginOptions = (opts.disableJwtPlugin ? void 0 : getJwtPlugin(ctx.context))?.options;
|
|
1079
1075
|
return {
|
|
@@ -1223,7 +1219,7 @@ async function rpInitiatedLogoutEndpoint(ctx, opts) {
|
|
|
1223
1219
|
const { id_token_hint, client_id, post_logout_redirect_uri, state } = ctx.query;
|
|
1224
1220
|
const baseURL = ctx.context.baseURL;
|
|
1225
1221
|
const jwtPluginOptions = (opts.disableJwtPlugin ? void 0 : getJwtPlugin(ctx.context))?.options;
|
|
1226
|
-
const jwksUrl = jwtPluginOptions?.jwks?.remoteUrl ?? `${baseURL}/jwks`;
|
|
1222
|
+
const jwksUrl = jwtPluginOptions?.jwks?.remoteUrl ?? `${baseURL}${jwtPluginOptions?.jwks?.jwksPath ?? "/jwks"}`;
|
|
1227
1223
|
let clientId = client_id;
|
|
1228
1224
|
if (!clientId) {
|
|
1229
1225
|
let decoded;
|
|
@@ -1323,152 +1319,6 @@ async function rpInitiatedLogoutEndpoint(ctx, opts) {
|
|
|
1323
1319
|
}
|
|
1324
1320
|
}
|
|
1325
1321
|
|
|
1326
|
-
//#endregion
|
|
1327
|
-
//#region ../better-auth/src/crypto/jwt.ts
|
|
1328
|
-
const info = new Uint8Array([
|
|
1329
|
-
66,
|
|
1330
|
-
101,
|
|
1331
|
-
116,
|
|
1332
|
-
116,
|
|
1333
|
-
101,
|
|
1334
|
-
114,
|
|
1335
|
-
65,
|
|
1336
|
-
117,
|
|
1337
|
-
116,
|
|
1338
|
-
104,
|
|
1339
|
-
46,
|
|
1340
|
-
106,
|
|
1341
|
-
115,
|
|
1342
|
-
32,
|
|
1343
|
-
71,
|
|
1344
|
-
101,
|
|
1345
|
-
110,
|
|
1346
|
-
101,
|
|
1347
|
-
114,
|
|
1348
|
-
97,
|
|
1349
|
-
116,
|
|
1350
|
-
101,
|
|
1351
|
-
100,
|
|
1352
|
-
32,
|
|
1353
|
-
69,
|
|
1354
|
-
110,
|
|
1355
|
-
99,
|
|
1356
|
-
114,
|
|
1357
|
-
121,
|
|
1358
|
-
112,
|
|
1359
|
-
116,
|
|
1360
|
-
105,
|
|
1361
|
-
111,
|
|
1362
|
-
110,
|
|
1363
|
-
32,
|
|
1364
|
-
75,
|
|
1365
|
-
101,
|
|
1366
|
-
121
|
|
1367
|
-
]);
|
|
1368
|
-
|
|
1369
|
-
//#endregion
|
|
1370
|
-
//#region ../better-auth/src/crypto/random.ts
|
|
1371
|
-
const generateRandomString$1 = createRandomStringGenerator("a-z", "0-9", "A-Z", "-_");
|
|
1372
|
-
|
|
1373
|
-
//#endregion
|
|
1374
|
-
//#region ../better-auth/src/utils/time.ts
|
|
1375
|
-
const SEC = 1e3;
|
|
1376
|
-
const MIN = SEC * 60;
|
|
1377
|
-
const HOUR = MIN * 60;
|
|
1378
|
-
const DAY = HOUR * 24;
|
|
1379
|
-
const WEEK = DAY * 7;
|
|
1380
|
-
const MONTH = DAY * 30;
|
|
1381
|
-
const YEAR = DAY * 365.25;
|
|
1382
|
-
const REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|months?|mo|years?|yrs?|y)(?: (ago|from now))?$/i;
|
|
1383
|
-
function parse(value) {
|
|
1384
|
-
const match = REGEX.exec(value);
|
|
1385
|
-
if (!match || match[4] && match[1]) throw new TypeError(`Invalid time string format: "${value}". Use formats like "7d", "30m", "1 hour", etc.`);
|
|
1386
|
-
const n = parseFloat(match[2]);
|
|
1387
|
-
const unit = match[3].toLowerCase();
|
|
1388
|
-
let result;
|
|
1389
|
-
switch (unit) {
|
|
1390
|
-
case "years":
|
|
1391
|
-
case "year":
|
|
1392
|
-
case "yrs":
|
|
1393
|
-
case "yr":
|
|
1394
|
-
case "y":
|
|
1395
|
-
result = n * YEAR;
|
|
1396
|
-
break;
|
|
1397
|
-
case "months":
|
|
1398
|
-
case "month":
|
|
1399
|
-
case "mo":
|
|
1400
|
-
result = n * MONTH;
|
|
1401
|
-
break;
|
|
1402
|
-
case "weeks":
|
|
1403
|
-
case "week":
|
|
1404
|
-
case "w":
|
|
1405
|
-
result = n * WEEK;
|
|
1406
|
-
break;
|
|
1407
|
-
case "days":
|
|
1408
|
-
case "day":
|
|
1409
|
-
case "d":
|
|
1410
|
-
result = n * DAY;
|
|
1411
|
-
break;
|
|
1412
|
-
case "hours":
|
|
1413
|
-
case "hour":
|
|
1414
|
-
case "hrs":
|
|
1415
|
-
case "hr":
|
|
1416
|
-
case "h":
|
|
1417
|
-
result = n * HOUR;
|
|
1418
|
-
break;
|
|
1419
|
-
case "minutes":
|
|
1420
|
-
case "minute":
|
|
1421
|
-
case "mins":
|
|
1422
|
-
case "min":
|
|
1423
|
-
case "m":
|
|
1424
|
-
result = n * MIN;
|
|
1425
|
-
break;
|
|
1426
|
-
case "seconds":
|
|
1427
|
-
case "second":
|
|
1428
|
-
case "secs":
|
|
1429
|
-
case "sec":
|
|
1430
|
-
case "s":
|
|
1431
|
-
result = n * SEC;
|
|
1432
|
-
break;
|
|
1433
|
-
default: throw new TypeError(`Unknown time unit: "${unit}"`);
|
|
1434
|
-
}
|
|
1435
|
-
if (match[1] === "-" || match[4] === "ago") return -result;
|
|
1436
|
-
return result;
|
|
1437
|
-
}
|
|
1438
|
-
/**
|
|
1439
|
-
* Parse a time string and return the value in seconds.
|
|
1440
|
-
*
|
|
1441
|
-
* @param value - A time string like "7d", "30m", "1 hour", "2 hours ago"
|
|
1442
|
-
* @returns The parsed value in seconds (rounded)
|
|
1443
|
-
* @throws TypeError if the string format is invalid
|
|
1444
|
-
*
|
|
1445
|
-
* @example
|
|
1446
|
-
* sec("1d") // 86400
|
|
1447
|
-
* sec("2 hours") // 7200
|
|
1448
|
-
* sec("-30s") // -30
|
|
1449
|
-
* sec("2 hours ago") // -7200
|
|
1450
|
-
*/
|
|
1451
|
-
function sec(value) {
|
|
1452
|
-
return Math.round(parse(value) / 1e3);
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
//#endregion
|
|
1456
|
-
//#region ../better-auth/src/plugins/jwt/utils.ts
|
|
1457
|
-
/**
|
|
1458
|
-
* Converts an expirationTime to ISO seconds expiration time (the format of JWT exp)
|
|
1459
|
-
*
|
|
1460
|
-
* See https://github.com/panva/jose/blob/main/src/lib/jwt_claims_set.ts#L245
|
|
1461
|
-
*
|
|
1462
|
-
* @param expirationTime - see options.jwt.expirationTime
|
|
1463
|
-
* @param iat - the iat time to consolidate on
|
|
1464
|
-
* @returns
|
|
1465
|
-
*/
|
|
1466
|
-
function toExpJWT$1(expirationTime, iat) {
|
|
1467
|
-
if (typeof expirationTime === "number") return expirationTime;
|
|
1468
|
-
else if (expirationTime instanceof Date) return Math.floor(expirationTime.getTime() / 1e3);
|
|
1469
|
-
else return iat + sec(expirationTime);
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
1322
|
//#endregion
|
|
1473
1323
|
//#region src/register.ts
|
|
1474
1324
|
async function registerEndpoint(ctx, opts) {
|
|
@@ -1540,7 +1390,7 @@ async function createOAuthClientEndpoint(ctx, opts, settings) {
|
|
|
1540
1390
|
disabled: void 0,
|
|
1541
1391
|
jwks: void 0,
|
|
1542
1392
|
jwks_uri: void 0,
|
|
1543
|
-
client_secret_expires_at: storedClientSecret ? settings.isRegister && opts?.clientRegistrationClientSecretExpiration ? toExpJWT
|
|
1393
|
+
client_secret_expires_at: storedClientSecret ? settings.isRegister && opts?.clientRegistrationClientSecretExpiration ? toExpJWT(opts.clientRegistrationClientSecretExpiration, iat) : 0 : void 0,
|
|
1544
1394
|
client_id: clientId,
|
|
1545
1395
|
client_secret: storedClientSecret,
|
|
1546
1396
|
client_id_issued_at: iat,
|
|
@@ -1570,14 +1420,19 @@ async function createOAuthClientEndpoint(ctx, opts, settings) {
|
|
|
1570
1420
|
* @returns
|
|
1571
1421
|
*/
|
|
1572
1422
|
function oauthToSchema(input) {
|
|
1573
|
-
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;
|
|
1574
1424
|
const expiresAt = _expiresAt ? /* @__PURE__ */ new Date(_expiresAt * 1e3) : void 0;
|
|
1575
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
|
+
};
|
|
1576
1431
|
return {
|
|
1577
1432
|
clientId,
|
|
1578
1433
|
clientSecret,
|
|
1579
1434
|
disabled,
|
|
1580
|
-
scopes
|
|
1435
|
+
scopes,
|
|
1581
1436
|
userId,
|
|
1582
1437
|
createdAt,
|
|
1583
1438
|
expiresAt,
|
|
@@ -1600,7 +1455,7 @@ function oauthToSchema(input) {
|
|
|
1600
1455
|
skipConsent,
|
|
1601
1456
|
enableEndSession,
|
|
1602
1457
|
referenceId,
|
|
1603
|
-
metadata:
|
|
1458
|
+
metadata: Object.keys(metadataObj).length ? JSON.stringify(metadataObj) : void 0
|
|
1604
1459
|
};
|
|
1605
1460
|
}
|
|
1606
1461
|
/**
|
|
@@ -1615,7 +1470,7 @@ function schemaToOAuth(input) {
|
|
|
1615
1470
|
const _createdAt = createdAt ? Math.round(createdAt.getTime() / 1e3) : void 0;
|
|
1616
1471
|
const _scopes = scopes?.join(" ");
|
|
1617
1472
|
return {
|
|
1618
|
-
...
|
|
1473
|
+
...parseClientMetadata(metadata),
|
|
1619
1474
|
client_id: clientId,
|
|
1620
1475
|
client_secret: clientSecret ?? void 0,
|
|
1621
1476
|
client_secret_expires_at: clientSecret ? _expiresAt ?? 0 : void 0,
|
|
@@ -3007,11 +2862,12 @@ const oauthProvider = (options) => {
|
|
|
3007
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");
|
|
3008
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");
|
|
3009
2864
|
return {
|
|
3010
|
-
id: "
|
|
2865
|
+
id: "oauth-provider",
|
|
3011
2866
|
options: opts,
|
|
3012
2867
|
init: (ctx) => {
|
|
2868
|
+
if (ctx.options.session && !ctx.options.session.storeSessionInDatabase) throw new BetterAuthError("OAuth Provider requires `session.storeSessionInDatabase: true` when using secondaryStorage");
|
|
3013
2869
|
if (!opts.disableJwtPlugin) {
|
|
3014
|
-
const issuer = getJwtPlugin(ctx)
|
|
2870
|
+
const issuer = (getJwtPlugin(ctx)?.options)?.jwt?.issuer ?? ctx.baseURL;
|
|
3015
2871
|
const issuerPath = new URL(issuer).pathname;
|
|
3016
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.`);
|
|
3017
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.`);
|
|
@@ -3064,7 +2920,7 @@ const oauthProvider = (options) => {
|
|
|
3064
2920
|
metadata: { SERVER_ONLY: true }
|
|
3065
2921
|
}, async (ctx) => {
|
|
3066
2922
|
if (opts.scopes && opts.scopes.includes("openid")) return oidcServerMetadata(ctx, opts);
|
|
3067
|
-
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 });
|
|
3068
2924
|
}),
|
|
3069
2925
|
getOpenIdConfig: createAuthEndpoint("/.well-known/openid-configuration", {
|
|
3070
2926
|
method: "GET",
|
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import { c as OAuthConsent, i as OIDCMetadata, m as Scope, r as OAuthClient, t as AuthServerMetadata, u as OAuthOptions } from "./oauth-
|
|
1
|
+
import { c as OAuthConsent, i as OIDCMetadata, m as Scope, r as OAuthClient, t as AuthServerMetadata, u as OAuthOptions } from "./oauth-BrFoF22H.mjs";
|
|
2
2
|
import * as better_call0 from "better-call";
|
|
3
3
|
import "@better-auth/core/context";
|
|
4
4
|
import * as z from "zod";
|
|
5
|
+
import * as better_auth_plugins0 from "better-auth/plugins";
|
|
5
6
|
import * as jose0 from "jose";
|
|
6
7
|
import * as better_auth0 from "better-auth";
|
|
7
|
-
import * as better_auth_plugins0 from "better-auth/plugins";
|
|
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_auth_plugins0 from "better-auth/plugins";
|
|
|
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: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { JWSAlgorithms } from "better-auth/plugins
|
|
1
|
+
import { JWSAlgorithms } from "better-auth/plugins";
|
|
2
2
|
import { JWTPayload } from "jose";
|
|
3
3
|
import { InferOptionSchema, Session, User } from "better-auth/types";
|
|
4
4
|
import { LiteralString } from "@better-auth/core";
|
|
@@ -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.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "An oauth provider plugin for Better Auth",
|
|
6
6
|
"main": "dist/index.mjs",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
"@modelcontextprotocol/sdk": "^1.24.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.3",
|
|
46
|
+
"better-auth": "1.5.0-beta.3"
|
|
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.3",
|
|
57
|
+
"better-auth": "1.5.0-beta.3"
|
|
58
58
|
},
|
|
59
59
|
"files": [
|
|
60
60
|
"dist"
|