@better-auth/core 1.7.0-beta.6 → 1.7.0-beta.8
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/api/index.d.mts +3 -3
- package/dist/context/global.mjs +1 -1
- package/dist/db/get-tables.mjs +3 -3
- package/dist/db/schema/account.d.mts +1 -1
- package/dist/db/schema/account.mjs +1 -1
- package/dist/error/codes.d.mts +0 -5
- package/dist/error/codes.mjs +0 -5
- package/dist/instrumentation/tracer.mjs +1 -1
- package/dist/oauth2/create-authorization-url.d.mts +4 -5
- package/dist/oauth2/create-authorization-url.mjs +4 -5
- package/dist/oauth2/index.d.mts +3 -4
- package/dist/oauth2/index.mjs +2 -3
- package/dist/oauth2/oauth-provider.d.mts +44 -48
- package/dist/oauth2/refresh-access-token.mjs +17 -2
- package/dist/oauth2/utils.d.mts +6 -1
- package/dist/oauth2/utils.mjs +24 -2
- package/dist/oauth2/verify-id-token.d.mts +6 -5
- package/dist/oauth2/verify-id-token.mjs +2 -2
- package/dist/social-providers/apple.d.mts +3 -5
- package/dist/social-providers/apple.mjs +5 -5
- package/dist/social-providers/atlassian.d.mts +3 -5
- package/dist/social-providers/atlassian.mjs +4 -4
- package/dist/social-providers/cognito.d.mts +3 -5
- package/dist/social-providers/cognito.mjs +11 -18
- package/dist/social-providers/discord.d.mts +3 -5
- package/dist/social-providers/discord.mjs +6 -7
- package/dist/social-providers/dropbox.d.mts +3 -5
- package/dist/social-providers/dropbox.mjs +5 -5
- package/dist/social-providers/facebook.d.mts +3 -5
- package/dist/social-providers/facebook.mjs +5 -5
- package/dist/social-providers/figma.d.mts +3 -5
- package/dist/social-providers/figma.mjs +5 -5
- package/dist/social-providers/github.d.mts +3 -5
- package/dist/social-providers/github.mjs +4 -4
- package/dist/social-providers/gitlab.d.mts +3 -5
- package/dist/social-providers/gitlab.mjs +6 -6
- package/dist/social-providers/google.d.mts +10 -10
- package/dist/social-providers/google.mjs +12 -13
- package/dist/social-providers/huggingface.d.mts +3 -5
- package/dist/social-providers/huggingface.mjs +8 -8
- package/dist/social-providers/index.d.mts +105 -177
- package/dist/social-providers/kakao.d.mts +3 -5
- package/dist/social-providers/kakao.mjs +8 -8
- package/dist/social-providers/kick.d.mts +3 -5
- package/dist/social-providers/kick.mjs +4 -4
- package/dist/social-providers/line.d.mts +3 -5
- package/dist/social-providers/line.mjs +10 -10
- package/dist/social-providers/linear.d.mts +3 -5
- package/dist/social-providers/linear.mjs +4 -4
- package/dist/social-providers/linkedin.d.mts +3 -5
- package/dist/social-providers/linkedin.mjs +10 -10
- package/dist/social-providers/microsoft-entra-id.d.mts +3 -5
- package/dist/social-providers/microsoft-entra-id.mjs +10 -11
- package/dist/social-providers/naver.d.mts +3 -5
- package/dist/social-providers/naver.mjs +4 -4
- package/dist/social-providers/notion.d.mts +3 -5
- package/dist/social-providers/notion.mjs +4 -4
- package/dist/social-providers/paybin.d.mts +3 -5
- package/dist/social-providers/paybin.mjs +10 -10
- package/dist/social-providers/paypal.d.mts +3 -5
- package/dist/social-providers/paypal.mjs +2 -8
- package/dist/social-providers/polar.d.mts +3 -5
- package/dist/social-providers/polar.mjs +8 -8
- package/dist/social-providers/railway.d.mts +3 -5
- package/dist/social-providers/railway.mjs +9 -9
- package/dist/social-providers/reddit.d.mts +3 -5
- package/dist/social-providers/reddit.mjs +5 -5
- package/dist/social-providers/roblox.d.mts +3 -5
- package/dist/social-providers/roblox.mjs +5 -5
- package/dist/social-providers/salesforce.d.mts +3 -5
- package/dist/social-providers/salesforce.mjs +8 -8
- package/dist/social-providers/slack.d.mts +3 -5
- package/dist/social-providers/slack.mjs +9 -9
- package/dist/social-providers/spotify.d.mts +3 -5
- package/dist/social-providers/spotify.mjs +5 -5
- package/dist/social-providers/tiktok.d.mts +3 -5
- package/dist/social-providers/tiktok.mjs +5 -9
- package/dist/social-providers/twitch.d.mts +3 -5
- package/dist/social-providers/twitch.mjs +4 -4
- package/dist/social-providers/twitter.d.mts +3 -5
- package/dist/social-providers/twitter.mjs +9 -9
- package/dist/social-providers/vercel.d.mts +3 -5
- package/dist/social-providers/vercel.mjs +7 -4
- package/dist/social-providers/vk.d.mts +3 -5
- package/dist/social-providers/vk.mjs +5 -5
- package/dist/social-providers/wechat.d.mts +3 -5
- package/dist/social-providers/wechat.mjs +5 -9
- package/dist/social-providers/zoom.d.mts +3 -6
- package/dist/social-providers/zoom.mjs +9 -15
- package/dist/types/context.d.mts +6 -2
- package/dist/utils/host.d.mts +1 -1
- package/dist/utils/host.mjs +3 -0
- package/package.json +1 -1
- package/src/db/get-tables.ts +3 -8
- package/src/db/schema/account.ts +5 -14
- package/src/error/codes.ts +0 -5
- package/src/oauth2/create-authorization-url.ts +5 -1
- package/src/oauth2/index.ts +3 -12
- package/src/oauth2/oauth-provider.ts +46 -53
- package/src/oauth2/refresh-access-token.ts +30 -5
- package/src/oauth2/utils.ts +39 -1
- package/src/oauth2/verify-id-token.ts +9 -5
- package/src/social-providers/apple.ts +8 -13
- package/src/social-providers/atlassian.ts +8 -12
- package/src/social-providers/cognito.ts +11 -18
- package/src/social-providers/discord.ts +8 -19
- package/src/social-providers/dropbox.ts +7 -13
- package/src/social-providers/facebook.ts +9 -13
- package/src/social-providers/figma.ts +9 -13
- package/src/social-providers/github.ts +8 -12
- package/src/social-providers/gitlab.ts +8 -14
- package/src/social-providers/google.ts +23 -29
- package/src/social-providers/huggingface.ts +8 -12
- package/src/social-providers/kakao.ts +8 -16
- package/src/social-providers/kick.ts +7 -12
- package/src/social-providers/line.ts +10 -14
- package/src/social-providers/linear.ts +6 -12
- package/src/social-providers/linkedin.ts +10 -14
- package/src/social-providers/microsoft-entra-id.ts +8 -18
- package/src/social-providers/naver.ts +6 -12
- package/src/social-providers/notion.ts +6 -12
- package/src/social-providers/paybin.ts +11 -14
- package/src/social-providers/paypal.ts +8 -6
- package/src/social-providers/polar.ts +8 -12
- package/src/social-providers/railway.ts +9 -13
- package/src/social-providers/reddit.ts +7 -18
- package/src/social-providers/roblox.ts +7 -18
- package/src/social-providers/salesforce.ts +8 -12
- package/src/social-providers/slack.ts +9 -18
- package/src/social-providers/spotify.ts +7 -13
- package/src/social-providers/tiktok.ts +7 -13
- package/src/social-providers/twitch.ts +8 -12
- package/src/social-providers/twitter.ts +8 -17
- package/src/social-providers/vercel.ts +10 -16
- package/src/social-providers/vk.ts +7 -13
- package/src/social-providers/wechat.ts +8 -20
- package/src/social-providers/zoom.ts +6 -19
- package/src/types/context.ts +8 -2
- package/src/utils/host.ts +10 -1
- package/dist/oauth2/scopes.d.mts +0 -76
- package/dist/oauth2/scopes.mjs +0 -96
- package/src/oauth2/scopes.ts +0 -118
package/dist/api/index.d.mts
CHANGED
|
@@ -2,7 +2,7 @@ import { BetterAuthDBSchema, ModelNames, SecondaryStorage } from "../db/type.mjs
|
|
|
2
2
|
import { DBAdapter } from "../db/adapter/index.mjs";
|
|
3
3
|
import { createLogger } from "../env/logger.mjs";
|
|
4
4
|
import { AuthContext } from "../types/context.mjs";
|
|
5
|
-
import {
|
|
5
|
+
import { OAuthProvider } from "../oauth2/oauth-provider.mjs";
|
|
6
6
|
import * as better_call0 from "better-call";
|
|
7
7
|
import { EndpointContext, EndpointOptions, StrictEndpoint } from "better-call";
|
|
8
8
|
import * as _better_auth_core0 from "@better-auth/core";
|
|
@@ -105,7 +105,7 @@ declare const createAuthMiddleware: {
|
|
|
105
105
|
image?: string | null | undefined;
|
|
106
106
|
} & Record<string, any>;
|
|
107
107
|
} | null) => void;
|
|
108
|
-
socialProviders:
|
|
108
|
+
socialProviders: OAuthProvider[];
|
|
109
109
|
authCookies: _better_auth_core0.BetterAuthCookies;
|
|
110
110
|
logger: ReturnType<typeof createLogger>;
|
|
111
111
|
rateLimit: {
|
|
@@ -234,7 +234,7 @@ declare const createAuthMiddleware: {
|
|
|
234
234
|
image?: string | null | undefined;
|
|
235
235
|
} & Record<string, any>;
|
|
236
236
|
} | null) => void;
|
|
237
|
-
socialProviders:
|
|
237
|
+
socialProviders: OAuthProvider[];
|
|
238
238
|
authCookies: _better_auth_core0.BetterAuthCookies;
|
|
239
239
|
logger: ReturnType<typeof createLogger>;
|
|
240
240
|
rateLimit: {
|
package/dist/context/global.mjs
CHANGED
package/dist/db/get-tables.mjs
CHANGED
|
@@ -228,10 +228,10 @@ const getAuthTables = (options) => {
|
|
|
228
228
|
returned: false,
|
|
229
229
|
fieldName: options.account?.fields?.refreshTokenExpiresAt || "refreshTokenExpiresAt"
|
|
230
230
|
},
|
|
231
|
-
|
|
232
|
-
type: "string
|
|
231
|
+
scope: {
|
|
232
|
+
type: "string",
|
|
233
233
|
required: false,
|
|
234
|
-
fieldName: options.account?.fields?.
|
|
234
|
+
fieldName: options.account?.fields?.scope || "scope"
|
|
235
235
|
},
|
|
236
236
|
password: {
|
|
237
237
|
type: "string",
|
|
@@ -16,7 +16,7 @@ declare const accountSchema: z.ZodObject<{
|
|
|
16
16
|
idToken: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
17
17
|
accessTokenExpiresAt: z.ZodOptional<z.ZodNullable<z.ZodDate>>;
|
|
18
18
|
refreshTokenExpiresAt: z.ZodOptional<z.ZodNullable<z.ZodDate>>;
|
|
19
|
-
|
|
19
|
+
scope: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
20
20
|
password: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
21
21
|
}, z.core.$strip>;
|
|
22
22
|
type BaseAccount = z.infer<typeof accountSchema>;
|
|
@@ -10,7 +10,7 @@ const accountSchema = coreSchema.extend({
|
|
|
10
10
|
idToken: z.string().nullish(),
|
|
11
11
|
accessTokenExpiresAt: z.date().nullish(),
|
|
12
12
|
refreshTokenExpiresAt: z.date().nullish(),
|
|
13
|
-
|
|
13
|
+
scope: z.string().nullish(),
|
|
14
14
|
password: z.string().nullish()
|
|
15
15
|
});
|
|
16
16
|
//#endregion
|
package/dist/error/codes.d.mts
CHANGED
|
@@ -29,11 +29,6 @@ declare const BASE_ERROR_CODES: {
|
|
|
29
29
|
TOKEN_EXPIRED: RawError<"TOKEN_EXPIRED">;
|
|
30
30
|
ID_TOKEN_NOT_SUPPORTED: RawError<"ID_TOKEN_NOT_SUPPORTED">;
|
|
31
31
|
FAILED_TO_GET_USER_INFO: RawError<"FAILED_TO_GET_USER_INFO">;
|
|
32
|
-
PROVIDER_NOT_SUPPORTED: RawError<"PROVIDER_NOT_SUPPORTED">;
|
|
33
|
-
TOKEN_REFRESH_NOT_SUPPORTED: RawError<"TOKEN_REFRESH_NOT_SUPPORTED">;
|
|
34
|
-
REFRESH_TOKEN_NOT_FOUND: RawError<"REFRESH_TOKEN_NOT_FOUND">;
|
|
35
|
-
FAILED_TO_GET_ACCESS_TOKEN: RawError<"FAILED_TO_GET_ACCESS_TOKEN">;
|
|
36
|
-
FAILED_TO_REFRESH_ACCESS_TOKEN: RawError<"FAILED_TO_REFRESH_ACCESS_TOKEN">;
|
|
37
32
|
USER_EMAIL_NOT_FOUND: RawError<"USER_EMAIL_NOT_FOUND">;
|
|
38
33
|
EMAIL_NOT_VERIFIED: RawError<"EMAIL_NOT_VERIFIED">;
|
|
39
34
|
PASSWORD_TOO_SHORT: RawError<"PASSWORD_TOO_SHORT">;
|
package/dist/error/codes.mjs
CHANGED
|
@@ -16,11 +16,6 @@ const BASE_ERROR_CODES = defineErrorCodes({
|
|
|
16
16
|
TOKEN_EXPIRED: "Token expired",
|
|
17
17
|
ID_TOKEN_NOT_SUPPORTED: "id_token not supported",
|
|
18
18
|
FAILED_TO_GET_USER_INFO: "Failed to get user info",
|
|
19
|
-
PROVIDER_NOT_SUPPORTED: "Provider not supported",
|
|
20
|
-
TOKEN_REFRESH_NOT_SUPPORTED: "Token refresh not supported",
|
|
21
|
-
REFRESH_TOKEN_NOT_FOUND: "Refresh token not found",
|
|
22
|
-
FAILED_TO_GET_ACCESS_TOKEN: "Failed to get a valid access token",
|
|
23
|
-
FAILED_TO_REFRESH_ACCESS_TOKEN: "Failed to refresh access token",
|
|
24
19
|
USER_EMAIL_NOT_FOUND: "User email not found",
|
|
25
20
|
EMAIL_NOT_VERIFIED: "Email not verified",
|
|
26
21
|
PASSWORD_TOO_SHORT: "Password too short",
|
|
@@ -2,7 +2,7 @@ import { ATTR_HTTP_RESPONSE_STATUS_CODE } from "./attributes.mjs";
|
|
|
2
2
|
import { getOpenTelemetryAPI } from "./api.mjs";
|
|
3
3
|
//#region src/instrumentation/tracer.ts
|
|
4
4
|
const INSTRUMENTATION_SCOPE = "better-auth";
|
|
5
|
-
const INSTRUMENTATION_VERSION = "1.7.0-beta.
|
|
5
|
+
const INSTRUMENTATION_VERSION = "1.7.0-beta.8";
|
|
6
6
|
/**
|
|
7
7
|
* Better-auth uses `throw ctx.redirect(url)` for flow control (e.g. OAuth
|
|
8
8
|
* callbacks). These are APIErrors with 3xx status codes and should not be
|
|
@@ -7,7 +7,7 @@ import { ProviderOptions } from "./oauth-provider.mjs";
|
|
|
7
7
|
* `additionalParams`. Overriding `state`, PKCE, or `redirect_uri` would
|
|
8
8
|
* break the callback correlation and session pinning guarantees.
|
|
9
9
|
*/
|
|
10
|
-
declare const RESERVED_AUTHORIZATION_PARAMS: readonly ["state", "client_id", "redirect_uri", "response_type", "code_challenge", "code_challenge_method", "scope"];
|
|
10
|
+
declare const RESERVED_AUTHORIZATION_PARAMS: readonly ["state", "client_id", "redirect_uri", "response_type", "code_challenge", "code_challenge_method", "nonce", "scope"];
|
|
11
11
|
declare const RESERVED_AUTHORIZATION_PARAMS_SET: ReadonlySet<string>;
|
|
12
12
|
declare function createAuthorizationURL({
|
|
13
13
|
id,
|
|
@@ -24,6 +24,7 @@ declare function createAuthorizationURL({
|
|
|
24
24
|
responseType,
|
|
25
25
|
display,
|
|
26
26
|
loginHint,
|
|
27
|
+
nonce,
|
|
27
28
|
hd,
|
|
28
29
|
responseMode,
|
|
29
30
|
additionalParams,
|
|
@@ -43,13 +44,11 @@ declare function createAuthorizationURL({
|
|
|
43
44
|
responseType?: string | undefined;
|
|
44
45
|
display?: string | undefined;
|
|
45
46
|
loginHint?: string | undefined;
|
|
47
|
+
nonce?: string | undefined;
|
|
46
48
|
hd?: string | undefined;
|
|
47
49
|
responseMode?: string | undefined;
|
|
48
50
|
additionalParams?: Record<string, string> | undefined;
|
|
49
51
|
scopeJoiner?: string | undefined;
|
|
50
|
-
}): Promise<
|
|
51
|
-
url: URL;
|
|
52
|
-
requestedScopes: string[];
|
|
53
|
-
}>;
|
|
52
|
+
}): Promise<URL>;
|
|
54
53
|
//#endregion
|
|
55
54
|
export { RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, createAuthorizationURL };
|
|
@@ -13,10 +13,11 @@ const RESERVED_AUTHORIZATION_PARAMS = [
|
|
|
13
13
|
"response_type",
|
|
14
14
|
"code_challenge",
|
|
15
15
|
"code_challenge_method",
|
|
16
|
+
"nonce",
|
|
16
17
|
"scope"
|
|
17
18
|
];
|
|
18
19
|
const RESERVED_AUTHORIZATION_PARAMS_SET = new Set(RESERVED_AUTHORIZATION_PARAMS);
|
|
19
|
-
async function createAuthorizationURL({ id, options, authorizationEndpoint, state, codeVerifier, scopes, claims, redirectURI, duration, prompt, accessType, responseType, display, loginHint, hd, responseMode, additionalParams, scopeJoiner }) {
|
|
20
|
+
async function createAuthorizationURL({ id, options, authorizationEndpoint, state, codeVerifier, scopes, claims, redirectURI, duration, prompt, accessType, responseType, display, loginHint, nonce, hd, responseMode, additionalParams, scopeJoiner }) {
|
|
20
21
|
options = typeof options === "function" ? await options() : options;
|
|
21
22
|
const url = new URL(options.authorizationEndpoint || authorizationEndpoint);
|
|
22
23
|
url.searchParams.set("response_type", responseType || "code");
|
|
@@ -29,6 +30,7 @@ async function createAuthorizationURL({ id, options, authorizationEndpoint, stat
|
|
|
29
30
|
duration && url.searchParams.set("duration", duration);
|
|
30
31
|
display && url.searchParams.set("display", display);
|
|
31
32
|
loginHint && url.searchParams.set("login_hint", loginHint);
|
|
33
|
+
nonce && url.searchParams.set("nonce", nonce);
|
|
32
34
|
prompt && url.searchParams.set("prompt", prompt);
|
|
33
35
|
hd && url.searchParams.set("hd", hd);
|
|
34
36
|
accessType && url.searchParams.set("access_type", accessType);
|
|
@@ -53,10 +55,7 @@ async function createAuthorizationURL({ id, options, authorizationEndpoint, stat
|
|
|
53
55
|
if (RESERVED_AUTHORIZATION_PARAMS_SET.has(key)) continue;
|
|
54
56
|
url.searchParams.set(key, value);
|
|
55
57
|
}
|
|
56
|
-
return
|
|
57
|
-
url,
|
|
58
|
-
requestedScopes: scopes ?? []
|
|
59
|
-
};
|
|
58
|
+
return url;
|
|
60
59
|
}
|
|
61
60
|
//#endregion
|
|
62
61
|
export { RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, createAuthorizationURL };
|
package/dist/oauth2/index.d.mts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { additionalAuthorizationParamsSchema } from "./authorization-params.mjs";
|
|
2
2
|
import { decodeBasicCredentials, encodeBasicCredentials } from "./basic-credentials.mjs";
|
|
3
3
|
import { CLIENT_ASSERTION_TYPE, ClientAssertionContext, ClientAssertionGetter, ClientAssertionGrantType, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS, PrivateKeyJwtClientAssertionGetterOptions, PrivateKeyJwtSigningAlgorithm, createPrivateKeyJwtClientAssertionGetter, resolveClientAssertionParams, signPrivateKeyJwtClientAssertion } from "./client-assertion.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { OAuth2Tokens, OAuth2UserInfo, OAuthIdTokenConfig, OAuthProvider, OAuthRefreshContext, ProviderOptions } from "./oauth-provider.mjs";
|
|
5
5
|
import { TokenEndpointAuth, TokenEndpointAuthMethod, TokenEndpointSecretAuthentication } from "./token-endpoint-auth.mjs";
|
|
6
6
|
import { clientCredentialsToken, clientCredentialsTokenRequest } from "./client-credentials-token.mjs";
|
|
7
7
|
import { RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, createAuthorizationURL } from "./create-authorization-url.mjs";
|
|
8
8
|
import { AccessTokenAuthorization, AccessTokenAuthorizationScheme, BEARER_AUTHORIZATION_SCHEME, DPOP_AUTHORIZATION_SCHEME, DPOP_PROOF_TYPE, DPOP_SIGNING_ALGORITHMS, DpopBindingError, DpopBindingErrorCode, DpopProofError, DpopProofErrorCode, DpopReplayReservation, DpopReplayReservations, DpopReplayStore, DpopSigningAlgorithm, EnforceDpopBindingParams, VerifiedDpopProof, VerifyDpopProofOptions, createDpopBindingError, createDpopProofError, createDpopReplayStore, createInMemoryDpopReplayStore, deriveDpopAth, deriveDpopJkt, enforceDpopBinding, getConfirmationJkt, getDpopJktFromPayload, isDpopBindingError, isDpopProofError, normalizeDpopHtu, parseAccessTokenAuthorization, stripAccessTokenAuthorizationScheme, verifyDpopProof } from "./dpop.mjs";
|
|
9
9
|
import { refreshAccessToken, refreshAccessTokenRequest } from "./refresh-access-token.mjs";
|
|
10
|
-
import {
|
|
11
|
-
import { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId } from "./utils.mjs";
|
|
10
|
+
import { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId, mergeScopes } from "./utils.mjs";
|
|
12
11
|
import { authorizationCodeRequest, validateAuthorizationCode, validateToken } from "./validate-authorization-code.mjs";
|
|
13
12
|
import { ResourceRequestInput, VerifyAccessTokenOptions, VerifyAccessTokenRequestOptions, getJwks, requestToResourceInput, verifyAccessTokenRequest, verifyBearerToken, verifyJwsAccessToken } from "./verify.mjs";
|
|
14
13
|
import { supportsIdTokenSignIn, verifyProviderIdToken } from "./verify-id-token.mjs";
|
|
15
|
-
export { type AccessTokenAuthorization, type AccessTokenAuthorizationScheme,
|
|
14
|
+
export { type AccessTokenAuthorization, type AccessTokenAuthorizationScheme, BEARER_AUTHORIZATION_SCHEME, CLIENT_ASSERTION_TYPE, type ClientAssertionContext, type ClientAssertionGetter, type ClientAssertionGrantType, DPOP_AUTHORIZATION_SCHEME, DPOP_PROOF_TYPE, DPOP_SIGNING_ALGORITHMS, type DpopBindingError, type DpopBindingErrorCode, type DpopProofError, type DpopProofErrorCode, type DpopReplayReservation, type DpopReplayReservations, type DpopReplayStore, type DpopSigningAlgorithm, type EnforceDpopBindingParams, type OAuth2Tokens, type OAuth2UserInfo, type OAuthIdTokenConfig, type OAuthProvider, type OAuthRefreshContext, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS, type PrivateKeyJwtClientAssertionGetterOptions, type PrivateKeyJwtSigningAlgorithm, type ProviderOptions, RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, type ResourceRequestInput, type TokenEndpointAuth, type TokenEndpointAuthMethod, type TokenEndpointSecretAuthentication, type VerifiedDpopProof, type VerifyAccessTokenOptions, type VerifyAccessTokenRequestOptions, type VerifyDpopProofOptions, additionalAuthorizationParamsSchema, applyDefaultAccessTokenExpiry, authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationURL, createDpopBindingError, createDpopProofError, createDpopReplayStore, createInMemoryDpopReplayStore, createPrivateKeyJwtClientAssertionGetter, decodeBasicCredentials, deriveDpopAth, deriveDpopJkt, encodeBasicCredentials, enforceDpopBinding, generateCodeChallenge, getConfirmationJkt, getDpopJktFromPayload, getJwks, getOAuth2Tokens, getPrimaryClientId, isDpopBindingError, isDpopProofError, mergeScopes, normalizeDpopHtu, parseAccessTokenAuthorization, refreshAccessToken, refreshAccessTokenRequest, requestToResourceInput, resolveClientAssertionParams, signPrivateKeyJwtClientAssertion, stripAccessTokenAuthorizationScheme, supportsIdTokenSignIn, validateAuthorizationCode, validateToken, verifyAccessTokenRequest, verifyBearerToken, verifyDpopProof, verifyJwsAccessToken, verifyProviderIdToken };
|
package/dist/oauth2/index.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId } from "./utils.mjs";
|
|
1
|
+
import { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId, mergeScopes } from "./utils.mjs";
|
|
3
2
|
import { RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, createAuthorizationURL } from "./create-authorization-url.mjs";
|
|
4
3
|
import { additionalAuthorizationParamsSchema } from "./authorization-params.mjs";
|
|
5
4
|
import { decodeBasicCredentials, encodeBasicCredentials } from "./basic-credentials.mjs";
|
|
@@ -10,4 +9,4 @@ import { refreshAccessToken, refreshAccessTokenRequest } from "./refresh-access-
|
|
|
10
9
|
import { authorizationCodeRequest, validateAuthorizationCode, validateToken } from "./validate-authorization-code.mjs";
|
|
11
10
|
import { getJwks, requestToResourceInput, verifyAccessTokenRequest, verifyBearerToken, verifyJwsAccessToken } from "./verify.mjs";
|
|
12
11
|
import { supportsIdTokenSignIn, verifyProviderIdToken } from "./verify-id-token.mjs";
|
|
13
|
-
export { BEARER_AUTHORIZATION_SCHEME, CLIENT_ASSERTION_TYPE, DPOP_AUTHORIZATION_SCHEME, DPOP_PROOF_TYPE, DPOP_SIGNING_ALGORITHMS, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS, RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, additionalAuthorizationParamsSchema, applyDefaultAccessTokenExpiry, authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationURL, createDpopBindingError, createDpopProofError, createDpopReplayStore, createInMemoryDpopReplayStore, createPrivateKeyJwtClientAssertionGetter, decodeBasicCredentials, deriveDpopAth, deriveDpopJkt, encodeBasicCredentials, enforceDpopBinding, generateCodeChallenge, getConfirmationJkt, getDpopJktFromPayload, getJwks, getOAuth2Tokens, getPrimaryClientId,
|
|
12
|
+
export { BEARER_AUTHORIZATION_SCHEME, CLIENT_ASSERTION_TYPE, DPOP_AUTHORIZATION_SCHEME, DPOP_PROOF_TYPE, DPOP_SIGNING_ALGORITHMS, PRIVATE_KEY_JWT_SIGNING_ALGORITHMS, RESERVED_AUTHORIZATION_PARAMS, RESERVED_AUTHORIZATION_PARAMS_SET, additionalAuthorizationParamsSchema, applyDefaultAccessTokenExpiry, authorizationCodeRequest, clientCredentialsToken, clientCredentialsTokenRequest, createAuthorizationURL, createDpopBindingError, createDpopProofError, createDpopReplayStore, createInMemoryDpopReplayStore, createPrivateKeyJwtClientAssertionGetter, decodeBasicCredentials, deriveDpopAth, deriveDpopJkt, encodeBasicCredentials, enforceDpopBinding, generateCodeChallenge, getConfirmationJkt, getDpopJktFromPayload, getJwks, getOAuth2Tokens, getPrimaryClientId, isDpopBindingError, isDpopProofError, mergeScopes, normalizeDpopHtu, parseAccessTokenAuthorization, refreshAccessToken, refreshAccessTokenRequest, requestToResourceInput, resolveClientAssertionParams, signPrivateKeyJwtClientAssertion, stripAccessTokenAuthorizationScheme, supportsIdTokenSignIn, validateAuthorizationCode, validateToken, verifyAccessTokenRequest, verifyBearerToken, verifyDpopProof, verifyJwsAccessToken, verifyProviderIdToken };
|
|
@@ -70,57 +70,29 @@ type OAuth2UserInfo = {
|
|
|
70
70
|
emailVerified: boolean;
|
|
71
71
|
};
|
|
72
72
|
/**
|
|
73
|
-
*
|
|
73
|
+
* Request metadata available to provider refresh hooks.
|
|
74
74
|
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* callback can fall back to the request when the provider omits `scope` from
|
|
79
|
-
* its token response (RFC 6749 §5.1).
|
|
75
|
+
* The refresh flow may be triggered by endpoints such as `getAccessToken` or
|
|
76
|
+
* `refreshToken`; this context gives provider hooks access to the triggering
|
|
77
|
+
* request without exposing the full endpoint implementation surface.
|
|
80
78
|
*/
|
|
81
|
-
interface
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
interface OAuthRefreshContext {
|
|
80
|
+
headers?: Headers | undefined;
|
|
81
|
+
request?: Request | undefined;
|
|
84
82
|
}
|
|
85
|
-
|
|
86
|
-
* How much an RP trusts a provider's echoed token-response `scope` when
|
|
87
|
-
* persisting `account.grantedScopes`.
|
|
88
|
-
*
|
|
89
|
-
* - `"full-grant"`: the echo is the user's complete current grant, so the seam
|
|
90
|
-
* replaces the stored grant with it. This is the only path that may narrow
|
|
91
|
-
* the grant. Declare it only for providers whose token response reports the
|
|
92
|
-
* full combined grant, e.g. Google with `include_granted_scopes`.
|
|
93
|
-
* - `"projection"`: the echo is this request's subset, so the seam unions it
|
|
94
|
-
* onto the stored grant. The safe default for every provider.
|
|
95
|
-
* - `"absent-echo"`: the provider omitted `scope`, so the grant equals what was
|
|
96
|
-
* requested (RFC 6749 §5.1) and the seam unions the requested set. Resolved
|
|
97
|
-
* at runtime by the persistence seam, never declared by a provider.
|
|
98
|
-
*
|
|
99
|
-
* @see https://www.rfc-editor.org/rfc/rfc6749#section-5.1
|
|
100
|
-
*/
|
|
101
|
-
type GrantAuthority = "full-grant" | "projection" | "absent-echo";
|
|
102
|
-
/**
|
|
103
|
-
* The authority a provider may declare for its own echoed scope. `"absent-echo"`
|
|
104
|
-
* is excluded because it is a runtime condition (an omitted echo), not a
|
|
105
|
-
* provider trait.
|
|
106
|
-
*/
|
|
107
|
-
type ProviderGrantAuthority = Exclude<GrantAuthority, "absent-echo">;
|
|
108
|
-
interface UpstreamProvider<T extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Partial<ProviderOptions>> {
|
|
83
|
+
interface OAuthProvider<T extends Record<string, any> = Record<string, any>, O extends Record<string, any> = Partial<ProviderOptions>> {
|
|
109
84
|
id: LiteralString;
|
|
110
85
|
/**
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
* How the persistence seam treats this provider's echoed token-response
|
|
117
|
-
* `scope`. Declare `"full-grant"` only when the echo is the user's complete
|
|
118
|
-
* current grant (e.g. Google with `include_granted_scopes`); otherwise the
|
|
119
|
-
* echo is unioned onto the stored grant.
|
|
86
|
+
* Optional path under the resolved per-request `baseURL` where this
|
|
87
|
+
* provider's OAuth callback handler is mounted. Providers that use the
|
|
88
|
+
* shared `/callback/<id>` route can omit this.
|
|
89
|
+
*
|
|
90
|
+
* Custom paths must start with `/`.
|
|
120
91
|
*
|
|
121
|
-
*
|
|
92
|
+
* Endpoints compose `redirectURI = ctx.context.baseURL + callbackPath` per
|
|
93
|
+
* request, so the provider must not hardcode an origin or `baseURL` here.
|
|
122
94
|
*/
|
|
123
|
-
|
|
95
|
+
callbackPath?: string | undefined;
|
|
124
96
|
createAuthorizationURL: (data: {
|
|
125
97
|
state: string;
|
|
126
98
|
codeVerifier: string;
|
|
@@ -128,6 +100,12 @@ interface UpstreamProvider<T extends Record<string, any> = Record<string, any>,
|
|
|
128
100
|
redirectURI: string;
|
|
129
101
|
display?: string | undefined;
|
|
130
102
|
loginHint?: string | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* OIDC nonce generated by the redirect initiator and persisted in OAuth
|
|
105
|
+
* state. Providers that set `requiresIdTokenNonce` must forward this to
|
|
106
|
+
* the authorization URL as the `nonce` parameter.
|
|
107
|
+
*/
|
|
108
|
+
idTokenNonce?: string | undefined;
|
|
131
109
|
/**
|
|
132
110
|
* Extra query parameters to append to the authorization URL.
|
|
133
111
|
* Providers forward these to the shared `createAuthorizationURL` helper,
|
|
@@ -135,7 +113,7 @@ interface UpstreamProvider<T extends Record<string, any> = Record<string, any>,
|
|
|
135
113
|
* before applying them.
|
|
136
114
|
*/
|
|
137
115
|
additionalParams?: Record<string, string> | undefined;
|
|
138
|
-
}) => Awaitable<
|
|
116
|
+
}) => Awaitable<URL>;
|
|
139
117
|
name: string;
|
|
140
118
|
validateAuthorizationCode: (data: {
|
|
141
119
|
code: string;
|
|
@@ -144,6 +122,12 @@ interface UpstreamProvider<T extends Record<string, any> = Record<string, any>,
|
|
|
144
122
|
deviceId?: string | undefined;
|
|
145
123
|
}) => Promise<OAuth2Tokens | null>;
|
|
146
124
|
getUserInfo: (token: OAuth2Tokens & {
|
|
125
|
+
/**
|
|
126
|
+
* OIDC nonce recovered from OAuth state. Providers that required an
|
|
127
|
+
* ID-token nonce must pass this to `verifyProviderIdToken` before
|
|
128
|
+
* trusting ID-token claims.
|
|
129
|
+
*/
|
|
130
|
+
expectedIdTokenNonce?: string | undefined;
|
|
147
131
|
/**
|
|
148
132
|
* The user object from the provider
|
|
149
133
|
* This is only available for some providers like Apple
|
|
@@ -160,9 +144,14 @@ interface UpstreamProvider<T extends Record<string, any> = Record<string, any>,
|
|
|
160
144
|
data: T;
|
|
161
145
|
} | null>;
|
|
162
146
|
/**
|
|
163
|
-
* Custom function to refresh a token
|
|
147
|
+
* Custom function to refresh a token.
|
|
148
|
+
*
|
|
149
|
+
* Receives request metadata from the endpoint that triggered the refresh.
|
|
150
|
+
* Providers that don't need request-scoped data can ignore the second
|
|
151
|
+
* argument.
|
|
164
152
|
*/
|
|
165
|
-
refreshAccessToken?: ((refreshToken: string) => Promise<OAuth2Tokens>) | undefined;
|
|
153
|
+
refreshAccessToken?: ((refreshToken: string, ctx?: OAuthRefreshContext) => Promise<OAuth2Tokens>) | undefined;
|
|
154
|
+
revokeToken?: ((token: string) => Promise<void>) | undefined;
|
|
166
155
|
/**
|
|
167
156
|
* Declarative id_token verification config consumed by the shared
|
|
168
157
|
* `verifyProviderIdToken` verifier. Providers set this instead of implementing a boolean
|
|
@@ -175,6 +164,13 @@ interface UpstreamProvider<T extends Record<string, any> = Record<string, any>,
|
|
|
175
164
|
* against this value to prevent authorization server mix-up attacks.
|
|
176
165
|
*/
|
|
177
166
|
issuer?: string | undefined;
|
|
167
|
+
/**
|
|
168
|
+
* Require shared OAuth redirect routes to bind ID-token verification to an
|
|
169
|
+
* authorization request nonce. When true, routes generate `idTokenNonce`,
|
|
170
|
+
* pass it to `createAuthorizationURL`, persist it in state, and provide it
|
|
171
|
+
* back to `getUserInfo` as `expectedIdTokenNonce`.
|
|
172
|
+
*/
|
|
173
|
+
requiresIdTokenNonce?: boolean | undefined;
|
|
178
174
|
/**
|
|
179
175
|
* Disable implicit sign up for new users. When set to true for the provider,
|
|
180
176
|
* sign-in need to be called with with requestSignUp as true to create new users.
|
|
@@ -333,4 +329,4 @@ type ProviderOptions<Profile extends Record<string, any> = any> = {
|
|
|
333
329
|
requireEmailVerification?: boolean | undefined;
|
|
334
330
|
};
|
|
335
331
|
//#endregion
|
|
336
|
-
export {
|
|
332
|
+
export { OAuth2Tokens, OAuth2UserInfo, OAuthIdTokenConfig, OAuthProvider, OAuthRefreshContext, ProviderOptions };
|
|
@@ -1,6 +1,14 @@
|
|
|
1
|
+
import { parseScopeField } from "./utils.mjs";
|
|
1
2
|
import { applyTokenEndpointAuth } from "./token-endpoint-auth.mjs";
|
|
2
3
|
import { betterFetch } from "@better-fetch/fetch";
|
|
3
4
|
//#region src/oauth2/refresh-access-token.ts
|
|
5
|
+
const BLOCKED_REFRESH_TOKEN_PARAMS_SET = new Set([
|
|
6
|
+
"grant_type",
|
|
7
|
+
"refresh_token",
|
|
8
|
+
"__proto__",
|
|
9
|
+
"constructor",
|
|
10
|
+
"prototype"
|
|
11
|
+
]);
|
|
4
12
|
async function refreshAccessTokenRequest({ refreshToken, options, authentication, tokenEndpointAuth, tokenEndpoint, extraParams, resource }) {
|
|
5
13
|
options = typeof options === "function" ? await options() : options;
|
|
6
14
|
const request = buildRefreshAccessTokenRequest({
|
|
@@ -20,6 +28,13 @@ async function refreshAccessTokenRequest({ refreshToken, options, authentication
|
|
|
20
28
|
});
|
|
21
29
|
return request;
|
|
22
30
|
}
|
|
31
|
+
function applyRefreshExtraParams(body, extraParams) {
|
|
32
|
+
if (!extraParams) return;
|
|
33
|
+
for (const [key, value] of Object.entries(extraParams)) {
|
|
34
|
+
if (BLOCKED_REFRESH_TOKEN_PARAMS_SET.has(key)) continue;
|
|
35
|
+
body.set(key, value);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
23
38
|
function buildRefreshAccessTokenRequest({ refreshToken, options, extraParams, resource }) {
|
|
24
39
|
const body = new URLSearchParams();
|
|
25
40
|
const headers = {
|
|
@@ -30,7 +45,7 @@ function buildRefreshAccessTokenRequest({ refreshToken, options, extraParams, re
|
|
|
30
45
|
body.set("refresh_token", refreshToken);
|
|
31
46
|
if (resource) if (typeof resource === "string") body.append("resource", resource);
|
|
32
47
|
else for (const _resource of resource) body.append("resource", _resource);
|
|
33
|
-
if (extraParams)
|
|
48
|
+
if (extraParams) applyRefreshExtraParams(body, extraParams);
|
|
34
49
|
return {
|
|
35
50
|
body,
|
|
36
51
|
headers
|
|
@@ -56,7 +71,7 @@ async function refreshAccessToken({ refreshToken, options, tokenEndpoint, authen
|
|
|
56
71
|
accessToken: data.access_token,
|
|
57
72
|
refreshToken: data.refresh_token,
|
|
58
73
|
tokenType: data.token_type,
|
|
59
|
-
scopes:
|
|
74
|
+
scopes: parseScopeField(data.scope),
|
|
60
75
|
idToken: data.id_token
|
|
61
76
|
};
|
|
62
77
|
if (data.expires_in) {
|
package/dist/oauth2/utils.d.mts
CHANGED
|
@@ -10,6 +10,11 @@ declare function getOAuth2Tokens(data: Record<string, any>): OAuth2Tokens;
|
|
|
10
10
|
* fallback is configured.
|
|
11
11
|
*/
|
|
12
12
|
declare function applyDefaultAccessTokenExpiry(tokens: OAuth2Tokens, accessTokenExpiresIn: number | undefined): OAuth2Tokens;
|
|
13
|
+
/**
|
|
14
|
+
* Compute the union of stored and incoming OAuth scopes, preserving
|
|
15
|
+
* stored insertion order and dropping duplicates.
|
|
16
|
+
*/
|
|
17
|
+
declare function mergeScopes(stored: string | null | undefined, incoming: string[] | undefined): string;
|
|
13
18
|
/**
|
|
14
19
|
* Return the provider's primary Client ID: the single string, or the entry at
|
|
15
20
|
* array index 0 for the cross-platform form used by ID token audience
|
|
@@ -21,4 +26,4 @@ declare function applyDefaultAccessTokenExpiry(tokens: OAuth2Tokens, accessToken
|
|
|
21
26
|
declare function getPrimaryClientId(clientId: unknown): string | undefined;
|
|
22
27
|
declare function generateCodeChallenge(codeVerifier: string): Promise<string>;
|
|
23
28
|
//#endregion
|
|
24
|
-
export { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId };
|
|
29
|
+
export { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId, mergeScopes };
|
package/dist/oauth2/utils.mjs
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import { parseScopeField } from "./scopes.mjs";
|
|
2
1
|
import { base64Url } from "@better-auth/utils/base64";
|
|
3
2
|
//#region src/oauth2/utils.ts
|
|
3
|
+
/**
|
|
4
|
+
* Parse a provider's `scope` token-response field into a string array.
|
|
5
|
+
*
|
|
6
|
+
* RFC 6749 Section 3.3 defines `scope` as a space-delimited string, but
|
|
7
|
+
* providers vary: some return an already-split array. Accept both forms and
|
|
8
|
+
* drop empty or non-string entries.
|
|
9
|
+
*
|
|
10
|
+
* @see https://github.com/better-auth/better-auth/issues/9076
|
|
11
|
+
*/
|
|
12
|
+
function parseScopeField(scope) {
|
|
13
|
+
if (Array.isArray(scope)) return scope.map((s) => typeof s === "string" ? s.trim() : "").filter(Boolean);
|
|
14
|
+
if (typeof scope === "string") return scope.trim().split(/\s+/).filter(Boolean);
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
4
17
|
function getOAuth2Tokens(data) {
|
|
5
18
|
const getDate = (seconds) => {
|
|
6
19
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -29,6 +42,15 @@ function applyDefaultAccessTokenExpiry(tokens, accessTokenExpiresIn) {
|
|
|
29
42
|
return tokens;
|
|
30
43
|
}
|
|
31
44
|
/**
|
|
45
|
+
* Compute the union of stored and incoming OAuth scopes, preserving
|
|
46
|
+
* stored insertion order and dropping duplicates.
|
|
47
|
+
*/
|
|
48
|
+
function mergeScopes(stored, incoming) {
|
|
49
|
+
const existing = stored ? stored.split(",").map((scope) => scope.trim()).filter(Boolean) : [];
|
|
50
|
+
const next = (incoming ?? []).map((scope) => scope.trim()).filter(Boolean);
|
|
51
|
+
return [...new Set([...existing, ...next])].join(",");
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
32
54
|
* Return the provider's primary Client ID: the single string, or the entry at
|
|
33
55
|
* array index 0 for the cross-platform form used by ID token audience
|
|
34
56
|
* verification. Index 0 is the designated primary and pairs with
|
|
@@ -46,4 +68,4 @@ async function generateCodeChallenge(codeVerifier) {
|
|
|
46
68
|
return base64Url.encode(new Uint8Array(hash), { padding: false });
|
|
47
69
|
}
|
|
48
70
|
//#endregion
|
|
49
|
-
export { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId };
|
|
71
|
+
export { applyDefaultAccessTokenExpiry, generateCodeChallenge, getOAuth2Tokens, getPrimaryClientId, mergeScopes, parseScopeField };
|
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OAuthProvider } from "./oauth-provider.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/oauth2/verify-id-token.d.ts
|
|
4
|
+
type ProviderWithIdTokenConfig = Pick<OAuthProvider, "idToken" | "options">;
|
|
4
5
|
/**
|
|
5
6
|
* Whether a provider can verify a client-submitted id_token.
|
|
6
7
|
*
|
|
7
|
-
* A provider supports id_token sign-in when it declares an {@link
|
|
8
|
+
* A provider supports id_token sign-in when it declares an {@link OAuthProvider.idToken}
|
|
8
9
|
* verification config, or when the integrator supplies a `verifyIdToken` override on the
|
|
9
10
|
* provider options. A provider whose options set `disableIdTokenSignIn`, or that declares
|
|
10
11
|
* neither, rejects the client id_token sign-in path with `ID_TOKEN_NOT_SUPPORTED`.
|
|
11
12
|
*/
|
|
12
|
-
declare function supportsIdTokenSignIn(provider:
|
|
13
|
+
declare function supportsIdTokenSignIn(provider: ProviderWithIdTokenConfig): boolean;
|
|
13
14
|
/**
|
|
14
15
|
* Verify a client-submitted id_token against a provider's verification config.
|
|
15
16
|
*
|
|
16
17
|
* This is the single id_token verifier for every social provider. Providers no longer
|
|
17
|
-
* implement their own boolean `verifyIdToken`; they declare an {@link
|
|
18
|
+
* implement their own boolean `verifyIdToken`; they declare an {@link OAuthProvider.idToken}
|
|
18
19
|
* config and this function performs the cryptographic check. The contract is fail-closed: a
|
|
19
20
|
* provider without a config (and without an integrator `verifyIdToken` override) returns
|
|
20
21
|
* `false`, so a forged token can never be accepted by omission.
|
|
21
22
|
*
|
|
22
23
|
* @returns `true` only when the token is authentic for the provider.
|
|
23
24
|
*/
|
|
24
|
-
declare function verifyProviderIdToken(provider:
|
|
25
|
+
declare function verifyProviderIdToken(provider: ProviderWithIdTokenConfig, token: string, nonce?: string): Promise<boolean>;
|
|
25
26
|
//#endregion
|
|
26
27
|
export { supportsIdTokenSignIn, verifyProviderIdToken };
|
|
@@ -14,7 +14,7 @@ async function nonceMatches(claimNonce, nonce, comparison = "exact") {
|
|
|
14
14
|
/**
|
|
15
15
|
* Whether a provider can verify a client-submitted id_token.
|
|
16
16
|
*
|
|
17
|
-
* A provider supports id_token sign-in when it declares an {@link
|
|
17
|
+
* A provider supports id_token sign-in when it declares an {@link OAuthProvider.idToken}
|
|
18
18
|
* verification config, or when the integrator supplies a `verifyIdToken` override on the
|
|
19
19
|
* provider options. A provider whose options set `disableIdTokenSignIn`, or that declares
|
|
20
20
|
* neither, rejects the client id_token sign-in path with `ID_TOKEN_NOT_SUPPORTED`.
|
|
@@ -28,7 +28,7 @@ function supportsIdTokenSignIn(provider) {
|
|
|
28
28
|
* Verify a client-submitted id_token against a provider's verification config.
|
|
29
29
|
*
|
|
30
30
|
* This is the single id_token verifier for every social provider. Providers no longer
|
|
31
|
-
* implement their own boolean `verifyIdToken`; they declare an {@link
|
|
31
|
+
* implement their own boolean `verifyIdToken`; they declare an {@link OAuthProvider.idToken}
|
|
32
32
|
* config and this function performs the cryptographic check. The contract is fail-closed: a
|
|
33
33
|
* provider without a config (and without an integrator `verifyIdToken` override) returns
|
|
34
34
|
* `false`, so a forged token can never be accepted by omission.
|
|
@@ -69,7 +69,6 @@ interface AppleOptions extends ProviderOptions<AppleProfile> {
|
|
|
69
69
|
declare const apple: (options: AppleOptions) => {
|
|
70
70
|
id: "apple";
|
|
71
71
|
name: string;
|
|
72
|
-
callbackPath: string;
|
|
73
72
|
createAuthorizationURL({
|
|
74
73
|
state,
|
|
75
74
|
scopes,
|
|
@@ -82,11 +81,9 @@ declare const apple: (options: AppleOptions) => {
|
|
|
82
81
|
redirectURI: string;
|
|
83
82
|
display?: string | undefined;
|
|
84
83
|
loginHint?: string | undefined;
|
|
84
|
+
idTokenNonce?: string | undefined;
|
|
85
85
|
additionalParams?: Record<string, string> | undefined;
|
|
86
|
-
}): Promise<
|
|
87
|
-
url: URL;
|
|
88
|
-
requestedScopes: string[];
|
|
89
|
-
}>;
|
|
86
|
+
}): Promise<URL>;
|
|
90
87
|
validateAuthorizationCode: ({
|
|
91
88
|
code,
|
|
92
89
|
codeVerifier,
|
|
@@ -106,6 +103,7 @@ declare const apple: (options: AppleOptions) => {
|
|
|
106
103
|
};
|
|
107
104
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
108
105
|
getUserInfo(token: OAuth2Tokens & {
|
|
106
|
+
expectedIdTokenNonce?: string | undefined;
|
|
109
107
|
user?: {
|
|
110
108
|
name?: {
|
|
111
109
|
firstName?: string;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { APIError, BetterAuthError } from "../error/index.mjs";
|
|
2
2
|
import { logger } from "../env/logger.mjs";
|
|
3
|
-
import { resolveRequestedScopes } from "../oauth2/scopes.mjs";
|
|
4
3
|
import { getPrimaryClientId } from "../oauth2/utils.mjs";
|
|
5
4
|
import { createAuthorizationURL } from "../oauth2/create-authorization-url.mjs";
|
|
6
5
|
import { refreshAccessToken } from "../oauth2/refresh-access-token.mjs";
|
|
@@ -8,23 +7,24 @@ import { validateAuthorizationCode } from "../oauth2/validate-authorization-code
|
|
|
8
7
|
import { decodeJwt, importJWK } from "jose";
|
|
9
8
|
import { betterFetch } from "@better-fetch/fetch";
|
|
10
9
|
//#region src/social-providers/apple.ts
|
|
11
|
-
const APPLE_DEFAULT_SCOPES = ["email", "name"];
|
|
12
10
|
const apple = (options) => {
|
|
13
11
|
const tokenEndpoint = "https://appleid.apple.com/auth/token";
|
|
14
12
|
return {
|
|
15
13
|
id: "apple",
|
|
16
14
|
name: "Apple",
|
|
17
|
-
callbackPath: "/callback/apple",
|
|
18
15
|
async createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
19
16
|
if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
|
|
20
17
|
logger.error("Client ID and client secret are required for Apple. Make sure to provide them in the options.");
|
|
21
18
|
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
22
19
|
}
|
|
23
|
-
|
|
20
|
+
const _scope = options.disableDefaultScope ? [] : ["email", "name"];
|
|
21
|
+
if (options.scope) _scope.push(...options.scope);
|
|
22
|
+
if (scopes) _scope.push(...scopes);
|
|
23
|
+
return await createAuthorizationURL({
|
|
24
24
|
id: "apple",
|
|
25
25
|
options,
|
|
26
26
|
authorizationEndpoint: "https://appleid.apple.com/auth/authorize",
|
|
27
|
-
scopes:
|
|
27
|
+
scopes: _scope,
|
|
28
28
|
state,
|
|
29
29
|
redirectURI,
|
|
30
30
|
responseMode: "form_post",
|
|
@@ -21,7 +21,6 @@ interface AtlassianOptions extends ProviderOptions<AtlassianProfile> {
|
|
|
21
21
|
declare const atlassian: (options: AtlassianOptions) => {
|
|
22
22
|
id: "atlassian";
|
|
23
23
|
name: string;
|
|
24
|
-
callbackPath: string;
|
|
25
24
|
createAuthorizationURL({
|
|
26
25
|
state,
|
|
27
26
|
scopes,
|
|
@@ -35,11 +34,9 @@ declare const atlassian: (options: AtlassianOptions) => {
|
|
|
35
34
|
redirectURI: string;
|
|
36
35
|
display?: string | undefined;
|
|
37
36
|
loginHint?: string | undefined;
|
|
37
|
+
idTokenNonce?: string | undefined;
|
|
38
38
|
additionalParams?: Record<string, string> | undefined;
|
|
39
|
-
}): Promise<
|
|
40
|
-
url: URL;
|
|
41
|
-
requestedScopes: string[];
|
|
42
|
-
}>;
|
|
39
|
+
}): Promise<URL>;
|
|
43
40
|
validateAuthorizationCode: ({
|
|
44
41
|
code,
|
|
45
42
|
codeVerifier,
|
|
@@ -52,6 +49,7 @@ declare const atlassian: (options: AtlassianOptions) => {
|
|
|
52
49
|
}) => Promise<OAuth2Tokens>;
|
|
53
50
|
refreshAccessToken: (refreshToken: string) => Promise<OAuth2Tokens>;
|
|
54
51
|
getUserInfo(token: OAuth2Tokens & {
|
|
52
|
+
expectedIdTokenNonce?: string | undefined;
|
|
55
53
|
user?: {
|
|
56
54
|
name?: {
|
|
57
55
|
firstName?: string;
|