@better-auth/core 1.4.0-beta.9 → 1.4.0
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/.turbo/turbo-build.log +41 -76
- package/dist/api/index.d.mts +3 -0
- package/dist/api/index.mjs +26 -0
- package/dist/async_hooks/index.d.mts +2 -10
- package/dist/async_hooks/index.mjs +2 -24
- package/dist/async_hooks-BfRfbd1J.mjs +18 -0
- package/dist/context/index.d.mts +54 -0
- package/dist/context/index.mjs +4 -0
- package/dist/context-DgQ9XGBl.mjs +114 -0
- package/dist/db/adapter/index.d.mts +3 -14
- package/dist/db/adapter/index.mjs +1 -1
- package/dist/db/index.d.mts +3 -39
- package/dist/db/index.mjs +46 -55
- package/dist/env/index.d.mts +2 -36
- package/dist/env/index.mjs +2 -299
- package/dist/env-DwlNAN_D.mjs +245 -0
- package/dist/error/index.d.mts +31 -29
- package/dist/error/index.mjs +3 -40
- package/dist/error-BhAKg8LX.mjs +45 -0
- package/dist/index-CdubV7uy.d.mts +82 -0
- package/dist/index-CkAWdKH8.d.mts +7352 -0
- package/dist/index-DgwIISs7.d.mts +7 -0
- package/dist/index.d.mts +3 -180
- package/dist/index.mjs +1 -1
- package/dist/oauth2/index.d.mts +3 -99
- package/dist/oauth2/index.mjs +2 -356
- package/dist/oauth2-DmgZmPEg.mjs +236 -0
- package/dist/social-providers/index.d.mts +3 -3903
- package/dist/social-providers/index.mjs +2434 -2654
- package/dist/utils/index.d.mts +5 -6
- package/dist/utils/index.mjs +2 -4
- package/dist/utils-C5EN75oV.mjs +7 -0
- package/package.json +70 -111
- package/src/api/index.ts +53 -0
- package/src/async_hooks/index.ts +1 -9
- package/src/context/endpoint-context.ts +49 -0
- package/src/context/index.ts +21 -0
- package/src/context/request-state.test.ts +94 -0
- package/src/context/request-state.ts +90 -0
- package/src/context/transaction.ts +73 -0
- package/src/db/adapter/index.ts +215 -129
- package/src/db/index.ts +12 -13
- package/src/db/plugin.ts +3 -3
- package/src/db/type.ts +54 -42
- package/src/env/color-depth.ts +5 -4
- package/src/env/env-impl.ts +2 -1
- package/src/env/index.ts +9 -9
- package/src/env/logger.test.ts +3 -2
- package/src/env/logger.ts +11 -9
- package/src/error/codes.ts +1 -1
- package/src/error/index.ts +1 -1
- package/src/oauth2/client-credentials-token.ts +9 -9
- package/src/oauth2/create-authorization-url.ts +12 -12
- package/src/oauth2/index.ts +10 -11
- package/src/oauth2/oauth-provider.ts +96 -74
- package/src/oauth2/refresh-access-token.ts +12 -12
- package/src/oauth2/utils.ts +2 -0
- package/src/oauth2/validate-authorization-code.ts +13 -15
- package/src/social-providers/apple.ts +8 -8
- package/src/social-providers/atlassian.ts +21 -19
- package/src/social-providers/cognito.ts +15 -15
- package/src/social-providers/discord.ts +8 -11
- package/src/social-providers/dropbox.ts +5 -5
- package/src/social-providers/facebook.ts +12 -10
- package/src/social-providers/figma.ts +6 -6
- package/src/social-providers/github.ts +4 -4
- package/src/social-providers/gitlab.ts +13 -10
- package/src/social-providers/google.ts +13 -13
- package/src/social-providers/huggingface.ts +27 -25
- package/src/social-providers/index.ts +30 -24
- package/src/social-providers/kakao.ts +41 -41
- package/src/social-providers/kick.ts +7 -9
- package/src/social-providers/line.ts +12 -12
- package/src/social-providers/linear.ts +9 -8
- package/src/social-providers/linkedin.ts +5 -5
- package/src/social-providers/microsoft-entra-id.ts +31 -15
- package/src/social-providers/naver.ts +5 -5
- package/src/social-providers/notion.ts +11 -9
- package/src/social-providers/paybin.ts +122 -0
- package/src/social-providers/paypal.ts +31 -29
- package/src/social-providers/polar.ts +110 -0
- package/src/social-providers/reddit.ts +6 -6
- package/src/social-providers/roblox.ts +15 -14
- package/src/social-providers/salesforce.ts +20 -18
- package/src/social-providers/slack.ts +4 -7
- package/src/social-providers/spotify.ts +5 -5
- package/src/social-providers/tiktok.ts +32 -33
- package/src/social-providers/twitch.ts +8 -8
- package/src/social-providers/twitter.ts +49 -45
- package/src/social-providers/vk.ts +14 -17
- package/src/social-providers/zoom.ts +29 -14
- package/src/types/context.ts +67 -67
- package/src/types/cookie.ts +1 -0
- package/src/types/index.ts +13 -11
- package/src/types/init-options.ts +1134 -911
- package/src/types/plugin-client.ts +61 -13
- package/src/types/plugin.ts +81 -57
- package/tsconfig.json +2 -5
- package/{build.config.ts → tsdown.config.ts} +8 -11
- package/vitest.config.ts +3 -0
- package/dist/async_hooks/index.cjs +0 -27
- package/dist/async_hooks/index.d.cts +0 -10
- package/dist/async_hooks/index.d.ts +0 -10
- package/dist/db/adapter/index.cjs +0 -2
- package/dist/db/adapter/index.d.cts +0 -14
- package/dist/db/adapter/index.d.ts +0 -14
- package/dist/db/index.cjs +0 -91
- package/dist/db/index.d.cts +0 -39
- package/dist/db/index.d.ts +0 -39
- package/dist/env/index.cjs +0 -315
- package/dist/env/index.d.cts +0 -36
- package/dist/env/index.d.ts +0 -36
- package/dist/error/index.cjs +0 -44
- package/dist/error/index.d.cts +0 -33
- package/dist/error/index.d.ts +0 -33
- package/dist/index.cjs +0 -2
- package/dist/index.d.cts +0 -180
- package/dist/index.d.ts +0 -180
- package/dist/middleware/index.cjs +0 -25
- package/dist/middleware/index.d.cts +0 -14
- package/dist/middleware/index.d.mts +0 -14
- package/dist/middleware/index.d.ts +0 -14
- package/dist/middleware/index.mjs +0 -21
- package/dist/oauth2/index.cjs +0 -368
- package/dist/oauth2/index.d.cts +0 -99
- package/dist/oauth2/index.d.ts +0 -99
- package/dist/shared/core.2rWMW9q9.d.ts +0 -13
- package/dist/shared/core.40VTWh-p.d.cts +0 -217
- package/dist/shared/core.BfcVdsSf.d.cts +0 -181
- package/dist/shared/core.Bisb2Bdk.d.mts +0 -181
- package/dist/shared/core.BwoNUcJQ.d.cts +0 -53
- package/dist/shared/core.BwoNUcJQ.d.mts +0 -53
- package/dist/shared/core.BwoNUcJQ.d.ts +0 -53
- package/dist/shared/core.CErFRCOZ.d.mts +0 -1684
- package/dist/shared/core.CGN6D-Mh.d.ts +0 -181
- package/dist/shared/core.CPuIItYE.d.ts +0 -217
- package/dist/shared/core.CftpHMDz.d.cts +0 -13
- package/dist/shared/core.Db7zJyxf.d.ts +0 -1684
- package/dist/shared/core.DqaxObkf.d.cts +0 -1684
- package/dist/shared/core.MjcDoj7R.d.cts +0 -5
- package/dist/shared/core.MjcDoj7R.d.mts +0 -5
- package/dist/shared/core.MjcDoj7R.d.ts +0 -5
- package/dist/shared/core.g2ZbxAEV.d.mts +0 -217
- package/dist/shared/core.g9ACQ8v2.d.mts +0 -13
- package/dist/social-providers/index.cjs +0 -2793
- package/dist/social-providers/index.d.cts +0 -3903
- package/dist/social-providers/index.d.ts +0 -3903
- package/dist/utils/index.cjs +0 -7
- package/dist/utils/index.d.cts +0 -10
- package/dist/utils/index.d.ts +0 -10
- package/src/middleware/index.ts +0 -33
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
2
|
import { decodeJwt } from "jose";
|
|
3
|
-
import type { OAuthProvider, ProviderOptions } from "
|
|
3
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
4
4
|
import {
|
|
5
5
|
createAuthorizationURL,
|
|
6
6
|
refreshAccessToken,
|
|
7
7
|
validateAuthorizationCode,
|
|
8
|
-
} from "
|
|
8
|
+
} from "../oauth2";
|
|
9
9
|
|
|
10
10
|
export interface LineIdTokenPayload {
|
|
11
11
|
iss: string;
|
|
@@ -13,18 +13,18 @@ export interface LineIdTokenPayload {
|
|
|
13
13
|
aud: string;
|
|
14
14
|
exp: number;
|
|
15
15
|
iat: number;
|
|
16
|
-
name?: string;
|
|
17
|
-
picture?: string;
|
|
18
|
-
email?: string;
|
|
19
|
-
amr?: string[];
|
|
20
|
-
nonce?: string;
|
|
16
|
+
name?: string | undefined;
|
|
17
|
+
picture?: string | undefined;
|
|
18
|
+
email?: string | undefined;
|
|
19
|
+
amr?: string[] | undefined;
|
|
20
|
+
nonce?: string | undefined;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export interface LineUserInfo {
|
|
24
24
|
sub: string;
|
|
25
|
-
name?: string;
|
|
26
|
-
picture?: string;
|
|
27
|
-
email?: string;
|
|
25
|
+
name?: string | undefined;
|
|
26
|
+
picture?: string | undefined;
|
|
27
|
+
email?: string | undefined;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
export interface LineOptions
|
|
@@ -60,8 +60,8 @@ export const line = (options: LineOptions) => {
|
|
|
60
60
|
const _scopes = options.disableDefaultScope
|
|
61
61
|
? []
|
|
62
62
|
: ["openid", "profile", "email"];
|
|
63
|
-
options.scope
|
|
64
|
-
scopes
|
|
63
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
64
|
+
if (scopes) _scopes.push(...scopes);
|
|
65
65
|
return await createAuthorizationURL({
|
|
66
66
|
id: "line",
|
|
67
67
|
options,
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type { OAuthProvider, ProviderOptions } from "
|
|
2
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
6
|
validateAuthorizationCode,
|
|
7
|
-
} from "
|
|
7
|
+
} from "../oauth2";
|
|
8
8
|
|
|
9
|
-
interface LinearUser {
|
|
9
|
+
export interface LinearUser {
|
|
10
10
|
id: string;
|
|
11
11
|
name: string;
|
|
12
12
|
email: string;
|
|
13
|
-
avatarUrl?: string;
|
|
13
|
+
avatarUrl?: string | undefined;
|
|
14
14
|
active: boolean;
|
|
15
15
|
createdAt: string;
|
|
16
16
|
updatedAt: string;
|
|
@@ -33,8 +33,8 @@ export const linear = (options: LinearOptions) => {
|
|
|
33
33
|
name: "Linear",
|
|
34
34
|
createAuthorizationURL({ state, scopes, loginHint, redirectURI }) {
|
|
35
35
|
const _scopes = options.disableDefaultScope ? [] : ["read"];
|
|
36
|
-
options.scope
|
|
37
|
-
scopes
|
|
36
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
37
|
+
if (scopes) _scopes.push(...scopes);
|
|
38
38
|
return createAuthorizationURL({
|
|
39
39
|
id: "linear",
|
|
40
40
|
options,
|
|
@@ -102,14 +102,15 @@ export const linear = (options: LinearOptions) => {
|
|
|
102
102
|
|
|
103
103
|
const userData = profile.data.viewer;
|
|
104
104
|
const userMap = await options.mapProfileToUser?.(userData);
|
|
105
|
-
|
|
105
|
+
// Linear does not provide email_verified claim.
|
|
106
|
+
// We default to false for security consistency.
|
|
106
107
|
return {
|
|
107
108
|
user: {
|
|
108
109
|
id: profile.data.viewer.id,
|
|
109
110
|
name: profile.data.viewer.name,
|
|
110
111
|
email: profile.data.viewer.email,
|
|
111
112
|
image: profile.data.viewer.avatarUrl,
|
|
112
|
-
emailVerified:
|
|
113
|
+
emailVerified: false,
|
|
113
114
|
...userMap,
|
|
114
115
|
},
|
|
115
116
|
data: userData,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type { OAuthProvider, ProviderOptions } from "
|
|
2
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
|
-
validateAuthorizationCode,
|
|
6
5
|
refreshAccessToken,
|
|
7
|
-
|
|
6
|
+
validateAuthorizationCode,
|
|
7
|
+
} from "../oauth2";
|
|
8
8
|
|
|
9
9
|
export interface LinkedInProfile {
|
|
10
10
|
sub: string;
|
|
@@ -41,8 +41,8 @@ export const linkedin = (options: LinkedInOptions) => {
|
|
|
41
41
|
const _scopes = options.disableDefaultScope
|
|
42
42
|
? []
|
|
43
43
|
: ["profile", "email", "openid"];
|
|
44
|
-
options.scope
|
|
45
|
-
scopes
|
|
44
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
45
|
+
if (scopes) _scopes.push(...scopes);
|
|
46
46
|
return await createAuthorizationURL({
|
|
47
47
|
id: "linkedin",
|
|
48
48
|
options,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
+
import { base64 } from "@better-auth/utils/base64";
|
|
2
|
+
import { betterFetch } from "@better-fetch/fetch";
|
|
3
|
+
import { decodeJwt } from "jose";
|
|
4
|
+
import { logger } from "../env";
|
|
5
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
1
6
|
import {
|
|
2
|
-
validateAuthorizationCode,
|
|
3
7
|
createAuthorizationURL,
|
|
4
8
|
refreshAccessToken,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { betterFetch } from "@better-fetch/fetch";
|
|
8
|
-
import { logger } from "@better-auth/core/env";
|
|
9
|
-
import { decodeJwt } from "jose";
|
|
10
|
-
import { base64 } from "@better-auth/utils/base64";
|
|
9
|
+
validateAuthorizationCode,
|
|
10
|
+
} from "../oauth2";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* @see [Microsoft Identity Platform - Optional claims reference](https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims-reference)
|
|
@@ -81,6 +81,8 @@ export interface MicrosoftEntraIDProfile extends Record<string, any> {
|
|
|
81
81
|
verified_primary_email: string[];
|
|
82
82
|
/** User's verified secondary email addresses */
|
|
83
83
|
verified_secondary_email: string[];
|
|
84
|
+
/** Whether the user's email is verified (optional claim, must be configured in app registration) */
|
|
85
|
+
email_verified?: boolean | undefined;
|
|
84
86
|
/** VNET specifier information */
|
|
85
87
|
vnet: string;
|
|
86
88
|
/** Client Capabilities */
|
|
@@ -118,21 +120,23 @@ export interface MicrosoftOptions
|
|
|
118
120
|
* The tenant ID of the Microsoft account
|
|
119
121
|
* @default "common"
|
|
120
122
|
*/
|
|
121
|
-
tenantId?: string;
|
|
123
|
+
tenantId?: string | undefined;
|
|
122
124
|
/**
|
|
123
125
|
* The authentication authority URL. Use the default "https://login.microsoftonline.com" for standard Entra ID or "https://<tenant-id>.ciamlogin.com" for CIAM scenarios.
|
|
124
126
|
* @default "https://login.microsoftonline.com"
|
|
125
127
|
*/
|
|
126
|
-
authority?: string;
|
|
128
|
+
authority?: string | undefined;
|
|
127
129
|
/**
|
|
128
130
|
* The size of the profile photo
|
|
129
131
|
* @default 48
|
|
130
132
|
*/
|
|
131
|
-
profilePhotoSize?:
|
|
133
|
+
profilePhotoSize?:
|
|
134
|
+
| (48 | 64 | 96 | 120 | 240 | 360 | 432 | 504 | 648)
|
|
135
|
+
| undefined;
|
|
132
136
|
/**
|
|
133
137
|
* Disable profile photo
|
|
134
138
|
*/
|
|
135
|
-
disableProfilePhoto?: boolean;
|
|
139
|
+
disableProfilePhoto?: boolean | undefined;
|
|
136
140
|
}
|
|
137
141
|
|
|
138
142
|
export const microsoft = (options: MicrosoftOptions) => {
|
|
@@ -147,8 +151,8 @@ export const microsoft = (options: MicrosoftOptions) => {
|
|
|
147
151
|
const scopes = options.disableDefaultScope
|
|
148
152
|
? []
|
|
149
153
|
: ["openid", "profile", "email", "User.Read", "offline_access"];
|
|
150
|
-
options.scope
|
|
151
|
-
data.scopes
|
|
154
|
+
if (options.scope) scopes.push(...options.scope);
|
|
155
|
+
if (data.scopes) scopes.push(...data.scopes);
|
|
152
156
|
return createAuthorizationURL({
|
|
153
157
|
id: "microsoft",
|
|
154
158
|
options,
|
|
@@ -206,13 +210,25 @@ export const microsoft = (options: MicrosoftOptions) => {
|
|
|
206
210
|
},
|
|
207
211
|
);
|
|
208
212
|
const userMap = await options.mapProfileToUser?.(user);
|
|
213
|
+
// Microsoft Entra ID does NOT include email_verified claim by default.
|
|
214
|
+
// It must be configured as an optional claim in the app registration.
|
|
215
|
+
// We default to false when not provided for security consistency.
|
|
216
|
+
// We can also check verified_primary_email/verified_secondary_email arrays as fallback.
|
|
217
|
+
const emailVerified =
|
|
218
|
+
user.email_verified !== undefined
|
|
219
|
+
? user.email_verified
|
|
220
|
+
: user.email &&
|
|
221
|
+
(user.verified_primary_email?.includes(user.email) ||
|
|
222
|
+
user.verified_secondary_email?.includes(user.email))
|
|
223
|
+
? true
|
|
224
|
+
: false;
|
|
209
225
|
return {
|
|
210
226
|
user: {
|
|
211
227
|
id: user.sub,
|
|
212
228
|
name: user.name,
|
|
213
229
|
email: user.email,
|
|
214
230
|
image: user.picture,
|
|
215
|
-
emailVerified
|
|
231
|
+
emailVerified,
|
|
216
232
|
...userMap,
|
|
217
233
|
},
|
|
218
234
|
data: user,
|
|
@@ -224,7 +240,7 @@ export const microsoft = (options: MicrosoftOptions) => {
|
|
|
224
240
|
const scopes = options.disableDefaultScope
|
|
225
241
|
? []
|
|
226
242
|
: ["openid", "profile", "email", "User.Read", "offline_access"];
|
|
227
|
-
options.scope
|
|
243
|
+
if (options.scope) scopes.push(...options.scope);
|
|
228
244
|
|
|
229
245
|
return refreshAccessToken({
|
|
230
246
|
refreshToken,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type { OAuthProvider, ProviderOptions } from "
|
|
2
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
|
-
validateAuthorizationCode,
|
|
6
5
|
refreshAccessToken,
|
|
7
|
-
|
|
6
|
+
validateAuthorizationCode,
|
|
7
|
+
} from "../oauth2";
|
|
8
8
|
|
|
9
9
|
export interface NaverProfile {
|
|
10
10
|
/** API response result code */
|
|
@@ -45,8 +45,8 @@ export const naver = (options: NaverOptions) => {
|
|
|
45
45
|
name: "Naver",
|
|
46
46
|
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
47
47
|
const _scopes = options.disableDefaultScope ? [] : ["profile", "email"];
|
|
48
|
-
options.scope
|
|
49
|
-
scopes
|
|
48
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
49
|
+
if (scopes) _scopes.push(...scopes);
|
|
50
50
|
return createAuthorizationURL({
|
|
51
51
|
id: "naver",
|
|
52
52
|
options,
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type { OAuthProvider, ProviderOptions } from "
|
|
2
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
3
|
import {
|
|
4
4
|
createAuthorizationURL,
|
|
5
5
|
refreshAccessToken,
|
|
6
6
|
validateAuthorizationCode,
|
|
7
|
-
} from "
|
|
7
|
+
} from "../oauth2";
|
|
8
8
|
|
|
9
9
|
export interface NotionProfile {
|
|
10
10
|
object: "user";
|
|
11
11
|
id: string;
|
|
12
12
|
type: "person" | "bot";
|
|
13
|
-
name?: string;
|
|
14
|
-
avatar_url?: string;
|
|
15
|
-
person?:
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
name?: string | undefined;
|
|
14
|
+
avatar_url?: string | undefined;
|
|
15
|
+
person?:
|
|
16
|
+
| {
|
|
17
|
+
email?: string;
|
|
18
|
+
}
|
|
19
|
+
| undefined;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
export interface NotionOptions extends ProviderOptions<NotionProfile> {
|
|
@@ -28,8 +30,8 @@ export const notion = (options: NotionOptions) => {
|
|
|
28
30
|
name: "Notion",
|
|
29
31
|
createAuthorizationURL({ state, scopes, loginHint, redirectURI }) {
|
|
30
32
|
const _scopes: string[] = options.disableDefaultScope ? [] : [];
|
|
31
|
-
options.scope
|
|
32
|
-
scopes
|
|
33
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
34
|
+
if (scopes) _scopes.push(...scopes);
|
|
33
35
|
return createAuthorizationURL({
|
|
34
36
|
id: "notion",
|
|
35
37
|
options,
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { decodeJwt } from "jose";
|
|
2
|
+
import { logger } from "../env";
|
|
3
|
+
import { BetterAuthError } from "../error";
|
|
4
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
5
|
+
import {
|
|
6
|
+
createAuthorizationURL,
|
|
7
|
+
refreshAccessToken,
|
|
8
|
+
validateAuthorizationCode,
|
|
9
|
+
} from "../oauth2";
|
|
10
|
+
|
|
11
|
+
export interface PaybinProfile {
|
|
12
|
+
sub: string;
|
|
13
|
+
email: string;
|
|
14
|
+
email_verified?: boolean | undefined;
|
|
15
|
+
name?: string | undefined;
|
|
16
|
+
preferred_username?: string | undefined;
|
|
17
|
+
picture?: string | undefined;
|
|
18
|
+
given_name?: string | undefined;
|
|
19
|
+
family_name?: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface PaybinOptions extends ProviderOptions<PaybinProfile> {
|
|
23
|
+
clientId: string;
|
|
24
|
+
/**
|
|
25
|
+
* The issuer URL of your Paybin OAuth server
|
|
26
|
+
* @default "https://idp.paybin.io"
|
|
27
|
+
*/
|
|
28
|
+
issuer?: string | undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const paybin = (options: PaybinOptions) => {
|
|
32
|
+
const issuer = options.issuer || "https://idp.paybin.io";
|
|
33
|
+
const authorizationEndpoint = `${issuer}/oauth2/authorize`;
|
|
34
|
+
const tokenEndpoint = `${issuer}/oauth2/token`;
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
id: "paybin",
|
|
38
|
+
name: "Paybin",
|
|
39
|
+
async createAuthorizationURL({
|
|
40
|
+
state,
|
|
41
|
+
scopes,
|
|
42
|
+
codeVerifier,
|
|
43
|
+
redirectURI,
|
|
44
|
+
loginHint,
|
|
45
|
+
}) {
|
|
46
|
+
if (!options.clientId || !options.clientSecret) {
|
|
47
|
+
logger.error(
|
|
48
|
+
"Client Id and Client Secret is required for Paybin. Make sure to provide them in the options.",
|
|
49
|
+
);
|
|
50
|
+
throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
|
|
51
|
+
}
|
|
52
|
+
if (!codeVerifier) {
|
|
53
|
+
throw new BetterAuthError("codeVerifier is required for Paybin");
|
|
54
|
+
}
|
|
55
|
+
const _scopes = options.disableDefaultScope
|
|
56
|
+
? []
|
|
57
|
+
: ["openid", "email", "profile"];
|
|
58
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
59
|
+
if (scopes) _scopes.push(...scopes);
|
|
60
|
+
const url = await createAuthorizationURL({
|
|
61
|
+
id: "paybin",
|
|
62
|
+
options,
|
|
63
|
+
authorizationEndpoint,
|
|
64
|
+
scopes: _scopes,
|
|
65
|
+
state,
|
|
66
|
+
codeVerifier,
|
|
67
|
+
redirectURI,
|
|
68
|
+
prompt: options.prompt,
|
|
69
|
+
loginHint,
|
|
70
|
+
});
|
|
71
|
+
return url;
|
|
72
|
+
},
|
|
73
|
+
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
74
|
+
return validateAuthorizationCode({
|
|
75
|
+
code,
|
|
76
|
+
codeVerifier,
|
|
77
|
+
redirectURI,
|
|
78
|
+
options,
|
|
79
|
+
tokenEndpoint,
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
refreshAccessToken: options.refreshAccessToken
|
|
83
|
+
? options.refreshAccessToken
|
|
84
|
+
: async (refreshToken) => {
|
|
85
|
+
return refreshAccessToken({
|
|
86
|
+
refreshToken,
|
|
87
|
+
options: {
|
|
88
|
+
clientId: options.clientId,
|
|
89
|
+
clientKey: options.clientKey,
|
|
90
|
+
clientSecret: options.clientSecret,
|
|
91
|
+
},
|
|
92
|
+
tokenEndpoint,
|
|
93
|
+
});
|
|
94
|
+
},
|
|
95
|
+
async getUserInfo(token) {
|
|
96
|
+
if (options.getUserInfo) {
|
|
97
|
+
return options.getUserInfo(token);
|
|
98
|
+
}
|
|
99
|
+
if (!token.idToken) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
const user = decodeJwt(token.idToken) as PaybinProfile;
|
|
103
|
+
const userMap = await options.mapProfileToUser?.(user);
|
|
104
|
+
return {
|
|
105
|
+
user: {
|
|
106
|
+
id: user.sub,
|
|
107
|
+
name:
|
|
108
|
+
user.name ||
|
|
109
|
+
user.preferred_username ||
|
|
110
|
+
(user.email ? user.email.split("@")[0] : "User") ||
|
|
111
|
+
"User",
|
|
112
|
+
email: user.email,
|
|
113
|
+
image: user.picture,
|
|
114
|
+
emailVerified: user.email_verified || false,
|
|
115
|
+
...userMap,
|
|
116
|
+
},
|
|
117
|
+
data: user,
|
|
118
|
+
};
|
|
119
|
+
},
|
|
120
|
+
options,
|
|
121
|
+
} satisfies OAuthProvider<PaybinProfile>;
|
|
122
|
+
};
|
|
@@ -1,46 +1,48 @@
|
|
|
1
|
+
import { base64 } from "@better-auth/utils/base64";
|
|
1
2
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import { BetterAuthError } from "../error";
|
|
3
|
-
import type { OAuthProvider, ProviderOptions } from "@better-auth/core/oauth2";
|
|
4
|
-
import { createAuthorizationURL } from "@better-auth/core/oauth2";
|
|
5
|
-
import { logger } from "@better-auth/core/env";
|
|
6
3
|
import { decodeJwt } from "jose";
|
|
7
|
-
import {
|
|
4
|
+
import { logger } from "../env";
|
|
5
|
+
import { BetterAuthError } from "../error";
|
|
6
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
7
|
+
import { createAuthorizationURL } from "../oauth2";
|
|
8
8
|
|
|
9
9
|
export interface PayPalProfile {
|
|
10
10
|
user_id: string;
|
|
11
11
|
name: string;
|
|
12
12
|
given_name: string;
|
|
13
13
|
family_name: string;
|
|
14
|
-
middle_name?: string;
|
|
15
|
-
picture?: string;
|
|
14
|
+
middle_name?: string | undefined;
|
|
15
|
+
picture?: string | undefined;
|
|
16
16
|
email: string;
|
|
17
17
|
email_verified: boolean;
|
|
18
|
-
gender?: string;
|
|
19
|
-
birthdate?: string;
|
|
20
|
-
zoneinfo?: string;
|
|
21
|
-
locale?: string;
|
|
22
|
-
phone_number?: string;
|
|
23
|
-
address?:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
18
|
+
gender?: string | undefined;
|
|
19
|
+
birthdate?: string | undefined;
|
|
20
|
+
zoneinfo?: string | undefined;
|
|
21
|
+
locale?: string | undefined;
|
|
22
|
+
phone_number?: string | undefined;
|
|
23
|
+
address?:
|
|
24
|
+
| {
|
|
25
|
+
street_address?: string;
|
|
26
|
+
locality?: string;
|
|
27
|
+
region?: string;
|
|
28
|
+
postal_code?: string;
|
|
29
|
+
country?: string;
|
|
30
|
+
}
|
|
31
|
+
| undefined;
|
|
32
|
+
verified_account?: boolean | undefined;
|
|
33
|
+
account_type?: string | undefined;
|
|
34
|
+
age_range?: string | undefined;
|
|
35
|
+
payer_id?: string | undefined;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
export interface PayPalTokenResponse {
|
|
37
|
-
scope?: string;
|
|
39
|
+
scope?: string | undefined;
|
|
38
40
|
access_token: string;
|
|
39
|
-
refresh_token?: string;
|
|
41
|
+
refresh_token?: string | undefined;
|
|
40
42
|
token_type: "Bearer";
|
|
41
|
-
id_token?: string;
|
|
43
|
+
id_token?: string | undefined;
|
|
42
44
|
expires_in: number;
|
|
43
|
-
nonce?: string;
|
|
45
|
+
nonce?: string | undefined;
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
export interface PayPalOptions extends ProviderOptions<PayPalProfile> {
|
|
@@ -49,12 +51,12 @@ export interface PayPalOptions extends ProviderOptions<PayPalProfile> {
|
|
|
49
51
|
* PayPal environment - 'sandbox' for testing, 'live' for production
|
|
50
52
|
* @default 'sandbox'
|
|
51
53
|
*/
|
|
52
|
-
environment?: "sandbox" | "live";
|
|
54
|
+
environment?: ("sandbox" | "live") | undefined;
|
|
53
55
|
/**
|
|
54
56
|
* Whether to request shipping address information
|
|
55
57
|
* @default false
|
|
56
58
|
*/
|
|
57
|
-
requestShippingAddress?: boolean;
|
|
59
|
+
requestShippingAddress?: boolean | undefined;
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
export const paypal = (options: PayPalOptions) => {
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
|
+
import {
|
|
4
|
+
createAuthorizationURL,
|
|
5
|
+
refreshAccessToken,
|
|
6
|
+
validateAuthorizationCode,
|
|
7
|
+
} from "../oauth2";
|
|
8
|
+
|
|
9
|
+
export interface PolarProfile {
|
|
10
|
+
id: string;
|
|
11
|
+
email: string;
|
|
12
|
+
username: string;
|
|
13
|
+
avatar_url: string;
|
|
14
|
+
github_username?: string | undefined;
|
|
15
|
+
account_id?: string | undefined;
|
|
16
|
+
public_name?: string | undefined;
|
|
17
|
+
email_verified?: boolean | undefined;
|
|
18
|
+
profile_settings?:
|
|
19
|
+
| {
|
|
20
|
+
profile_settings_enabled?: boolean;
|
|
21
|
+
profile_settings_public_name?: string;
|
|
22
|
+
profile_settings_public_avatar?: string;
|
|
23
|
+
profile_settings_public_bio?: string;
|
|
24
|
+
profile_settings_public_location?: string;
|
|
25
|
+
profile_settings_public_website?: string;
|
|
26
|
+
profile_settings_public_twitter?: string;
|
|
27
|
+
profile_settings_public_github?: string;
|
|
28
|
+
profile_settings_public_email?: string;
|
|
29
|
+
}
|
|
30
|
+
| undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface PolarOptions extends ProviderOptions<PolarProfile> {}
|
|
34
|
+
|
|
35
|
+
export const polar = (options: PolarOptions) => {
|
|
36
|
+
return {
|
|
37
|
+
id: "polar",
|
|
38
|
+
name: "Polar",
|
|
39
|
+
createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
|
|
40
|
+
const _scopes = options.disableDefaultScope
|
|
41
|
+
? []
|
|
42
|
+
: ["openid", "profile", "email"];
|
|
43
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
44
|
+
if (scopes) _scopes.push(...scopes);
|
|
45
|
+
return createAuthorizationURL({
|
|
46
|
+
id: "polar",
|
|
47
|
+
options,
|
|
48
|
+
authorizationEndpoint: "https://polar.sh/oauth2/authorize",
|
|
49
|
+
scopes: _scopes,
|
|
50
|
+
state,
|
|
51
|
+
codeVerifier,
|
|
52
|
+
redirectURI,
|
|
53
|
+
prompt: options.prompt,
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
validateAuthorizationCode: async ({ code, codeVerifier, redirectURI }) => {
|
|
57
|
+
return validateAuthorizationCode({
|
|
58
|
+
code,
|
|
59
|
+
codeVerifier,
|
|
60
|
+
redirectURI,
|
|
61
|
+
options,
|
|
62
|
+
tokenEndpoint: "https://api.polar.sh/v1/oauth2/token",
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
refreshAccessToken: options.refreshAccessToken
|
|
66
|
+
? options.refreshAccessToken
|
|
67
|
+
: async (refreshToken) => {
|
|
68
|
+
return refreshAccessToken({
|
|
69
|
+
refreshToken,
|
|
70
|
+
options: {
|
|
71
|
+
clientId: options.clientId,
|
|
72
|
+
clientKey: options.clientKey,
|
|
73
|
+
clientSecret: options.clientSecret,
|
|
74
|
+
},
|
|
75
|
+
tokenEndpoint: "https://api.polar.sh/v1/oauth2/token",
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
async getUserInfo(token) {
|
|
79
|
+
if (options.getUserInfo) {
|
|
80
|
+
return options.getUserInfo(token);
|
|
81
|
+
}
|
|
82
|
+
const { data: profile, error } = await betterFetch<PolarProfile>(
|
|
83
|
+
"https://api.polar.sh/v1/oauth2/userinfo",
|
|
84
|
+
{
|
|
85
|
+
headers: {
|
|
86
|
+
Authorization: `Bearer ${token.accessToken}`,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
if (error) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const userMap = await options.mapProfileToUser?.(profile);
|
|
94
|
+
// Polar may provide email_verified claim, but it's not guaranteed.
|
|
95
|
+
// We check for it first, then default to false for security consistency.
|
|
96
|
+
return {
|
|
97
|
+
user: {
|
|
98
|
+
id: profile.id,
|
|
99
|
+
name: profile.public_name || profile.username,
|
|
100
|
+
email: profile.email,
|
|
101
|
+
image: profile.avatar_url,
|
|
102
|
+
emailVerified: profile.email_verified ?? false,
|
|
103
|
+
...userMap,
|
|
104
|
+
},
|
|
105
|
+
data: profile,
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
options,
|
|
109
|
+
} satisfies OAuthProvider<PolarProfile>;
|
|
110
|
+
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
+
import { base64 } from "@better-auth/utils/base64";
|
|
1
2
|
import { betterFetch } from "@better-fetch/fetch";
|
|
2
|
-
import type { OAuthProvider, ProviderOptions } from "
|
|
3
|
+
import type { OAuthProvider, ProviderOptions } from "../oauth2";
|
|
3
4
|
import {
|
|
4
5
|
createAuthorizationURL,
|
|
5
6
|
getOAuth2Tokens,
|
|
6
7
|
refreshAccessToken,
|
|
7
|
-
} from "
|
|
8
|
-
import { base64 } from "@better-auth/utils/base64";
|
|
8
|
+
} from "../oauth2";
|
|
9
9
|
|
|
10
10
|
export interface RedditProfile {
|
|
11
11
|
id: string;
|
|
@@ -18,7 +18,7 @@ export interface RedditProfile {
|
|
|
18
18
|
|
|
19
19
|
export interface RedditOptions extends ProviderOptions<RedditProfile> {
|
|
20
20
|
clientId: string;
|
|
21
|
-
duration?: string;
|
|
21
|
+
duration?: string | undefined;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
export const reddit = (options: RedditOptions) => {
|
|
@@ -27,8 +27,8 @@ export const reddit = (options: RedditOptions) => {
|
|
|
27
27
|
name: "Reddit",
|
|
28
28
|
createAuthorizationURL({ state, scopes, redirectURI }) {
|
|
29
29
|
const _scopes = options.disableDefaultScope ? [] : ["identity"];
|
|
30
|
-
options.scope
|
|
31
|
-
scopes
|
|
30
|
+
if (options.scope) _scopes.push(...options.scope);
|
|
31
|
+
if (scopes) _scopes.push(...scopes);
|
|
32
32
|
return createAuthorizationURL({
|
|
33
33
|
id: "reddit",
|
|
34
34
|
options,
|