@lobehub/lobehub 2.0.0-next.355 → 2.0.0-next.357
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/.env.desktop +0 -1
- package/.env.example +16 -20
- package/.env.example.development +1 -4
- package/.github/workflows/e2e.yml +10 -11
- package/CHANGELOG.md +60 -0
- package/Dockerfile +28 -4
- package/changelog/v1.json +18 -0
- package/docker-compose/local/docker-compose.yml +2 -2
- package/docker-compose/local/grafana/docker-compose.yml +2 -2
- package/docker-compose/local/logto/docker-compose.yml +2 -2
- package/docker-compose/local/zitadel/.env.example +2 -2
- package/docker-compose/local/zitadel/.env.zh-CN.example +2 -2
- package/docker-compose/production/grafana/docker-compose.yml +2 -2
- package/docker-compose/production/logto/.env.example +2 -2
- package/docker-compose/production/logto/.env.zh-CN.example +2 -2
- package/docker-compose/production/zitadel/.env.example +2 -2
- package/docker-compose/production/zitadel/.env.zh-CN.example +2 -2
- package/docs/development/basic/add-new-authentication-providers.mdx +144 -136
- package/docs/development/basic/add-new-authentication-providers.zh-CN.mdx +146 -136
- package/docs/self-hosting/advanced/auth/legacy.mdx +4 -0
- package/docs/self-hosting/advanced/auth/legacy.zh-CN.mdx +4 -0
- package/docs/self-hosting/advanced/auth/nextauth-to-betterauth.mdx +326 -0
- package/docs/self-hosting/advanced/auth/nextauth-to-betterauth.zh-CN.mdx +323 -0
- package/docs/self-hosting/advanced/auth.mdx +43 -16
- package/docs/self-hosting/advanced/auth.zh-CN.mdx +44 -16
- package/docs/self-hosting/advanced/redis/upstash.mdx +69 -0
- package/docs/self-hosting/advanced/redis/upstash.zh-CN.mdx +69 -0
- package/docs/self-hosting/advanced/redis.mdx +128 -0
- package/docs/self-hosting/advanced/redis.zh-CN.mdx +126 -0
- package/docs/self-hosting/environment-variables/auth.mdx +15 -1
- package/docs/self-hosting/environment-variables/auth.zh-CN.mdx +15 -1
- package/docs/self-hosting/environment-variables/basic.mdx +13 -0
- package/docs/self-hosting/environment-variables/basic.zh-CN.mdx +13 -0
- package/docs/self-hosting/environment-variables/redis.mdx +68 -0
- package/docs/self-hosting/environment-variables/redis.zh-CN.mdx +67 -0
- package/docs/self-hosting/migration/v2/breaking-changes.mdx +23 -23
- package/docs/self-hosting/migration/v2/breaking-changes.zh-CN.mdx +23 -23
- package/docs/self-hosting/server-database/docker-compose.mdx +4 -4
- package/docs/self-hosting/server-database/docker-compose.zh-CN.mdx +4 -4
- package/e2e/CLAUDE.md +5 -6
- package/e2e/docs/local-setup.md +9 -12
- package/e2e/scripts/setup.ts +9 -15
- package/e2e/src/support/webServer.ts +6 -5
- package/package.json +4 -6
- package/packages/database/src/schemas/nextauth.ts +7 -2
- package/packages/model-runtime/src/core/contextBuilders/anthropic.test.ts +370 -0
- package/packages/model-runtime/src/core/contextBuilders/anthropic.ts +18 -5
- package/packages/utils/src/server/__tests__/auth.test.ts +1 -63
- package/packages/utils/src/server/auth.ts +8 -24
- package/scripts/_shared/checkDeprecatedAuth.js +99 -0
- package/scripts/clerk-to-betterauth/index.ts +8 -3
- package/scripts/nextauth-to-betterauth/_internal/config.ts +41 -0
- package/scripts/nextauth-to-betterauth/_internal/db.ts +32 -0
- package/scripts/nextauth-to-betterauth/_internal/env.ts +6 -0
- package/scripts/nextauth-to-betterauth/index.ts +226 -0
- package/scripts/nextauth-to-betterauth/verify.ts +188 -0
- package/scripts/prebuild.mts +66 -13
- package/scripts/serverLauncher/startServer.js +5 -5
- package/src/app/(backend)/api/auth/[...all]/route.ts +5 -23
- package/src/app/(backend)/api/webhooks/casdoor/route.ts +5 -5
- package/src/app/(backend)/api/webhooks/logto/route.ts +8 -8
- package/src/app/(backend)/middleware/auth/index.test.ts +8 -1
- package/src/app/(backend)/middleware/auth/index.ts +6 -15
- package/src/app/(backend)/middleware/auth/utils.test.ts +0 -32
- package/src/app/(backend)/middleware/auth/utils.ts +3 -8
- package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +8 -1
- package/src/app/(backend)/webapi/create-image/comfyui/route.ts +0 -1
- package/src/app/(backend)/webapi/models/[provider]/route.test.ts +8 -1
- package/src/app/[variants]/(auth)/signin/SignInEmailStep.tsx +1 -1
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +4 -17
- package/src/app/[variants]/(main)/agent/cron/[cronId]/features/CronJobContentEditor.tsx +34 -21
- package/src/app/[variants]/(main)/settings/profile/features/SSOProvidersList/index.tsx +12 -19
- package/src/app/[variants]/(main)/settings/profile/index.tsx +8 -14
- package/src/components/{NextAuth/AuthIcons.tsx → AuthIcons.tsx} +8 -10
- package/src/envs/auth.ts +12 -51
- package/src/envs/email.ts +3 -0
- package/src/envs/redis.ts +12 -54
- package/src/features/ChatInput/ChatInputProvider.tsx +22 -2
- package/src/features/ChatInput/InputEditor/index.tsx +14 -3
- package/src/features/ChatInput/store/initialState.ts +2 -0
- package/src/features/EditorCanvas/DiffAllToolbar.tsx +4 -5
- package/src/features/EditorCanvas/DocumentIdMode.tsx +21 -1
- package/src/features/User/__tests__/PanelContent.test.tsx +0 -11
- package/src/features/User/__tests__/UserAvatar.test.tsx +1 -16
- package/src/layout/AuthProvider/index.tsx +1 -6
- package/src/layout/GlobalProvider/StoreInitialization.tsx +2 -4
- package/src/libs/better-auth/define-config.ts +2 -0
- package/src/libs/better-auth/plugins/email-whitelist.test.ts +120 -0
- package/src/libs/better-auth/plugins/email-whitelist.ts +62 -0
- package/src/libs/next/config/define-config.ts +13 -1
- package/src/libs/next/proxy/define-config.ts +2 -75
- package/src/libs/oidc-provider/provider.test.ts +0 -4
- package/src/libs/redis/index.ts +0 -1
- package/src/libs/redis/manager.test.ts +9 -45
- package/src/libs/redis/manager.ts +2 -16
- package/src/libs/redis/redis.test.ts +2 -4
- package/src/libs/redis/redis.ts +2 -4
- package/src/libs/redis/types.ts +2 -24
- package/src/libs/redis/utils.test.ts +0 -10
- package/src/libs/redis/utils.ts +0 -19
- package/src/libs/trpc/lambda/context.test.ts +0 -13
- package/src/libs/trpc/lambda/context.ts +21 -59
- package/src/libs/trpc/middleware/userAuth.ts +1 -7
- package/src/libs/trusted-client/getSessionUser.ts +15 -35
- package/src/server/globalConfig/index.ts +1 -3
- package/src/server/routers/lambda/__tests__/user.test.ts +0 -48
- package/src/server/routers/lambda/user.ts +1 -12
- package/src/server/services/email/impls/nodemailer/index.ts +2 -2
- package/src/server/services/webhookUser/index.ts +88 -0
- package/src/services/user/index.test.ts +0 -14
- package/src/services/user/index.ts +0 -4
- package/src/store/document/slices/document/action.ts +1 -0
- package/src/store/user/slices/auth/action.test.ts +22 -126
- package/src/store/user/slices/auth/action.ts +32 -65
- package/src/store/user/slices/auth/initialState.ts +0 -3
- package/src/store/user/slices/auth/selectors.ts +0 -3
- package/tests/setup.ts +10 -0
- package/scripts/_shared/checkDeprecatedClerkEnv.js +0 -42
- package/src/app/(backend)/api/auth/adapter/route.ts +0 -137
- package/src/app/[variants]/(auth)/next-auth/error/AuthErrorPage.tsx +0 -40
- package/src/app/[variants]/(auth)/next-auth/error/page.tsx +0 -11
- package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +0 -167
- package/src/app/[variants]/(auth)/next-auth/signin/page.tsx +0 -11
- package/src/app/[variants]/(auth)/reset-password/layout.tsx +0 -12
- package/src/app/[variants]/(auth)/signin/layout.tsx +0 -12
- package/src/app/[variants]/(auth)/verify-email/layout.tsx +0 -12
- package/src/envs/auth.test.ts +0 -47
- package/src/layout/AuthProvider/NextAuth/UserUpdater.tsx +0 -44
- package/src/layout/AuthProvider/NextAuth/index.tsx +0 -17
- package/src/libs/next-auth/adapter/index.ts +0 -177
- package/src/libs/next-auth/auth.config.ts +0 -64
- package/src/libs/next-auth/index.ts +0 -20
- package/src/libs/next-auth/sso-providers/auth0.ts +0 -24
- package/src/libs/next-auth/sso-providers/authelia.ts +0 -39
- package/src/libs/next-auth/sso-providers/authentik.ts +0 -25
- package/src/libs/next-auth/sso-providers/casdoor.ts +0 -50
- package/src/libs/next-auth/sso-providers/cloudflare-zero-trust.ts +0 -34
- package/src/libs/next-auth/sso-providers/cognito.ts +0 -8
- package/src/libs/next-auth/sso-providers/feishu.ts +0 -83
- package/src/libs/next-auth/sso-providers/generic-oidc.ts +0 -38
- package/src/libs/next-auth/sso-providers/github.ts +0 -23
- package/src/libs/next-auth/sso-providers/google.ts +0 -18
- package/src/libs/next-auth/sso-providers/index.ts +0 -35
- package/src/libs/next-auth/sso-providers/keycloak.ts +0 -22
- package/src/libs/next-auth/sso-providers/logto.ts +0 -48
- package/src/libs/next-auth/sso-providers/microsoft-entra-id-helper.ts +0 -29
- package/src/libs/next-auth/sso-providers/microsoft-entra-id.ts +0 -19
- package/src/libs/next-auth/sso-providers/okta.ts +0 -22
- package/src/libs/next-auth/sso-providers/sso.config.ts +0 -8
- package/src/libs/next-auth/sso-providers/wechat.ts +0 -36
- package/src/libs/next-auth/sso-providers/zitadel.ts +0 -21
- package/src/libs/redis/upstash.test.ts +0 -158
- package/src/libs/redis/upstash.ts +0 -136
- package/src/server/services/nextAuthUser/index.ts +0 -318
- package/src/server/services/nextAuthUser/utils.ts +0 -62
- package/src/types/next-auth.d.ts +0 -26
|
@@ -4,184 +4,192 @@ title: New Authentication Provider Guide
|
|
|
4
4
|
|
|
5
5
|
# New Authentication Provider Guide
|
|
6
6
|
|
|
7
|
-
LobeChat uses [Auth
|
|
7
|
+
LobeChat uses [Better Auth](https://www.better-auth.com) as its authentication service. This document explains how to add new SSO authentication providers.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Architecture Overview
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Better Auth SSO providers fall into two categories:
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
| Type | Description | Examples |
|
|
14
|
+
| --------- | ------------------------------------------- | -------------------------------- |
|
|
15
|
+
| `builtin` | Providers natively supported by Better Auth | Google, GitHub, Microsoft, Apple |
|
|
16
|
+
| `generic` | Implemented via Generic OIDC/OAuth plugin | Okta, Auth0, Keycloak, etc. |
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
## Adding a New SSO Provider
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
Using **Okta** as an example, here's how to add a `generic` type provider.
|
|
18
21
|
|
|
19
|
-
### Step 1:
|
|
22
|
+
### Step 1: Create Provider Definition File
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
Create `okta.ts` in `src/libs/better-auth/sso/providers/`:
|
|
22
25
|
|
|
23
26
|
```ts
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
import
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
import { authEnv } from '@/envs/auth';
|
|
28
|
+
|
|
29
|
+
import { buildOidcConfig } from '../helpers';
|
|
30
|
+
import type { GenericProviderDefinition } from '../types';
|
|
31
|
+
|
|
32
|
+
const provider: GenericProviderDefinition<{
|
|
33
|
+
AUTH_OKTA_ID: string;
|
|
34
|
+
AUTH_OKTA_ISSUER: string;
|
|
35
|
+
AUTH_OKTA_SECRET: string;
|
|
36
|
+
}> = {
|
|
37
|
+
// Build OIDC configuration
|
|
38
|
+
build: (env) =>
|
|
39
|
+
buildOidcConfig({
|
|
40
|
+
clientId: env.AUTH_OKTA_ID,
|
|
41
|
+
clientSecret: env.AUTH_OKTA_SECRET,
|
|
42
|
+
issuer: env.AUTH_OKTA_ISSUER,
|
|
43
|
+
overrides: {
|
|
44
|
+
// Optional: customize user profile mapping
|
|
45
|
+
mapProfileToUser: (profile) => ({
|
|
46
|
+
email: profile.email,
|
|
47
|
+
name: profile.name ?? profile.preferred_username ?? profile.email ?? profile.sub,
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
providerId: 'okta',
|
|
51
|
+
}),
|
|
32
52
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
53
|
+
// Environment variable validation
|
|
54
|
+
checkEnvs: () => {
|
|
55
|
+
return !!(authEnv.AUTH_OKTA_ID && authEnv.AUTH_OKTA_SECRET && authEnv.AUTH_OKTA_ISSUER)
|
|
56
|
+
? {
|
|
57
|
+
AUTH_OKTA_ID: authEnv.AUTH_OKTA_ID,
|
|
58
|
+
AUTH_OKTA_ISSUER: authEnv.AUTH_OKTA_ISSUER,
|
|
59
|
+
AUTH_OKTA_SECRET: authEnv.AUTH_OKTA_SECRET,
|
|
60
|
+
}
|
|
61
|
+
: false;
|
|
62
|
+
},
|
|
36
63
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
64
|
+
// Provider ID (used in AUTH_SSO_PROVIDERS)
|
|
65
|
+
id: 'okta',
|
|
66
|
+
type: 'generic',
|
|
67
|
+
};
|
|
40
68
|
|
|
41
|
-
|
|
42
|
-
clientId: OKTA_CLIENT_ID,
|
|
43
|
-
clientSecret: OKTA_CLIENT_SECRET,
|
|
44
|
-
issuer: OKTA_ISSUER,
|
|
45
|
-
}),
|
|
46
|
-
],
|
|
47
|
-
});
|
|
69
|
+
export default provider;
|
|
48
70
|
```
|
|
49
71
|
|
|
50
|
-
### Step 2:
|
|
72
|
+
### Step 2: Register the Provider
|
|
51
73
|
|
|
52
|
-
|
|
74
|
+
Import and register in `src/libs/better-auth/sso/index.ts`:
|
|
53
75
|
|
|
54
76
|
```ts
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
OKTA_ISSUER: process.env.OKTA_ISSUER || '',
|
|
64
|
-
};
|
|
65
|
-
};
|
|
77
|
+
// Import provider
|
|
78
|
+
import Okta from './providers/okta';
|
|
79
|
+
|
|
80
|
+
// Add to providerDefinitions array
|
|
81
|
+
const providerDefinitions = [
|
|
82
|
+
// ... other providers
|
|
83
|
+
Okta,
|
|
84
|
+
] as const;
|
|
66
85
|
```
|
|
67
86
|
|
|
68
|
-
### Step 3:
|
|
69
|
-
|
|
70
|
-
Modify the `signIn` function parameter in `src/Features/Conversation/Error/OAuthForm.tsx` and \`src/app/settings/common/Common.tsx
|
|
87
|
+
### Step 3: Add Environment Variable Types
|
|
71
88
|
|
|
72
|
-
|
|
89
|
+
Add type declarations in `src/envs/auth.ts`:
|
|
73
90
|
|
|
74
|
-
|
|
91
|
+
```ts
|
|
92
|
+
// Add to ProcessEnv interface
|
|
93
|
+
AUTH_OKTA_ID?: string;
|
|
94
|
+
AUTH_OKTA_SECRET?: string;
|
|
95
|
+
AUTH_OKTA_ISSUER?: string;
|
|
96
|
+
|
|
97
|
+
// Add to getAuthConfig server schema
|
|
98
|
+
AUTH_OKTA_ID: z.string().optional(),
|
|
99
|
+
AUTH_OKTA_SECRET: z.string().optional(),
|
|
100
|
+
AUTH_OKTA_ISSUER: z.string().optional(),
|
|
101
|
+
|
|
102
|
+
// Add to runtimeEnv
|
|
103
|
+
AUTH_OKTA_ID: process.env.AUTH_OKTA_ID,
|
|
104
|
+
AUTH_OKTA_SECRET: process.env.AUTH_OKTA_SECRET,
|
|
105
|
+
AUTH_OKTA_ISSUER: process.env.AUTH_OKTA_ISSUER,
|
|
106
|
+
```
|
|
75
107
|
|
|
76
|
-
### Step 4:
|
|
108
|
+
### Step 4: Update Documentation (Optional)
|
|
77
109
|
|
|
78
|
-
Add
|
|
110
|
+
Add provider documentation in `docs/self-hosting/advanced/auth.mdx` and `docs/self-hosting/advanced/auth.zh-CN.mdx`.
|
|
79
111
|
|
|
80
|
-
|
|
112
|
+
## Adding a Built-in Provider
|
|
81
113
|
|
|
82
|
-
|
|
114
|
+
For providers natively supported by Better Auth (e.g., Discord), the steps differ slightly:
|
|
83
115
|
|
|
84
|
-
|
|
116
|
+
### Step 1: Create Provider Definition File
|
|
85
117
|
|
|
86
118
|
```ts
|
|
87
|
-
import {
|
|
119
|
+
import { authEnv } from '@/envs/auth';
|
|
120
|
+
|
|
121
|
+
import type { BuiltinProviderDefinition } from '../types';
|
|
122
|
+
|
|
123
|
+
const provider: BuiltinProviderDefinition<{
|
|
124
|
+
AUTH_DISCORD_ID: string;
|
|
125
|
+
AUTH_DISCORD_SECRET: string;
|
|
126
|
+
}> = {
|
|
127
|
+
build: (env) => ({
|
|
128
|
+
clientId: env.AUTH_DISCORD_ID,
|
|
129
|
+
clientSecret: env.AUTH_DISCORD_SECRET,
|
|
130
|
+
}),
|
|
131
|
+
checkEnvs: () => {
|
|
132
|
+
return !!(authEnv.AUTH_DISCORD_ID && authEnv.AUTH_DISCORD_SECRET)
|
|
133
|
+
? {
|
|
134
|
+
AUTH_DISCORD_ID: authEnv.AUTH_DISCORD_ID,
|
|
135
|
+
AUTH_DISCORD_SECRET: authEnv.AUTH_DISCORD_SECRET,
|
|
136
|
+
}
|
|
137
|
+
: false;
|
|
138
|
+
},
|
|
139
|
+
id: 'discord',
|
|
140
|
+
type: 'builtin',
|
|
141
|
+
};
|
|
88
142
|
|
|
89
|
-
|
|
143
|
+
export default provider;
|
|
90
144
|
```
|
|
91
145
|
|
|
92
|
-
|
|
146
|
+
### Step 2: Update Constants File
|
|
147
|
+
|
|
148
|
+
Add to `src/libs/better-auth/constants.ts`:
|
|
93
149
|
|
|
94
150
|
```ts
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
151
|
+
export const BUILTIN_BETTER_AUTH_PROVIDERS = [
|
|
152
|
+
'apple',
|
|
153
|
+
'google',
|
|
154
|
+
'github',
|
|
155
|
+
'cognito',
|
|
156
|
+
'microsoft',
|
|
157
|
+
'discord', // Add new provider
|
|
158
|
+
] as const;
|
|
101
159
|
```
|
|
102
160
|
|
|
103
|
-
|
|
161
|
+
## Callback URL Format
|
|
104
162
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
```txt
|
|
108
|
-
authorize --> jwt --> session
|
|
109
|
-
```
|
|
163
|
+
When configuring OAuth applications, use these callback URL formats:
|
|
110
164
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
```ts
|
|
114
|
-
callbacks: {
|
|
115
|
-
async jwt({ token, account, profile }) {
|
|
116
|
-
if (account) {
|
|
117
|
-
// You can select a different value from `account` or `profile`
|
|
118
|
-
token.userId = account.providerAccountId;
|
|
119
|
-
}
|
|
120
|
-
return token;
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
```
|
|
165
|
+
- **Built-in providers**: `https://yourdomain.com/api/auth/callback/{providerId}`
|
|
166
|
+
- **Generic OIDC**: `https://yourdomain.com/api/auth/callback/{providerId}`
|
|
124
167
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
If you want to carry more information about `profile` and `account` in the `session`, according to the data processing order mentioned above in `Auth.js`, you must first copy this information to the `token`. For example, add the user avatar URL `profile.picture` to the `session`:
|
|
128
|
-
|
|
129
|
-
```diff
|
|
130
|
-
callbacks: {
|
|
131
|
-
async jwt({ token, profile, account }) {
|
|
132
|
-
if (profile && account) {
|
|
133
|
-
token.userId = account.providerAccountId;
|
|
134
|
-
+ token.avatar = profile.picture;
|
|
135
|
-
}
|
|
136
|
-
return token;
|
|
137
|
-
},
|
|
138
|
-
async session({ session, token }) {
|
|
139
|
-
if (session.user) {
|
|
140
|
-
session.user.id = token.userId ?? session.user.id;
|
|
141
|
-
+ session.user.avatar = token.avatar;
|
|
142
|
-
}
|
|
143
|
-
return session;
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
```
|
|
168
|
+
## Using the New Provider
|
|
147
169
|
|
|
148
|
-
|
|
170
|
+
After configuring environment variables, enable in `AUTH_SSO_PROVIDERS`:
|
|
149
171
|
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
declare module 'next-auth' {
|
|
159
|
-
interface User {
|
|
160
|
-
avatar?: string;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
172
|
+
```bash
|
|
173
|
+
AUTH_SSO_PROVIDERS=google,github,okta
|
|
174
|
+
AUTH_OKTA_ID=your-client-id
|
|
175
|
+
AUTH_OKTA_SECRET=your-client-secret
|
|
176
|
+
AUTH_OKTA_ISSUER=https://your-domain.okta.com
|
|
163
177
|
```
|
|
164
178
|
|
|
165
|
-
|
|
179
|
+
## Debugging Tips
|
|
166
180
|
|
|
167
|
-
|
|
181
|
+
1. **Environment variable check fails**: Ensure all required environment variables are set
|
|
182
|
+
2. **Callback URL errors**: Verify the callback URL configured in your OAuth application
|
|
183
|
+
3. **User profile mapping**: Use `mapProfileToUser` to customize the mapping from OAuth profile to user info
|
|
168
184
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
```ts
|
|
172
|
-
callbacks: {
|
|
173
|
-
async jwt({ token, profile, account }) {
|
|
174
|
-
if (profile && account) {
|
|
175
|
-
if (account.provider === 'authing')
|
|
176
|
-
token.userId = account.providerAccountId ?? token.sub;
|
|
177
|
-
else if (acount.provider === 'auth0')
|
|
178
|
-
token.userId = profile.sub ?? token.sub;
|
|
179
|
-
else
|
|
180
|
-
// other providers
|
|
181
|
-
}
|
|
182
|
-
return token;
|
|
183
|
-
},
|
|
184
|
-
}
|
|
185
|
-
```
|
|
185
|
+
## Related Files
|
|
186
186
|
|
|
187
|
-
|
|
187
|
+
| File | Description |
|
|
188
|
+
| ----------------------------------------- | -------------------------------- |
|
|
189
|
+
| `src/libs/better-auth/sso/providers/*.ts` | Provider definitions |
|
|
190
|
+
| `src/libs/better-auth/sso/index.ts` | Provider registration |
|
|
191
|
+
| `src/libs/better-auth/sso/types.ts` | Type definitions |
|
|
192
|
+
| `src/libs/better-auth/sso/helpers.ts` | Helper functions |
|
|
193
|
+
| `src/libs/better-auth/constants.ts` | Built-in provider constants |
|
|
194
|
+
| `src/envs/auth.ts` | Environment variable definitions |
|
|
195
|
+
| `src/libs/better-auth/define-config.ts` | Better Auth configuration |
|
|
@@ -1,185 +1,195 @@
|
|
|
1
1
|
---
|
|
2
|
-
title:
|
|
2
|
+
title: 新身份验证提供商开发指南
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# 新身份验证提供商开发指南
|
|
6
6
|
|
|
7
|
-
LobeChat 使用 [Auth
|
|
7
|
+
LobeChat 使用 [Better Auth](https://www.better-auth.com) 作为身份验证服务。本文档介绍如何添加新的 SSO 身份验证提供商。
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## 架构概述
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Better Auth SSO 提供商分为两类:
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
| 类型 | 说明 | 示例 |
|
|
14
|
+
| --------- | -------------------------- | ----------------------------- |
|
|
15
|
+
| `builtin` | Better Auth 内置支持的提供商 | Google、GitHub、Microsoft、Apple |
|
|
16
|
+
| `generic` | 通过 Generic OIDC/OAuth 插件实现 | Okta、Auth0、Keycloak 等 |
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
## 添加新的 SSO 提供商
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
以添加 **Okta** 为例,介绍添加 `generic` 类型提供商的完整步骤。
|
|
18
21
|
|
|
19
|
-
### 步骤 1:
|
|
22
|
+
### 步骤 1: 创建提供商定义文件
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
在 `src/libs/better-auth/sso/providers/` 目录下创建 `okta.ts`:
|
|
22
25
|
|
|
23
26
|
```ts
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
import
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
import { authEnv } from '@/envs/auth';
|
|
28
|
+
|
|
29
|
+
import { buildOidcConfig } from '../helpers';
|
|
30
|
+
import type { GenericProviderDefinition } from '../types';
|
|
31
|
+
|
|
32
|
+
const provider: GenericProviderDefinition<{
|
|
33
|
+
AUTH_OKTA_ID: string;
|
|
34
|
+
AUTH_OKTA_ISSUER: string;
|
|
35
|
+
AUTH_OKTA_SECRET: string;
|
|
36
|
+
}> = {
|
|
37
|
+
// 构建 OIDC 配置
|
|
38
|
+
build: (env) =>
|
|
39
|
+
buildOidcConfig({
|
|
40
|
+
clientId: env.AUTH_OKTA_ID,
|
|
41
|
+
clientSecret: env.AUTH_OKTA_SECRET,
|
|
42
|
+
issuer: env.AUTH_OKTA_ISSUER,
|
|
43
|
+
overrides: {
|
|
44
|
+
// 可选:自定义用户信息映射
|
|
45
|
+
mapProfileToUser: (profile) => ({
|
|
46
|
+
email: profile.email,
|
|
47
|
+
name: profile.name ?? profile.preferred_username ?? profile.email ?? profile.sub,
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
providerId: 'okta',
|
|
51
|
+
}),
|
|
32
52
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
53
|
+
// 环境变量检查
|
|
54
|
+
checkEnvs: () => {
|
|
55
|
+
return !!(authEnv.AUTH_OKTA_ID && authEnv.AUTH_OKTA_SECRET && authEnv.AUTH_OKTA_ISSUER)
|
|
56
|
+
? {
|
|
57
|
+
AUTH_OKTA_ID: authEnv.AUTH_OKTA_ID,
|
|
58
|
+
AUTH_OKTA_ISSUER: authEnv.AUTH_OKTA_ISSUER,
|
|
59
|
+
AUTH_OKTA_SECRET: authEnv.AUTH_OKTA_SECRET,
|
|
60
|
+
}
|
|
61
|
+
: false;
|
|
62
|
+
},
|
|
36
63
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
64
|
+
// 提供商 ID(用于 AUTH_SSO_PROVIDERS 配置)
|
|
65
|
+
id: 'okta',
|
|
66
|
+
type: 'generic',
|
|
67
|
+
};
|
|
40
68
|
|
|
41
|
-
|
|
42
|
-
clientId: OKTA_CLIENT_ID,
|
|
43
|
-
clientSecret: OKTA_CLIENT_SECRET,
|
|
44
|
-
issuer: OKTA_ISSUER,
|
|
45
|
-
}),
|
|
46
|
-
],
|
|
47
|
-
});
|
|
69
|
+
export default provider;
|
|
48
70
|
```
|
|
49
71
|
|
|
50
|
-
### 步骤 2:
|
|
72
|
+
### 步骤 2: 注册提供商
|
|
51
73
|
|
|
52
|
-
|
|
74
|
+
在 `src/libs/better-auth/sso/index.ts` 中导入并注册:
|
|
53
75
|
|
|
54
76
|
```ts
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
OKTA_ISSUER: process.env.OKTA_ISSUER || '',
|
|
64
|
-
};
|
|
65
|
-
};
|
|
77
|
+
// 导入提供商
|
|
78
|
+
import Okta from './providers/okta';
|
|
79
|
+
|
|
80
|
+
// 添加到 providerDefinitions 数组
|
|
81
|
+
const providerDefinitions = [
|
|
82
|
+
// ... 其他提供商
|
|
83
|
+
Okta,
|
|
84
|
+
] as const;
|
|
66
85
|
```
|
|
67
86
|
|
|
68
|
-
### 步骤 3:
|
|
87
|
+
### 步骤 3: 添加环境变量类型声明
|
|
69
88
|
|
|
70
|
-
|
|
89
|
+
在 `src/envs/auth.ts` 中添加类型声明:
|
|
71
90
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
91
|
+
```ts
|
|
92
|
+
// ProcessEnv 接口中添加
|
|
93
|
+
AUTH_OKTA_ID?: string;
|
|
94
|
+
AUTH_OKTA_SECRET?: string;
|
|
95
|
+
AUTH_OKTA_ISSUER?: string;
|
|
96
|
+
|
|
97
|
+
// getAuthConfig server schema 中添加
|
|
98
|
+
AUTH_OKTA_ID: z.string().optional(),
|
|
99
|
+
AUTH_OKTA_SECRET: z.string().optional(),
|
|
100
|
+
AUTH_OKTA_ISSUER: z.string().optional(),
|
|
101
|
+
|
|
102
|
+
// runtimeEnv 中添加
|
|
103
|
+
AUTH_OKTA_ID: process.env.AUTH_OKTA_ID,
|
|
104
|
+
AUTH_OKTA_SECRET: process.env.AUTH_OKTA_SECRET,
|
|
105
|
+
AUTH_OKTA_ISSUER: process.env.AUTH_OKTA_ISSUER,
|
|
106
|
+
```
|
|
75
107
|
|
|
76
|
-
### 步骤 4:
|
|
108
|
+
### 步骤 4: 更新文档(可选)
|
|
77
109
|
|
|
78
|
-
|
|
110
|
+
在 `docs/self-hosting/advanced/auth.mdx` 和 `docs/self-hosting/advanced/auth.zh-CN.mdx` 中添加提供商文档。
|
|
79
111
|
|
|
80
|
-
|
|
112
|
+
## 添加内置提供商
|
|
81
113
|
|
|
82
|
-
|
|
114
|
+
如果要添加 Better Auth 内置支持的提供商(如 Discord),步骤略有不同:
|
|
83
115
|
|
|
84
|
-
|
|
116
|
+
### 步骤 1: 创建提供商定义文件
|
|
85
117
|
|
|
86
118
|
```ts
|
|
87
|
-
import {
|
|
119
|
+
import { authEnv } from '@/envs/auth';
|
|
120
|
+
|
|
121
|
+
import type { BuiltinProviderDefinition } from '../types';
|
|
122
|
+
|
|
123
|
+
const provider: BuiltinProviderDefinition<{
|
|
124
|
+
AUTH_DISCORD_ID: string;
|
|
125
|
+
AUTH_DISCORD_SECRET: string;
|
|
126
|
+
}> = {
|
|
127
|
+
build: (env) => ({
|
|
128
|
+
clientId: env.AUTH_DISCORD_ID,
|
|
129
|
+
clientSecret: env.AUTH_DISCORD_SECRET,
|
|
130
|
+
}),
|
|
131
|
+
checkEnvs: () => {
|
|
132
|
+
return !!(authEnv.AUTH_DISCORD_ID && authEnv.AUTH_DISCORD_SECRET)
|
|
133
|
+
? {
|
|
134
|
+
AUTH_DISCORD_ID: authEnv.AUTH_DISCORD_ID,
|
|
135
|
+
AUTH_DISCORD_SECRET: authEnv.AUTH_DISCORD_SECRET,
|
|
136
|
+
}
|
|
137
|
+
: false;
|
|
138
|
+
},
|
|
139
|
+
id: 'discord',
|
|
140
|
+
type: 'builtin',
|
|
141
|
+
};
|
|
88
142
|
|
|
89
|
-
|
|
143
|
+
export default provider;
|
|
90
144
|
```
|
|
91
145
|
|
|
92
|
-
|
|
146
|
+
### 步骤 2: 更新常量文件
|
|
147
|
+
|
|
148
|
+
在 `src/libs/better-auth/constants.ts` 中添加:
|
|
93
149
|
|
|
94
150
|
```ts
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
151
|
+
export const BUILTIN_BETTER_AUTH_PROVIDERS = [
|
|
152
|
+
'apple',
|
|
153
|
+
'google',
|
|
154
|
+
'github',
|
|
155
|
+
'cognito',
|
|
156
|
+
'microsoft',
|
|
157
|
+
'discord', // 新增
|
|
158
|
+
] as const;
|
|
101
159
|
```
|
|
102
160
|
|
|
103
|
-
|
|
161
|
+
## 回调 URL 格式
|
|
104
162
|
|
|
105
|
-
|
|
163
|
+
配置 OAuth 应用时,回调 URL 格式为:
|
|
106
164
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
默认情况下,在 `jwt --> session` 过程中,`Auth.js` 会[自动根据登陆类型](https://authjs.dev/reference/core/types#provideraccountid)将用户 `id` 赋值到 `account.providerAccountId` 中。 如果您需要选取其他值作为用户 `id` ,您需要实现以下处理逻辑。
|
|
112
|
-
|
|
113
|
-
```ts
|
|
114
|
-
callbacks: {
|
|
115
|
-
async jwt({ token, account, profile }) {
|
|
116
|
-
if (account) {
|
|
117
|
-
// 您可以从 `account` 或 `profile` 中选取其他值
|
|
118
|
-
token.userId = account.providerAccountId;
|
|
119
|
-
}
|
|
120
|
-
return token;
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
```
|
|
165
|
+
- **内置提供商**:`https://yourdomain.com/api/auth/callback/{providerId}`
|
|
166
|
+
- **Generic OIDC**:`https://yourdomain.com/api/auth/callback/{providerId}`
|
|
124
167
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
如果您想在 `session` 中携带更多关于 `profile` 及 `account` 的信息,根据上面提到的 `Auth.js` 数据处理顺序,那必须先将该信息复制到 `token` 上。示例:把用户头像 URL:`profile.picture` 添加到`session` 中:
|
|
128
|
-
|
|
129
|
-
```diff
|
|
130
|
-
callbacks: {
|
|
131
|
-
async jwt({ token, profile, account }) {
|
|
132
|
-
if (profile && account) {
|
|
133
|
-
token.userId = account.providerAccountId;
|
|
134
|
-
+ token.avatar = profile.picture;
|
|
135
|
-
}
|
|
136
|
-
return token;
|
|
137
|
-
},
|
|
138
|
-
async session({ session, token }) {
|
|
139
|
-
if (session.user) {
|
|
140
|
-
session.user.id = token.userId ?? session.user.id;
|
|
141
|
-
+ session.user.avatar = token.avatar;
|
|
142
|
-
}
|
|
143
|
-
return session;
|
|
144
|
-
},
|
|
145
|
-
},
|
|
146
|
-
```
|
|
168
|
+
## 使用新提供商
|
|
147
169
|
|
|
148
|
-
|
|
170
|
+
配置环境变量后,在 `AUTH_SSO_PROVIDERS` 中启用:
|
|
149
171
|
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
declare module 'next-auth' {
|
|
159
|
-
interface User {
|
|
160
|
-
avatar?: string;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
172
|
+
```bash
|
|
173
|
+
AUTH_SSO_PROVIDERS=google,github,okta
|
|
174
|
+
AUTH_OKTA_ID=your-client-id
|
|
175
|
+
AUTH_OKTA_SECRET=your-client-secret
|
|
176
|
+
AUTH_OKTA_ISSUER=https://your-domain.okta.com
|
|
163
177
|
```
|
|
164
178
|
|
|
165
|
-
|
|
179
|
+
## 调试技巧
|
|
166
180
|
|
|
167
|
-
|
|
181
|
+
1. **环境变量检查失败**:确保所有必需的环境变量都已设置
|
|
182
|
+
2. **回调 URL 错误**:检查 OAuth 应用配置的回调 URL 是否正确
|
|
183
|
+
3. **用户信息映射**:通过 `mapProfileToUser` 自定义从 OAuth profile 到用户信息的映射
|
|
168
184
|
|
|
169
|
-
|
|
185
|
+
## 相关文件
|
|
170
186
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
// other providers
|
|
181
|
-
}
|
|
182
|
-
return token;
|
|
183
|
-
},
|
|
184
|
-
}
|
|
185
|
-
```
|
|
187
|
+
| 文件 | 说明 |
|
|
188
|
+
| ----------------------------------------- | -------------- |
|
|
189
|
+
| `src/libs/better-auth/sso/providers/*.ts` | 提供商定义 |
|
|
190
|
+
| `src/libs/better-auth/sso/index.ts` | 提供商注册 |
|
|
191
|
+
| `src/libs/better-auth/sso/types.ts` | 类型定义 |
|
|
192
|
+
| `src/libs/better-auth/sso/helpers.ts` | 辅助函数 |
|
|
193
|
+
| `src/libs/better-auth/constants.ts` | 内置提供商常量 |
|
|
194
|
+
| `src/envs/auth.ts` | 环境变量定义 |
|
|
195
|
+
| `src/libs/better-auth/define-config.ts` | Better Auth 配置 |
|