@better-auth/core 1.7.0-rc.1 → 1.7.0-rc.2
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 +28 -28
- package/dist/async_hooks/index.d.mts +0 -1
- package/dist/async_hooks/pure.index.d.mts +0 -1
- package/dist/context/endpoint-context.d.mts +1 -1
- package/dist/context/global.d.mts +0 -1
- package/dist/context/global.mjs +1 -1
- package/dist/context/request-state.d.mts +0 -1
- package/dist/context/request-state.mjs +8 -5
- package/dist/context/transaction.d.mts +8 -3
- package/dist/context/transaction.mjs +27 -10
- package/dist/db/adapter/factory.d.mts +3 -5
- package/dist/db/adapter/factory.mjs +7 -5
- package/dist/db/adapter/get-default-field-name.d.mts +2 -9
- package/dist/db/adapter/get-default-model-name.d.mts +1 -5
- package/dist/db/adapter/get-default-model-name.mjs +6 -5
- package/dist/db/adapter/get-field-attributes.d.mts +4 -11
- package/dist/db/adapter/get-field-name.d.mts +2 -9
- package/dist/db/adapter/get-id-field.d.mts +4 -12
- package/dist/db/adapter/get-model-name.d.mts +1 -5
- package/dist/db/adapter/index.d.mts +7 -32
- package/dist/db/adapter/types.d.mts +5 -17
- package/dist/db/adapter/utils.d.mts +0 -1
- package/dist/db/database-index.d.mts +44 -0
- package/dist/db/database-index.mjs +168 -0
- package/dist/db/get-tables.d.mts +7 -1
- package/dist/db/get-tables.mjs +47 -6
- package/dist/db/index.d.mts +3 -3
- package/dist/db/index.mjs +2 -2
- package/dist/db/internal.d.mts +3 -0
- package/dist/db/internal.mjs +3 -0
- package/dist/db/plugin.d.mts +4 -3
- package/dist/db/schema/account.d.mts +16 -3
- package/dist/db/schema/account.mjs +35 -2
- package/dist/db/schema/rate-limit.d.mts +1 -1
- package/dist/db/schema/rate-limit.mjs +9 -0
- package/dist/db/schema/session.d.mts +1 -1
- package/dist/db/schema/shared.d.mts +0 -1
- package/dist/db/schema/user.d.mts +1 -1
- package/dist/db/schema/verification.d.mts +1 -1
- package/dist/db/type.d.mts +17 -9
- package/dist/env/logger.d.mts +25 -25
- package/dist/error/codes.d.mts +0 -1
- package/dist/error/index.d.mts +0 -1
- package/dist/index.d.mts +1 -1
- package/dist/instrumentation/attributes.d.mts +0 -1
- package/dist/instrumentation/pure.index.d.mts +0 -1
- package/dist/instrumentation/tracer.mjs +1 -1
- package/dist/oauth2/authorization-params.d.mts +0 -1
- package/dist/oauth2/client-assertion.d.mts +3 -13
- package/dist/oauth2/client-credentials-token.d.mts +3 -17
- package/dist/oauth2/client-credentials-token.mjs +1 -4
- package/dist/oauth2/create-authorization-url.d.mts +3 -21
- package/dist/oauth2/dpop.d.mts +2 -23
- package/dist/oauth2/dpop.mjs +1 -1
- package/dist/oauth2/index.d.mts +2 -2
- package/dist/oauth2/oauth-provider.d.mts +85 -36
- package/dist/oauth2/refresh-access-token.d.mts +3 -19
- package/dist/oauth2/refresh-access-token.mjs +3 -9
- package/dist/oauth2/reject-redirects.mjs +1 -1
- package/dist/oauth2/token-endpoint-auth.d.mts +0 -1
- package/dist/oauth2/utils.d.mts +0 -1
- package/dist/oauth2/utils.mjs +2 -3
- package/dist/oauth2/validate-authorization-code.d.mts +5 -29
- package/dist/oauth2/verify-id-token.d.mts +3 -2
- package/dist/oauth2/verify-id-token.mjs +3 -3
- package/dist/oauth2/verify.d.mts +5 -7
- package/dist/oauth2/verify.mjs +2 -2
- package/dist/social-providers/apple.d.mts +9 -24
- package/dist/social-providers/apple.mjs +2 -1
- package/dist/social-providers/atlassian.d.mts +18 -19
- package/dist/social-providers/atlassian.mjs +1 -1
- package/dist/social-providers/cognito.d.mts +33 -22
- package/dist/social-providers/cognito.mjs +2 -2
- package/dist/social-providers/discord.d.mts +7 -20
- package/dist/social-providers/discord.mjs +1 -1
- package/dist/social-providers/dropbox.d.mts +7 -22
- package/dist/social-providers/dropbox.mjs +1 -1
- package/dist/social-providers/facebook.d.mts +19 -27
- package/dist/social-providers/facebook.mjs +6 -17
- package/dist/social-providers/figma.d.mts +7 -22
- package/dist/social-providers/figma.mjs +1 -1
- package/dist/social-providers/github.d.mts +7 -23
- package/dist/social-providers/github.mjs +1 -1
- package/dist/social-providers/gitlab.d.mts +6 -43
- package/dist/social-providers/gitlab.mjs +1 -1
- package/dist/social-providers/google.d.mts +10 -32
- package/dist/social-providers/google.mjs +2 -1
- package/dist/social-providers/huggingface.d.mts +7 -22
- package/dist/social-providers/huggingface.mjs +1 -1
- package/dist/social-providers/index.d.mts +229 -787
- package/dist/social-providers/kakao.d.mts +8 -33
- package/dist/social-providers/kakao.mjs +1 -1
- package/dist/social-providers/kick.d.mts +7 -22
- package/dist/social-providers/kick.mjs +1 -1
- package/dist/social-providers/line.d.mts +8 -44
- package/dist/social-providers/line.mjs +4 -6
- package/dist/social-providers/linear.d.mts +7 -21
- package/dist/social-providers/linear.mjs +1 -1
- package/dist/social-providers/linkedin.d.mts +7 -21
- package/dist/social-providers/linkedin.mjs +1 -1
- package/dist/social-providers/microsoft-entra-id.d.mts +8 -18
- package/dist/social-providers/microsoft-entra-id.mjs +18 -2
- package/dist/social-providers/naver.d.mts +27 -42
- package/dist/social-providers/naver.mjs +1 -1
- package/dist/social-providers/notion.d.mts +7 -21
- package/dist/social-providers/notion.mjs +1 -1
- package/dist/social-providers/paybin.d.mts +8 -23
- package/dist/social-providers/paybin.mjs +2 -1
- package/dist/social-providers/paypal.d.mts +8 -33
- package/dist/social-providers/paypal.mjs +1 -1
- package/dist/social-providers/polar.d.mts +7 -22
- package/dist/social-providers/polar.mjs +1 -1
- package/dist/social-providers/railway.d.mts +7 -22
- package/dist/social-providers/railway.mjs +1 -1
- package/dist/social-providers/reddit.d.mts +7 -20
- package/dist/social-providers/reddit.mjs +1 -1
- package/dist/social-providers/roblox.d.mts +7 -20
- package/dist/social-providers/roblox.mjs +1 -1
- package/dist/social-providers/salesforce.d.mts +7 -22
- package/dist/social-providers/salesforce.mjs +1 -1
- package/dist/social-providers/slack.d.mts +7 -20
- package/dist/social-providers/slack.mjs +1 -1
- package/dist/social-providers/spotify.d.mts +7 -22
- package/dist/social-providers/spotify.mjs +1 -1
- package/dist/social-providers/tiktok.d.mts +10 -22
- package/dist/social-providers/tiktok.mjs +1 -1
- package/dist/social-providers/twitch.d.mts +7 -20
- package/dist/social-providers/twitch.mjs +1 -1
- package/dist/social-providers/twitter.d.mts +29 -26
- package/dist/social-providers/twitter.mjs +1 -1
- package/dist/social-providers/vercel.d.mts +7 -22
- package/dist/social-providers/vercel.mjs +1 -1
- package/dist/social-providers/vk.d.mts +8 -24
- package/dist/social-providers/vk.mjs +5 -6
- package/dist/social-providers/wechat.d.mts +7 -19
- package/dist/social-providers/wechat.mjs +1 -1
- package/dist/social-providers/zoom.d.mts +9 -25
- package/dist/social-providers/zoom.mjs +1 -1
- package/dist/types/context.d.mts +16 -9
- package/dist/types/cookie.d.mts +0 -1
- package/dist/types/helper.d.mts +1 -1
- package/dist/types/index.d.mts +1 -1
- package/dist/types/init-options.d.mts +37 -26
- package/dist/types/plugin-client.d.mts +1 -3
- package/dist/types/plugin.d.mts +2 -2
- package/dist/utils/async.d.mts +0 -1
- package/dist/utils/db.d.mts +1 -0
- package/dist/utils/deprecate.d.mts +0 -1
- package/dist/utils/error-codes.d.mts +2 -2
- package/dist/utils/host.d.mts +27 -1
- package/dist/utils/host.mjs +1 -1
- package/dist/utils/ip.d.mts +1 -0
- package/dist/utils/ip.mjs +1 -1
- package/dist/utils/is-api-error.d.mts +0 -1
- package/dist/utils/redirect-uri.d.mts +0 -1
- package/package.json +10 -2
- package/src/context/request-state.ts +26 -6
- package/src/context/transaction.ts +37 -18
- package/src/db/adapter/factory.ts +24 -18
- package/src/db/adapter/get-default-model-name.ts +23 -14
- package/src/db/database-index.ts +351 -0
- package/src/db/get-tables.ts +89 -9
- package/src/db/index.ts +4 -0
- package/src/db/internal.ts +12 -0
- package/src/db/plugin.ts +3 -1
- package/src/db/schema/account.ts +27 -1
- package/src/db/schema/user.ts +1 -1
- package/src/db/type.ts +12 -0
- package/src/oauth2/index.ts +3 -0
- package/src/oauth2/oauth-provider.ts +94 -36
- package/src/oauth2/verify-id-token.ts +4 -2
- package/src/social-providers/apple.ts +2 -1
- package/src/social-providers/atlassian.ts +1 -1
- package/src/social-providers/cognito.ts +2 -2
- package/src/social-providers/discord.ts +1 -1
- package/src/social-providers/dropbox.ts +1 -1
- package/src/social-providers/facebook.ts +21 -28
- package/src/social-providers/figma.ts +1 -1
- package/src/social-providers/github.ts +1 -1
- package/src/social-providers/gitlab.ts +1 -1
- package/src/social-providers/google.ts +2 -1
- package/src/social-providers/huggingface.ts +1 -1
- package/src/social-providers/kakao.ts +1 -1
- package/src/social-providers/kick.ts +1 -1
- package/src/social-providers/line.ts +7 -12
- package/src/social-providers/linear.ts +1 -1
- package/src/social-providers/linkedin.ts +1 -1
- package/src/social-providers/microsoft-entra-id.ts +3 -2
- package/src/social-providers/naver.ts +1 -1
- package/src/social-providers/notion.ts +1 -1
- package/src/social-providers/paybin.ts +2 -1
- package/src/social-providers/paypal.ts +1 -1
- package/src/social-providers/polar.ts +1 -1
- package/src/social-providers/railway.ts +1 -1
- package/src/social-providers/reddit.ts +1 -1
- package/src/social-providers/roblox.ts +1 -1
- package/src/social-providers/salesforce.ts +1 -1
- package/src/social-providers/slack.ts +1 -1
- package/src/social-providers/spotify.ts +1 -1
- package/src/social-providers/tiktok.ts +2 -2
- package/src/social-providers/twitch.ts +1 -1
- package/src/social-providers/twitter.ts +1 -1
- package/src/social-providers/vercel.ts +1 -1
- package/src/social-providers/vk.ts +2 -2
- package/src/social-providers/wechat.ts +1 -1
- package/src/social-providers/zoom.ts +1 -1
- package/src/types/context.ts +21 -14
- package/src/types/init-options.ts +15 -14
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { JWTVerifyGetKey } from "jose";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
Awaitable,
|
|
4
|
+
GenericEndpointContext,
|
|
5
|
+
LiteralString,
|
|
6
|
+
} from "../types";
|
|
3
7
|
|
|
4
8
|
/**
|
|
5
9
|
* id_token verification config for a social provider.
|
|
@@ -51,7 +55,11 @@ export type OAuthIdTokenConfig =
|
|
|
51
55
|
* Custom verifier for providers that cannot verify against a local JWKS, such as a
|
|
52
56
|
* remote verification endpoint (e.g. LINE).
|
|
53
57
|
*/
|
|
54
|
-
verify: (
|
|
58
|
+
verify: (
|
|
59
|
+
token: string,
|
|
60
|
+
nonce?: string,
|
|
61
|
+
ctx?: GenericEndpointContext,
|
|
62
|
+
) => Promise<boolean>;
|
|
55
63
|
};
|
|
56
64
|
|
|
57
65
|
export interface OAuth2Tokens {
|
|
@@ -69,14 +77,52 @@ export interface OAuth2Tokens {
|
|
|
69
77
|
raw?: Record<string, unknown> | undefined;
|
|
70
78
|
}
|
|
71
79
|
|
|
80
|
+
/** Mutable local-user attributes normalized from an OAuth provider profile. */
|
|
72
81
|
export type OAuth2UserInfo = {
|
|
73
|
-
|
|
82
|
+
/** Provider identity belongs in raw profile data and `accountSubject`. */
|
|
83
|
+
id?: never;
|
|
74
84
|
name?: string | undefined;
|
|
75
85
|
email?: (string | null) | undefined;
|
|
76
86
|
image?: string | undefined;
|
|
77
87
|
emailVerified: boolean;
|
|
78
88
|
};
|
|
79
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Verified provider data available when deriving a stable OAuth account key.
|
|
92
|
+
*
|
|
93
|
+
* Account-key resolvers must use the raw provider profile or verified token
|
|
94
|
+
* response. They never receive the mapped local user, so profile mapping
|
|
95
|
+
* cannot redefine provider identity.
|
|
96
|
+
*/
|
|
97
|
+
export interface OAuthAccountKeyContext<Profile extends object = object> {
|
|
98
|
+
tokens: OAuth2Tokens;
|
|
99
|
+
profile: Profile;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Resolves one part of an account key from a profile returned by the same
|
|
104
|
+
* provider. The method-derived callback keeps that profile pairing intact when
|
|
105
|
+
* providers with different profile shapes share an `OAuthProvider[]`.
|
|
106
|
+
*/
|
|
107
|
+
type OAuthAccountKeyResolver<Profile extends object, Value> = {
|
|
108
|
+
resolve(context: OAuthAccountKeyContext<Profile>): Awaitable<Value>;
|
|
109
|
+
}["resolve"];
|
|
110
|
+
|
|
111
|
+
/** Resolves the stable provider subject used to build an OAuth account key. */
|
|
112
|
+
export type OAuthAccountSubject<Profile extends object = object> =
|
|
113
|
+
OAuthAccountKeyResolver<Profile, string | number>;
|
|
114
|
+
|
|
115
|
+
/** Mutable local-user attributes returned by `mapProfileToUser`. */
|
|
116
|
+
export type OAuthMappedUser = {
|
|
117
|
+
/** Provider identity is defined by `accountSubject`, not local user mapping. */
|
|
118
|
+
id?: never;
|
|
119
|
+
name?: string;
|
|
120
|
+
email?: string | null;
|
|
121
|
+
image?: string;
|
|
122
|
+
emailVerified?: boolean;
|
|
123
|
+
[key: string]: unknown;
|
|
124
|
+
};
|
|
125
|
+
|
|
80
126
|
/**
|
|
81
127
|
* Request metadata available to provider refresh hooks.
|
|
82
128
|
*
|
|
@@ -90,8 +136,8 @@ export interface OAuthRefreshContext {
|
|
|
90
136
|
}
|
|
91
137
|
|
|
92
138
|
export interface OAuthProvider<
|
|
93
|
-
T extends
|
|
94
|
-
O extends
|
|
139
|
+
T extends object = object,
|
|
140
|
+
O extends object = Partial<ProviderOptions>,
|
|
95
141
|
> {
|
|
96
142
|
id: LiteralString;
|
|
97
143
|
/**
|
|
@@ -127,6 +173,15 @@ export interface OAuthProvider<
|
|
|
127
173
|
additionalParams?: Record<string, string> | undefined;
|
|
128
174
|
}) => Awaitable<URL>;
|
|
129
175
|
name: string;
|
|
176
|
+
/**
|
|
177
|
+
* Stable subject that identifies the provider account.
|
|
178
|
+
*
|
|
179
|
+
* Read this value from the raw, provider-verified profile. For OpenID
|
|
180
|
+
* Connect providers, use the `sub` claim. For OAuth providers, use the
|
|
181
|
+
* provider's documented immutable user identifier. Never derive this value
|
|
182
|
+
* from `mapProfileToUser`.
|
|
183
|
+
*/
|
|
184
|
+
accountSubject: OAuthAccountSubject<T>;
|
|
130
185
|
validateAuthorizationCode: (data: {
|
|
131
186
|
code: string;
|
|
132
187
|
redirectURI: string;
|
|
@@ -185,6 +240,16 @@ export interface OAuthProvider<
|
|
|
185
240
|
* against this value to prevent authorization server mix-up attacks.
|
|
186
241
|
*/
|
|
187
242
|
issuer?: string | undefined;
|
|
243
|
+
/**
|
|
244
|
+
* Stable issuer used with the provider subject to recognize an account.
|
|
245
|
+
*
|
|
246
|
+
* Use the validated OpenID Connect issuer for OIDC providers. A resolver is
|
|
247
|
+
* supported for tenant-specific issuers and receives only provider-verified
|
|
248
|
+
* data. OAuth providers without an issuer omit this property and are scoped
|
|
249
|
+
* to the synthetic `local:oauth:<encoded providerId>` issuer, where the
|
|
250
|
+
* provider ID segment is percent-encoded.
|
|
251
|
+
*/
|
|
252
|
+
accountIssuer?: string | OAuthAccountKeyResolver<T, string> | undefined;
|
|
188
253
|
/**
|
|
189
254
|
* Require shared OAuth redirect routes to bind ID-token verification to an
|
|
190
255
|
* authorization request nonce. When true, routes generate `idTokenNonce`,
|
|
@@ -218,7 +283,15 @@ export interface OAuthProvider<
|
|
|
218
283
|
options?: O | undefined;
|
|
219
284
|
}
|
|
220
285
|
|
|
221
|
-
|
|
286
|
+
/**
|
|
287
|
+
* Maps a provider-specific profile while remaining compatible with the erased
|
|
288
|
+
* profile type used by shared OAuth helpers.
|
|
289
|
+
*/
|
|
290
|
+
type OAuthProfileMapper<Profile extends object> = {
|
|
291
|
+
map(profile: Profile): Awaitable<OAuthMappedUser>;
|
|
292
|
+
}["map"];
|
|
293
|
+
|
|
294
|
+
export type ProviderOptions<Profile extends object = object> = {
|
|
222
295
|
/**
|
|
223
296
|
* The client ID of your application.
|
|
224
297
|
*
|
|
@@ -262,25 +335,28 @@ export type ProviderOptions<Profile extends Record<string, any> = any> = {
|
|
|
262
335
|
*/
|
|
263
336
|
disableIdTokenSignIn?: boolean | undefined;
|
|
264
337
|
/**
|
|
265
|
-
* verifyIdToken function to verify the id token
|
|
338
|
+
* verifyIdToken function to verify the id token.
|
|
339
|
+
*
|
|
340
|
+
* The optional endpoint context exposes request metadata to custom
|
|
341
|
+
* verifiers without coupling built-in provider verification to a runtime.
|
|
266
342
|
*/
|
|
267
343
|
verifyIdToken?:
|
|
268
|
-
| ((
|
|
344
|
+
| ((
|
|
345
|
+
token: string,
|
|
346
|
+
nonce?: string,
|
|
347
|
+
ctx?: GenericEndpointContext,
|
|
348
|
+
) => Promise<boolean>)
|
|
269
349
|
| undefined;
|
|
270
350
|
/**
|
|
271
351
|
* Custom function to get user info from the provider
|
|
352
|
+
*
|
|
353
|
+
* `data` must preserve the declared raw profile shape because account-key
|
|
354
|
+
* resolvers consume it after this hook returns.
|
|
272
355
|
*/
|
|
273
356
|
getUserInfo?:
|
|
274
357
|
| ((token: OAuth2Tokens) => Promise<{
|
|
275
|
-
user:
|
|
276
|
-
|
|
277
|
-
name?: string;
|
|
278
|
-
email?: string | null;
|
|
279
|
-
image?: string;
|
|
280
|
-
emailVerified: boolean;
|
|
281
|
-
[key: string]: any;
|
|
282
|
-
};
|
|
283
|
-
data: any;
|
|
358
|
+
user: OAuth2UserInfo & Record<string, unknown>;
|
|
359
|
+
data: Profile;
|
|
284
360
|
} | null>)
|
|
285
361
|
| undefined;
|
|
286
362
|
/**
|
|
@@ -293,25 +369,7 @@ export type ProviderOptions<Profile extends Record<string, any> = any> = {
|
|
|
293
369
|
* Custom function to map the provider profile to a
|
|
294
370
|
* user.
|
|
295
371
|
*/
|
|
296
|
-
mapProfileToUser?:
|
|
297
|
-
| ((profile: Profile) =>
|
|
298
|
-
| {
|
|
299
|
-
id?: string;
|
|
300
|
-
name?: string;
|
|
301
|
-
email?: string | null;
|
|
302
|
-
image?: string;
|
|
303
|
-
emailVerified?: boolean;
|
|
304
|
-
[key: string]: any;
|
|
305
|
-
}
|
|
306
|
-
| Promise<{
|
|
307
|
-
id?: string;
|
|
308
|
-
name?: string;
|
|
309
|
-
email?: string | null;
|
|
310
|
-
image?: string;
|
|
311
|
-
emailVerified?: boolean;
|
|
312
|
-
[key: string]: any;
|
|
313
|
-
}>)
|
|
314
|
-
| undefined;
|
|
372
|
+
mapProfileToUser?: OAuthProfileMapper<Profile> | undefined;
|
|
315
373
|
/**
|
|
316
374
|
* Disable implicit sign up for new users. When set to true for the provider,
|
|
317
375
|
* sign-in need to be called with with requestSignUp as true to create new users.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { decodeProtectedHeader, jwtVerify } from "jose";
|
|
2
|
+
import type { GenericEndpointContext } from "../types";
|
|
2
3
|
import type { OAuthProvider, ProviderOptions } from "./oauth-provider";
|
|
3
4
|
|
|
4
5
|
type ProviderWithIdTokenConfig = Pick<OAuthProvider, "idToken" | "options">;
|
|
@@ -59,6 +60,7 @@ export async function verifyProviderIdToken(
|
|
|
59
60
|
provider: ProviderWithIdTokenConfig,
|
|
60
61
|
token: string,
|
|
61
62
|
nonce?: string,
|
|
63
|
+
ctx?: GenericEndpointContext,
|
|
62
64
|
): Promise<boolean> {
|
|
63
65
|
const options = (provider.options ?? {}) as Partial<ProviderOptions>;
|
|
64
66
|
if (options.disableIdTokenSignIn) {
|
|
@@ -69,14 +71,14 @@ export async function verifyProviderIdToken(
|
|
|
69
71
|
// escaping to the caller as a server error.
|
|
70
72
|
try {
|
|
71
73
|
if (options.verifyIdToken) {
|
|
72
|
-
return await options.verifyIdToken(token, nonce);
|
|
74
|
+
return await options.verifyIdToken(token, nonce, ctx);
|
|
73
75
|
}
|
|
74
76
|
const config = provider.idToken;
|
|
75
77
|
if (!config) {
|
|
76
78
|
return false;
|
|
77
79
|
}
|
|
78
80
|
if ("verify" in config) {
|
|
79
|
-
return await config.verify(token, nonce);
|
|
81
|
+
return await config.verify(token, nonce, ctx);
|
|
80
82
|
}
|
|
81
83
|
// Opaque (non-JWS) tokens carry no signature to check. They are accepted only when the
|
|
82
84
|
// provider opts in, in which case getUserInfo resolves identity from the access token via
|
|
@@ -82,6 +82,8 @@ export const apple = (options: AppleOptions) => {
|
|
|
82
82
|
return {
|
|
83
83
|
id: "apple",
|
|
84
84
|
name: "Apple",
|
|
85
|
+
accountSubject: ({ profile }) => profile.sub,
|
|
86
|
+
accountIssuer: "https://appleid.apple.com",
|
|
85
87
|
async createAuthorizationURL({
|
|
86
88
|
state,
|
|
87
89
|
scopes,
|
|
@@ -174,7 +176,6 @@ export const apple = (options: AppleOptions) => {
|
|
|
174
176
|
const userMap = await options.mapProfileToUser?.(enrichedProfile);
|
|
175
177
|
return {
|
|
176
178
|
user: {
|
|
177
|
-
id: profile.sub,
|
|
178
179
|
name: enrichedProfile.name,
|
|
179
180
|
emailVerified: emailVerified,
|
|
180
181
|
email: profile.email,
|
|
@@ -34,6 +34,7 @@ export const atlassian = (options: AtlassianOptions) => {
|
|
|
34
34
|
return {
|
|
35
35
|
id: "atlassian",
|
|
36
36
|
name: "Atlassian",
|
|
37
|
+
accountSubject: ({ profile }) => profile.account_id,
|
|
37
38
|
|
|
38
39
|
async createAuthorizationURL({
|
|
39
40
|
state,
|
|
@@ -120,7 +121,6 @@ export const atlassian = (options: AtlassianOptions) => {
|
|
|
120
121
|
|
|
121
122
|
return {
|
|
122
123
|
user: {
|
|
123
|
-
id: profile.account_id,
|
|
124
124
|
name: profile.name,
|
|
125
125
|
email: profile.email,
|
|
126
126
|
image: profile.picture,
|
|
@@ -73,6 +73,8 @@ export const cognito = (options: CognitoOptions) => {
|
|
|
73
73
|
return {
|
|
74
74
|
id: "cognito",
|
|
75
75
|
name: "Cognito",
|
|
76
|
+
accountSubject: ({ profile }) => profile.sub,
|
|
77
|
+
accountIssuer: `https://cognito-idp.${options.region}.amazonaws.com/${options.userPoolId}`,
|
|
76
78
|
async createAuthorizationURL({
|
|
77
79
|
state,
|
|
78
80
|
scopes,
|
|
@@ -184,7 +186,6 @@ export const cognito = (options: CognitoOptions) => {
|
|
|
184
186
|
|
|
185
187
|
return {
|
|
186
188
|
user: {
|
|
187
|
-
id: profile.sub,
|
|
188
189
|
name: enrichedProfile.name,
|
|
189
190
|
email: profile.email,
|
|
190
191
|
image: profile.picture,
|
|
@@ -213,7 +214,6 @@ export const cognito = (options: CognitoOptions) => {
|
|
|
213
214
|
const userMap = await options.mapProfileToUser?.(userInfo);
|
|
214
215
|
return {
|
|
215
216
|
user: {
|
|
216
|
-
id: userInfo.sub,
|
|
217
217
|
name:
|
|
218
218
|
userInfo.name ||
|
|
219
219
|
userInfo.given_name ||
|
|
@@ -88,6 +88,7 @@ export const discord = (options: DiscordOptions) => {
|
|
|
88
88
|
return {
|
|
89
89
|
id: "discord",
|
|
90
90
|
name: "Discord",
|
|
91
|
+
accountSubject: ({ profile }) => profile.id,
|
|
91
92
|
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
92
93
|
const _scopes = options.disableDefaultScope ? [] : ["identify", "email"];
|
|
93
94
|
if (scopes) _scopes.push(...scopes);
|
|
@@ -159,7 +160,6 @@ export const discord = (options: DiscordOptions) => {
|
|
|
159
160
|
const userMap = await options.mapProfileToUser?.(profile);
|
|
160
161
|
return {
|
|
161
162
|
user: {
|
|
162
|
-
id: profile.id,
|
|
163
163
|
name: profile.global_name || profile.username || "",
|
|
164
164
|
email: profile.email,
|
|
165
165
|
emailVerified: profile.verified,
|
|
@@ -31,6 +31,7 @@ export const dropbox = (options: DropboxOptions) => {
|
|
|
31
31
|
return {
|
|
32
32
|
id: "dropbox",
|
|
33
33
|
name: "Dropbox",
|
|
34
|
+
accountSubject: ({ profile }) => profile.account_id,
|
|
34
35
|
createAuthorizationURL: async ({
|
|
35
36
|
state,
|
|
36
37
|
scopes,
|
|
@@ -99,7 +100,6 @@ export const dropbox = (options: DropboxOptions) => {
|
|
|
99
100
|
const userMap = await options.mapProfileToUser?.(profile);
|
|
100
101
|
return {
|
|
101
102
|
user: {
|
|
102
|
-
id: profile.account_id,
|
|
103
103
|
name: profile.name?.display_name,
|
|
104
104
|
email: profile.email,
|
|
105
105
|
emailVerified: profile.email_verified || false,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
refreshAccessToken,
|
|
10
10
|
validateAuthorizationCode,
|
|
11
11
|
} from "../oauth2";
|
|
12
|
-
export interface
|
|
12
|
+
export interface FacebookGraphProfile {
|
|
13
13
|
id: string;
|
|
14
14
|
name: string;
|
|
15
15
|
email?: string;
|
|
@@ -24,6 +24,17 @@ export interface FacebookProfile {
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
export interface FacebookLimitedLoginProfile {
|
|
28
|
+
sub: string;
|
|
29
|
+
email: string;
|
|
30
|
+
name: string;
|
|
31
|
+
picture: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type FacebookProfile =
|
|
35
|
+
| FacebookGraphProfile
|
|
36
|
+
| FacebookLimitedLoginProfile;
|
|
37
|
+
|
|
27
38
|
interface FacebookDebugTokenData {
|
|
28
39
|
app_id?: string;
|
|
29
40
|
is_valid?: boolean;
|
|
@@ -95,6 +106,9 @@ export const facebook = (options: FacebookOptions) => {
|
|
|
95
106
|
return {
|
|
96
107
|
id: "facebook",
|
|
97
108
|
name: "Facebook",
|
|
109
|
+
accountSubject: ({ profile }) =>
|
|
110
|
+
"sub" in profile ? profile.sub : profile.id,
|
|
111
|
+
accountIssuer: "https://www.facebook.com",
|
|
98
112
|
async createAuthorizationURL({
|
|
99
113
|
state,
|
|
100
114
|
scopes,
|
|
@@ -167,38 +181,18 @@ export const facebook = (options: FacebookOptions) => {
|
|
|
167
181
|
}
|
|
168
182
|
|
|
169
183
|
if (token.idToken && token.idToken.split(".").length === 3) {
|
|
170
|
-
const profile = decodeJwt(token.idToken) as
|
|
171
|
-
sub: string;
|
|
172
|
-
email: string;
|
|
173
|
-
name: string;
|
|
174
|
-
picture: string;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
const user = {
|
|
178
|
-
id: profile.sub,
|
|
179
|
-
name: profile.name,
|
|
180
|
-
email: profile.email,
|
|
181
|
-
picture: {
|
|
182
|
-
data: {
|
|
183
|
-
url: profile.picture,
|
|
184
|
-
height: 100,
|
|
185
|
-
width: 100,
|
|
186
|
-
is_silhouette: false,
|
|
187
|
-
},
|
|
188
|
-
},
|
|
189
|
-
};
|
|
184
|
+
const profile = decodeJwt(token.idToken) as FacebookLimitedLoginProfile;
|
|
190
185
|
|
|
191
186
|
// https://developers.facebook.com/docs/facebook-login/limited-login/permissions
|
|
192
187
|
// Facebook ID token does not include email_verified claim.
|
|
193
188
|
// We default to false for security consistency.
|
|
194
|
-
const userMap = await options.mapProfileToUser?.(
|
|
195
|
-
...user,
|
|
196
|
-
email_verified: false,
|
|
197
|
-
});
|
|
189
|
+
const userMap = await options.mapProfileToUser?.(profile);
|
|
198
190
|
|
|
199
191
|
return {
|
|
200
192
|
user: {
|
|
201
|
-
|
|
193
|
+
name: profile.name,
|
|
194
|
+
email: profile.email,
|
|
195
|
+
image: profile.picture,
|
|
202
196
|
emailVerified: false,
|
|
203
197
|
...userMap,
|
|
204
198
|
},
|
|
@@ -228,7 +222,7 @@ export const facebook = (options: FacebookOptions) => {
|
|
|
228
222
|
"picture",
|
|
229
223
|
...(options?.fields || []),
|
|
230
224
|
];
|
|
231
|
-
const { data: profile, error } = await betterFetch<
|
|
225
|
+
const { data: profile, error } = await betterFetch<FacebookGraphProfile>(
|
|
232
226
|
"https://graph.facebook.com/me?fields=" + fields.join(","),
|
|
233
227
|
{
|
|
234
228
|
auth: {
|
|
@@ -247,7 +241,6 @@ export const facebook = (options: FacebookOptions) => {
|
|
|
247
241
|
const userMap = await options.mapProfileToUser?.(profile);
|
|
248
242
|
return {
|
|
249
243
|
user: {
|
|
250
|
-
id: profile.id,
|
|
251
244
|
name: profile.name,
|
|
252
245
|
email: profile.email,
|
|
253
246
|
image: profile.picture.data.url,
|
|
@@ -24,6 +24,7 @@ export const figma = (options: FigmaOptions) => {
|
|
|
24
24
|
return {
|
|
25
25
|
id: "figma",
|
|
26
26
|
name: "Figma",
|
|
27
|
+
accountSubject: ({ profile }) => profile.id,
|
|
27
28
|
async createAuthorizationURL({
|
|
28
29
|
state,
|
|
29
30
|
scopes,
|
|
@@ -106,7 +107,6 @@ export const figma = (options: FigmaOptions) => {
|
|
|
106
107
|
|
|
107
108
|
return {
|
|
108
109
|
user: {
|
|
109
|
-
id: profile.id,
|
|
110
110
|
name: profile.handle,
|
|
111
111
|
email: profile.email,
|
|
112
112
|
image: profile.img_url,
|
|
@@ -63,6 +63,7 @@ export const github = (options: GithubOptions) => {
|
|
|
63
63
|
return {
|
|
64
64
|
id: "github",
|
|
65
65
|
name: "GitHub",
|
|
66
|
+
accountSubject: ({ profile }) => profile.id,
|
|
66
67
|
createAuthorizationURL({
|
|
67
68
|
state,
|
|
68
69
|
scopes,
|
|
@@ -171,7 +172,6 @@ export const github = (options: GithubOptions) => {
|
|
|
171
172
|
const userMap = await options.mapProfileToUser?.(profile);
|
|
172
173
|
return {
|
|
173
174
|
user: {
|
|
174
|
-
id: profile.id,
|
|
175
175
|
name: profile.name || profile.login || "",
|
|
176
176
|
email: profile.email,
|
|
177
177
|
image: profile.avatar_url,
|
|
@@ -81,6 +81,7 @@ export const gitlab = (options: GitlabOptions) => {
|
|
|
81
81
|
return {
|
|
82
82
|
id: issuerId,
|
|
83
83
|
name: issuerName,
|
|
84
|
+
accountSubject: ({ profile }) => profile.id,
|
|
84
85
|
createAuthorizationURL: async ({
|
|
85
86
|
state,
|
|
86
87
|
scopes,
|
|
@@ -142,7 +143,6 @@ export const gitlab = (options: GitlabOptions) => {
|
|
|
142
143
|
// We check for it first, then default to false for security consistency.
|
|
143
144
|
return {
|
|
144
145
|
user: {
|
|
145
|
-
id: profile.id,
|
|
146
146
|
name: profile.name ?? profile.username ?? "",
|
|
147
147
|
email: profile.email,
|
|
148
148
|
image: profile.avatar_url,
|
|
@@ -150,6 +150,8 @@ export const google = (options: GoogleOptions) => {
|
|
|
150
150
|
return {
|
|
151
151
|
id: "google",
|
|
152
152
|
name: "Google",
|
|
153
|
+
accountSubject: ({ profile }) => profile.sub,
|
|
154
|
+
accountIssuer: "https://accounts.google.com",
|
|
153
155
|
async createAuthorizationURL({
|
|
154
156
|
state,
|
|
155
157
|
scopes,
|
|
@@ -254,7 +256,6 @@ export const google = (options: GoogleOptions) => {
|
|
|
254
256
|
const userMap = await options.mapProfileToUser?.(user);
|
|
255
257
|
return {
|
|
256
258
|
user: {
|
|
257
|
-
id: user.sub,
|
|
258
259
|
name: user.name,
|
|
259
260
|
email: user.email,
|
|
260
261
|
image: user.picture,
|
|
@@ -47,6 +47,7 @@ export const huggingface = (options: HuggingFaceOptions) => {
|
|
|
47
47
|
return {
|
|
48
48
|
id: "huggingface",
|
|
49
49
|
name: "Hugging Face",
|
|
50
|
+
accountSubject: ({ profile }) => profile.sub,
|
|
50
51
|
createAuthorizationURL({
|
|
51
52
|
state,
|
|
52
53
|
scopes,
|
|
@@ -111,7 +112,6 @@ export const huggingface = (options: HuggingFaceOptions) => {
|
|
|
111
112
|
const userMap = await options.mapProfileToUser?.(profile);
|
|
112
113
|
return {
|
|
113
114
|
user: {
|
|
114
|
-
id: profile.sub,
|
|
115
115
|
name: profile.name || profile.preferred_username || "",
|
|
116
116
|
email: profile.email,
|
|
117
117
|
image: profile.picture,
|
|
@@ -106,6 +106,7 @@ export const kakao = (options: KakaoOptions) => {
|
|
|
106
106
|
return {
|
|
107
107
|
id: "kakao",
|
|
108
108
|
name: "Kakao",
|
|
109
|
+
accountSubject: ({ profile }) => profile.id,
|
|
109
110
|
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
110
111
|
const _scopes = options.disableDefaultScope
|
|
111
112
|
? []
|
|
@@ -162,7 +163,6 @@ export const kakao = (options: KakaoOptions) => {
|
|
|
162
163
|
const account = profile.kakao_account || {};
|
|
163
164
|
const kakaoProfile = account.profile || {};
|
|
164
165
|
const user = {
|
|
165
|
-
id: String(profile.id),
|
|
166
166
|
name: kakaoProfile.nickname || account.name || "",
|
|
167
167
|
email: account.email,
|
|
168
168
|
image:
|
|
@@ -33,6 +33,7 @@ export const kick = (options: KickOptions) => {
|
|
|
33
33
|
return {
|
|
34
34
|
id: "kick",
|
|
35
35
|
name: "Kick",
|
|
36
|
+
accountSubject: ({ profile }) => profile.user_id,
|
|
36
37
|
createAuthorizationURL({
|
|
37
38
|
state,
|
|
38
39
|
scopes,
|
|
@@ -101,7 +102,6 @@ export const kick = (options: KickOptions) => {
|
|
|
101
102
|
// We default to false for security consistency.
|
|
102
103
|
return {
|
|
103
104
|
user: {
|
|
104
|
-
id: profile.user_id,
|
|
105
105
|
name: profile.name,
|
|
106
106
|
email: profile.email,
|
|
107
107
|
image: profile.profile_picture,
|
|
@@ -50,6 +50,8 @@ export const line = (options: LineOptions) => {
|
|
|
50
50
|
return {
|
|
51
51
|
id: "line",
|
|
52
52
|
name: "LINE",
|
|
53
|
+
accountSubject: ({ profile }) => profile.sub,
|
|
54
|
+
accountIssuer: "https://access.line.me",
|
|
53
55
|
async createAuthorizationURL({
|
|
54
56
|
state,
|
|
55
57
|
scopes,
|
|
@@ -142,24 +144,17 @@ export const line = (options: LineOptions) => {
|
|
|
142
144
|
profile = data || null;
|
|
143
145
|
}
|
|
144
146
|
if (!profile) return null;
|
|
145
|
-
const userMap = await options.mapProfileToUser?.(profile
|
|
146
|
-
// ID preference order
|
|
147
|
-
const id = (profile as any).sub || (profile as any).userId;
|
|
148
|
-
const name = (profile as any).name || (profile as any).displayName || "";
|
|
149
|
-
const image =
|
|
150
|
-
(profile as any).picture || (profile as any).pictureUrl || undefined;
|
|
151
|
-
const email = (profile as any).email;
|
|
147
|
+
const userMap = await options.mapProfileToUser?.(profile);
|
|
152
148
|
return {
|
|
153
149
|
user: {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
image,
|
|
150
|
+
name: profile.name || "",
|
|
151
|
+
email: profile.email,
|
|
152
|
+
image: profile.picture,
|
|
158
153
|
// LINE does not expose email verification status in ID token/userinfo
|
|
159
154
|
emailVerified: false,
|
|
160
155
|
...userMap,
|
|
161
156
|
},
|
|
162
|
-
data: profile
|
|
157
|
+
data: profile,
|
|
163
158
|
};
|
|
164
159
|
},
|
|
165
160
|
options,
|
|
@@ -31,6 +31,7 @@ export const linear = (options: LinearOptions) => {
|
|
|
31
31
|
return {
|
|
32
32
|
id: "linear",
|
|
33
33
|
name: "Linear",
|
|
34
|
+
accountSubject: ({ profile }) => profile.id,
|
|
34
35
|
createAuthorizationURL({
|
|
35
36
|
state,
|
|
36
37
|
scopes,
|
|
@@ -113,7 +114,6 @@ export const linear = (options: LinearOptions) => {
|
|
|
113
114
|
// We default to false for security consistency.
|
|
114
115
|
return {
|
|
115
116
|
user: {
|
|
116
|
-
id: profile.data.viewer.id,
|
|
117
117
|
name: profile.data.viewer.name,
|
|
118
118
|
email: profile.data.viewer.email,
|
|
119
119
|
image: profile.data.viewer.avatarUrl,
|
|
@@ -32,6 +32,7 @@ export const linkedin = (options: LinkedInOptions) => {
|
|
|
32
32
|
return {
|
|
33
33
|
id: "linkedin",
|
|
34
34
|
name: "Linkedin",
|
|
35
|
+
accountSubject: ({ profile }) => profile.sub,
|
|
35
36
|
createAuthorizationURL: async ({
|
|
36
37
|
state,
|
|
37
38
|
scopes,
|
|
@@ -97,7 +98,6 @@ export const linkedin = (options: LinkedInOptions) => {
|
|
|
97
98
|
const userMap = await options.mapProfileToUser?.(profile);
|
|
98
99
|
return {
|
|
99
100
|
user: {
|
|
100
|
-
id: profile.sub,
|
|
101
101
|
name: profile.name,
|
|
102
102
|
email: profile.email,
|
|
103
103
|
emailVerified: profile.email_verified ?? false,
|
|
@@ -187,6 +187,8 @@ export const microsoft = (options: MicrosoftOptions) => {
|
|
|
187
187
|
return {
|
|
188
188
|
id: "microsoft",
|
|
189
189
|
name: "Microsoft EntraID",
|
|
190
|
+
accountSubject: ({ profile }) => profile.sub,
|
|
191
|
+
accountIssuer: ({ profile }) => profile.iss,
|
|
190
192
|
createAuthorizationURL(data) {
|
|
191
193
|
// Microsoft Entra supports public clients (SPA / native apps with
|
|
192
194
|
// PKCE only), so clientSecret is intentionally not required here.
|
|
@@ -319,7 +321,6 @@ export const microsoft = (options: MicrosoftOptions) => {
|
|
|
319
321
|
: false;
|
|
320
322
|
return {
|
|
321
323
|
user: {
|
|
322
|
-
id: user.sub,
|
|
323
324
|
name: user.name,
|
|
324
325
|
email: user.email,
|
|
325
326
|
image: user.picture,
|
|
@@ -351,7 +352,7 @@ export const microsoft = (options: MicrosoftOptions) => {
|
|
|
351
352
|
});
|
|
352
353
|
},
|
|
353
354
|
options,
|
|
354
|
-
} satisfies OAuthProvider
|
|
355
|
+
} satisfies OAuthProvider<MicrosoftEntraIDProfile>;
|
|
355
356
|
};
|
|
356
357
|
|
|
357
358
|
export const getMicrosoftPublicKey = async (
|
|
@@ -44,6 +44,7 @@ export const naver = (options: NaverOptions) => {
|
|
|
44
44
|
return {
|
|
45
45
|
id: "naver",
|
|
46
46
|
name: "Naver",
|
|
47
|
+
accountSubject: ({ profile }) => profile.response.id,
|
|
47
48
|
createAuthorizationURL({ state, scopes, redirectURI, additionalParams }) {
|
|
48
49
|
const _scopes = options.disableDefaultScope ? [] : ["profile", "email"];
|
|
49
50
|
if (options.scope) _scopes.push(...options.scope);
|
|
@@ -97,7 +98,6 @@ export const naver = (options: NaverOptions) => {
|
|
|
97
98
|
const userMap = await options.mapProfileToUser?.(profile);
|
|
98
99
|
const res = profile.response || {};
|
|
99
100
|
const user = {
|
|
100
|
-
id: res.id,
|
|
101
101
|
name: res.name || res.nickname || "",
|
|
102
102
|
email: res.email,
|
|
103
103
|
image: res.profile_image,
|
|
@@ -28,6 +28,7 @@ export const notion = (options: NotionOptions) => {
|
|
|
28
28
|
return {
|
|
29
29
|
id: "notion",
|
|
30
30
|
name: "Notion",
|
|
31
|
+
accountSubject: ({ profile }) => profile.id,
|
|
31
32
|
createAuthorizationURL({
|
|
32
33
|
state,
|
|
33
34
|
scopes,
|
|
@@ -100,7 +101,6 @@ export const notion = (options: NotionOptions) => {
|
|
|
100
101
|
const userMap = await options.mapProfileToUser?.(userProfile);
|
|
101
102
|
return {
|
|
102
103
|
user: {
|
|
103
|
-
id: userProfile.id,
|
|
104
104
|
name: userProfile.name || "",
|
|
105
105
|
email: userProfile.person?.email || null,
|
|
106
106
|
image: userProfile.avatar_url,
|