@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
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useSession } from 'next-auth/react';
|
|
4
|
-
import { memo, useEffect } from 'react';
|
|
5
|
-
import { createStoreUpdater } from 'zustand-utils';
|
|
6
|
-
|
|
7
|
-
import { useUserStore } from '@/store/user';
|
|
8
|
-
import { type LobeUser } from '@/types/user';
|
|
9
|
-
|
|
10
|
-
// update the user data into the context
|
|
11
|
-
const UserUpdater = memo(() => {
|
|
12
|
-
const { data: session, status } = useSession();
|
|
13
|
-
const isLoaded = status !== 'loading';
|
|
14
|
-
|
|
15
|
-
const isSignedIn = (status === 'authenticated' && session && !!session.user) || false;
|
|
16
|
-
|
|
17
|
-
const nextUser = session?.user;
|
|
18
|
-
const useStoreUpdater = createStoreUpdater(useUserStore);
|
|
19
|
-
|
|
20
|
-
useStoreUpdater('isLoaded', isLoaded);
|
|
21
|
-
useStoreUpdater('isSignedIn', isSignedIn);
|
|
22
|
-
useStoreUpdater('nextSession', session!);
|
|
23
|
-
|
|
24
|
-
// 使用 useEffect 处理需要保持同步的用户数据
|
|
25
|
-
useEffect(() => {
|
|
26
|
-
if (nextUser) {
|
|
27
|
-
const userAvatar = useUserStore.getState().user?.avatar;
|
|
28
|
-
|
|
29
|
-
const lobeUser = {
|
|
30
|
-
// 头像使用设置的,而不是从 next-auth 中获取
|
|
31
|
-
avatar: userAvatar || '',
|
|
32
|
-
email: nextUser.email,
|
|
33
|
-
fullName: nextUser.name,
|
|
34
|
-
id: nextUser.id,
|
|
35
|
-
} as LobeUser;
|
|
36
|
-
|
|
37
|
-
// 更新用户相关数据
|
|
38
|
-
useUserStore.setState({ nextUser: nextUser, user: lobeUser });
|
|
39
|
-
}
|
|
40
|
-
}, [nextUser]);
|
|
41
|
-
return null;
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
export default UserUpdater;
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { SessionProvider } from 'next-auth/react';
|
|
2
|
-
import { type PropsWithChildren } from 'react';
|
|
3
|
-
|
|
4
|
-
import { API_ENDPOINTS } from '@/services/_url';
|
|
5
|
-
|
|
6
|
-
import UserUpdater from './UserUpdater';
|
|
7
|
-
|
|
8
|
-
const NextAuth = ({ children }: PropsWithChildren) => {
|
|
9
|
-
return (
|
|
10
|
-
<SessionProvider basePath={API_ENDPOINTS.oauth}>
|
|
11
|
-
{children}
|
|
12
|
-
<UserUpdater />
|
|
13
|
-
</SessionProvider>
|
|
14
|
-
);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export default NextAuth;
|
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AdapterAuthenticator,
|
|
3
|
-
AdapterSession,
|
|
4
|
-
AdapterUser,
|
|
5
|
-
VerificationToken,
|
|
6
|
-
} from '@auth/core/adapters';
|
|
7
|
-
import debug from 'debug';
|
|
8
|
-
import { type Adapter, type AdapterAccount } from 'next-auth/adapters';
|
|
9
|
-
import urlJoin from 'url-join';
|
|
10
|
-
|
|
11
|
-
import { serverDBEnv } from '@/config/db';
|
|
12
|
-
import { appEnv } from '@/envs/app';
|
|
13
|
-
|
|
14
|
-
const log = debug('lobe-next-auth:adapter');
|
|
15
|
-
|
|
16
|
-
interface BackendAdapterResponse {
|
|
17
|
-
data?: any;
|
|
18
|
-
error?: string;
|
|
19
|
-
success: boolean;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Due to use direct HTTP Post, the date string cannot parse automatically
|
|
23
|
-
export const dateKeys = ['expires', 'emailVerified'];
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* @description LobeNextAuthDbAdapter is implemented to handle the database operations for NextAuth
|
|
27
|
-
* @returns {Adapter}
|
|
28
|
-
*/
|
|
29
|
-
export function LobeNextAuthDbAdapter(): Adapter {
|
|
30
|
-
const baseUrl = appEnv.APP_URL;
|
|
31
|
-
|
|
32
|
-
// Ensure the baseUrl is set, otherwise throw an error
|
|
33
|
-
if (!baseUrl) {
|
|
34
|
-
throw new Error('LobeNextAuthDbAdapter: APP_URL is not set in environment variables');
|
|
35
|
-
}
|
|
36
|
-
const interactionUrl = urlJoin(baseUrl, '/api/auth/adapter');
|
|
37
|
-
log(`LobeNextAuthDbAdapter initialized with url: ${interactionUrl}`);
|
|
38
|
-
|
|
39
|
-
// Ensure serverDBEnv.KEY_VAULTS_SECRET is set, otherwise throw an error
|
|
40
|
-
if (!serverDBEnv.KEY_VAULTS_SECRET) {
|
|
41
|
-
throw new Error('LobeNextAuthDbAdapter: KEY_VAULTS_SECRET is not set in environment variables');
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const fetcher = (action: string, data: any) =>
|
|
45
|
-
fetch(interactionUrl, {
|
|
46
|
-
body: JSON.stringify({ action, data }),
|
|
47
|
-
headers: {
|
|
48
|
-
'Authorization': `Bearer ${serverDBEnv.KEY_VAULTS_SECRET}`,
|
|
49
|
-
'Content-Type': 'application/json',
|
|
50
|
-
},
|
|
51
|
-
method: 'POST',
|
|
52
|
-
});
|
|
53
|
-
const postProcessor = async (res: Response) => {
|
|
54
|
-
const data = (await res.json()) as BackendAdapterResponse;
|
|
55
|
-
log('LobeNextAuthDbAdapter: postProcessor called with data:', data);
|
|
56
|
-
if (!data.success) {
|
|
57
|
-
log('LobeNextAuthDbAdapter: Error in postProcessor:');
|
|
58
|
-
log(data);
|
|
59
|
-
throw new Error(`LobeNextAuthDbAdapter: ${data.error}`);
|
|
60
|
-
}
|
|
61
|
-
if (data?.data) {
|
|
62
|
-
for (const key of dateKeys) {
|
|
63
|
-
if (data.data[key]) {
|
|
64
|
-
data.data[key] = new Date(data.data[key]);
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return data.data;
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
return {
|
|
73
|
-
async createAuthenticator(authenticator): Promise<AdapterAuthenticator> {
|
|
74
|
-
const data = await fetcher('createAuthenticator', authenticator);
|
|
75
|
-
return await postProcessor(data);
|
|
76
|
-
},
|
|
77
|
-
async createSession(session): Promise<AdapterSession> {
|
|
78
|
-
const data = await fetcher('createSession', session);
|
|
79
|
-
return await postProcessor(data);
|
|
80
|
-
},
|
|
81
|
-
async createUser(user): Promise<AdapterUser> {
|
|
82
|
-
const data = await fetcher('createUser', user);
|
|
83
|
-
return await postProcessor(data);
|
|
84
|
-
},
|
|
85
|
-
async createVerificationToken(data): Promise<VerificationToken | null | undefined> {
|
|
86
|
-
const result = await fetcher('createVerificationToken', data);
|
|
87
|
-
return await postProcessor(result);
|
|
88
|
-
},
|
|
89
|
-
async deleteSession(sessionToken): Promise<AdapterSession | null | undefined> {
|
|
90
|
-
const result = await fetcher('deleteSession', sessionToken);
|
|
91
|
-
await postProcessor(result);
|
|
92
|
-
return;
|
|
93
|
-
},
|
|
94
|
-
async deleteUser(id): Promise<AdapterUser | null | undefined> {
|
|
95
|
-
const result = await fetcher('deleteUser', id);
|
|
96
|
-
await postProcessor(result);
|
|
97
|
-
return;
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
async getAccount(providerAccountId, provider): Promise<AdapterAccount | null> {
|
|
101
|
-
const data = await fetcher('getAccount', {
|
|
102
|
-
provider,
|
|
103
|
-
providerAccountId,
|
|
104
|
-
});
|
|
105
|
-
return await postProcessor(data);
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
async getAuthenticator(credentialID): Promise<AdapterAuthenticator | null> {
|
|
109
|
-
const result = await fetcher('getAuthenticator', credentialID);
|
|
110
|
-
return await postProcessor(result);
|
|
111
|
-
},
|
|
112
|
-
|
|
113
|
-
async getSessionAndUser(sessionToken): Promise<{
|
|
114
|
-
session: AdapterSession;
|
|
115
|
-
user: AdapterUser;
|
|
116
|
-
} | null> {
|
|
117
|
-
const result = await fetcher('getSessionAndUser', sessionToken);
|
|
118
|
-
return await postProcessor(result);
|
|
119
|
-
},
|
|
120
|
-
|
|
121
|
-
async getUser(id): Promise<AdapterUser | null> {
|
|
122
|
-
log('getUser called with id:', id);
|
|
123
|
-
const result = await fetcher('getUser', id);
|
|
124
|
-
return await postProcessor(result);
|
|
125
|
-
},
|
|
126
|
-
|
|
127
|
-
async getUserByAccount(account): Promise<AdapterUser | null> {
|
|
128
|
-
const data = await fetcher('getUserByAccount', account);
|
|
129
|
-
return await postProcessor(data);
|
|
130
|
-
},
|
|
131
|
-
|
|
132
|
-
async getUserByEmail(email): Promise<AdapterUser | null> {
|
|
133
|
-
const data = await fetcher('getUserByEmail', email);
|
|
134
|
-
return await postProcessor(data);
|
|
135
|
-
},
|
|
136
|
-
|
|
137
|
-
async linkAccount(data): Promise<AdapterAccount | null | undefined> {
|
|
138
|
-
const result = await fetcher('linkAccount', data);
|
|
139
|
-
return await postProcessor(result);
|
|
140
|
-
},
|
|
141
|
-
|
|
142
|
-
async listAuthenticatorsByUserId(userId): Promise<AdapterAuthenticator[]> {
|
|
143
|
-
const result = await fetcher('listAuthenticatorsByUserId', userId);
|
|
144
|
-
return await postProcessor(result);
|
|
145
|
-
},
|
|
146
|
-
|
|
147
|
-
// @ts-ignore: The return type is {Promise<void> | Awaitable<AdapterAccount | undefined>}
|
|
148
|
-
async unlinkAccount(account): Promise<void | AdapterAccount | undefined> {
|
|
149
|
-
const result = await fetcher('unlinkAccount', account);
|
|
150
|
-
await postProcessor(result);
|
|
151
|
-
return;
|
|
152
|
-
},
|
|
153
|
-
|
|
154
|
-
async updateAuthenticatorCounter(credentialID, counter): Promise<AdapterAuthenticator> {
|
|
155
|
-
const result = await fetcher('updateAuthenticatorCounter', {
|
|
156
|
-
counter,
|
|
157
|
-
credentialID,
|
|
158
|
-
});
|
|
159
|
-
return await postProcessor(result);
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
async updateSession(data): Promise<AdapterSession | null | undefined> {
|
|
163
|
-
const result = await fetcher('updateSession', data);
|
|
164
|
-
return await postProcessor(result);
|
|
165
|
-
},
|
|
166
|
-
|
|
167
|
-
async updateUser(user): Promise<AdapterUser> {
|
|
168
|
-
const result = await fetcher('updateUser', user);
|
|
169
|
-
return await postProcessor(result);
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
async useVerificationToken(identifier_token): Promise<VerificationToken | null> {
|
|
173
|
-
const result = await fetcher('useVerificationToken', identifier_token);
|
|
174
|
-
return await postProcessor(result);
|
|
175
|
-
},
|
|
176
|
-
};
|
|
177
|
-
}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import type { NextAuthConfig } from 'next-auth';
|
|
2
|
-
|
|
3
|
-
import { getAuthConfig } from '@/envs/auth';
|
|
4
|
-
|
|
5
|
-
import { LobeNextAuthDbAdapter } from './adapter';
|
|
6
|
-
import { ssoProviders } from './sso-providers';
|
|
7
|
-
|
|
8
|
-
const {
|
|
9
|
-
NEXT_AUTH_DEBUG,
|
|
10
|
-
NEXT_AUTH_SECRET,
|
|
11
|
-
NEXT_AUTH_SSO_SESSION_STRATEGY,
|
|
12
|
-
NEXT_AUTH_SSO_PROVIDERS,
|
|
13
|
-
NEXT_PUBLIC_ENABLE_NEXT_AUTH,
|
|
14
|
-
} = getAuthConfig();
|
|
15
|
-
|
|
16
|
-
export const initSSOProviders = () => {
|
|
17
|
-
return NEXT_PUBLIC_ENABLE_NEXT_AUTH
|
|
18
|
-
? NEXT_AUTH_SSO_PROVIDERS.split(/[,,]/).map((provider) => {
|
|
19
|
-
const validProvider = ssoProviders.find((item) => item.id === provider.trim());
|
|
20
|
-
|
|
21
|
-
if (validProvider) return validProvider.provider;
|
|
22
|
-
|
|
23
|
-
throw new Error(`[NextAuth] provider ${provider} is not supported`);
|
|
24
|
-
})
|
|
25
|
-
: [];
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// Notice this is only an object, not a full Auth.js instance
|
|
29
|
-
export default {
|
|
30
|
-
adapter: NEXT_PUBLIC_ENABLE_NEXT_AUTH ? LobeNextAuthDbAdapter() : undefined,
|
|
31
|
-
callbacks: {
|
|
32
|
-
// Note: Data processing order of callback: authorize --> jwt --> session
|
|
33
|
-
async jwt({ token, user }) {
|
|
34
|
-
// ref: https://authjs.dev/guides/extending-the-session#with-jwt
|
|
35
|
-
if (user?.id) {
|
|
36
|
-
token.userId = user?.id;
|
|
37
|
-
}
|
|
38
|
-
return token;
|
|
39
|
-
},
|
|
40
|
-
async session({ session, token, user }) {
|
|
41
|
-
if (session.user) {
|
|
42
|
-
// ref: https://authjs.dev/guides/extending-the-session#with-database
|
|
43
|
-
if (user) {
|
|
44
|
-
session.user.id = user.id;
|
|
45
|
-
} else {
|
|
46
|
-
session.user.id = (token.userId ?? session.user.id) as string;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
return session;
|
|
50
|
-
},
|
|
51
|
-
},
|
|
52
|
-
debug: NEXT_AUTH_DEBUG,
|
|
53
|
-
pages: {
|
|
54
|
-
error: '/next-auth/error',
|
|
55
|
-
signIn: '/next-auth/signin',
|
|
56
|
-
},
|
|
57
|
-
providers: initSSOProviders(),
|
|
58
|
-
secret: NEXT_AUTH_SECRET ?? process.env.AUTH_SECRET,
|
|
59
|
-
session: {
|
|
60
|
-
// Force use JWT if server service is disabled
|
|
61
|
-
strategy: NEXT_AUTH_SSO_SESSION_STRATEGY,
|
|
62
|
-
},
|
|
63
|
-
trustHost: process.env?.AUTH_TRUST_HOST ? process.env.AUTH_TRUST_HOST === 'true' : true,
|
|
64
|
-
} satisfies NextAuthConfig;
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import NextAuth from 'next-auth';
|
|
2
|
-
|
|
3
|
-
import authConfig from './auth.config';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* NextAuth initialization without Database adapter
|
|
7
|
-
*
|
|
8
|
-
* @note
|
|
9
|
-
* We currently use `jwt` strategy for session management.
|
|
10
|
-
* So you don't need to import `signIn` or `signOut` from
|
|
11
|
-
* this module, just import from `next-auth` directly.
|
|
12
|
-
*
|
|
13
|
-
* Inside react component
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* import { signOut } from 'next-auth/react';
|
|
17
|
-
* signOut();
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export default NextAuth(authConfig);
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import Auth0 from 'next-auth/providers/auth0';
|
|
2
|
-
|
|
3
|
-
import { CommonProviderConfig } from './sso.config';
|
|
4
|
-
|
|
5
|
-
const provider = {
|
|
6
|
-
id: 'auth0',
|
|
7
|
-
provider: Auth0({
|
|
8
|
-
...CommonProviderConfig,
|
|
9
|
-
// Specify auth scope, at least include 'openid email'
|
|
10
|
-
// all scopes in Auth0 ref: https://auth0.com/docs/get-started/apis/scopes/openid-connect-scopes#standard-claims
|
|
11
|
-
authorization: { params: { scope: 'openid email profile' } },
|
|
12
|
-
profile(profile) {
|
|
13
|
-
return {
|
|
14
|
-
email: profile.email,
|
|
15
|
-
id: profile.sub,
|
|
16
|
-
image: profile.picture,
|
|
17
|
-
name: profile.name,
|
|
18
|
-
providerAccountId: profile.sub,
|
|
19
|
-
};
|
|
20
|
-
},
|
|
21
|
-
}),
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export default provider;
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import type { OIDCConfig } from '@auth/core/providers';
|
|
2
|
-
|
|
3
|
-
import { CommonProviderConfig } from './sso.config';
|
|
4
|
-
|
|
5
|
-
export type AutheliaProfile = {
|
|
6
|
-
// The users display name
|
|
7
|
-
email: string;
|
|
8
|
-
// The users email
|
|
9
|
-
groups: string[];
|
|
10
|
-
// The username the user used to login with
|
|
11
|
-
name: string;
|
|
12
|
-
preferred_username: string; // The users groups
|
|
13
|
-
sub: string; // The users id
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const provider = {
|
|
17
|
-
id: 'authelia',
|
|
18
|
-
provider: {
|
|
19
|
-
...CommonProviderConfig,
|
|
20
|
-
authorization: { params: { scope: 'openid email profile' } },
|
|
21
|
-
checks: ['state', 'pkce'],
|
|
22
|
-
clientId: process.env.AUTH_AUTHELIA_ID,
|
|
23
|
-
clientSecret: process.env.AUTH_AUTHELIA_SECRET,
|
|
24
|
-
id: 'authelia',
|
|
25
|
-
issuer: process.env.AUTH_AUTHELIA_ISSUER,
|
|
26
|
-
name: 'Authelia',
|
|
27
|
-
profile(profile) {
|
|
28
|
-
return {
|
|
29
|
-
email: profile.email,
|
|
30
|
-
id: profile.sub,
|
|
31
|
-
name: profile.name,
|
|
32
|
-
providerAccountId: profile.sub,
|
|
33
|
-
};
|
|
34
|
-
},
|
|
35
|
-
type: 'oidc',
|
|
36
|
-
} satisfies OIDCConfig<AutheliaProfile>,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export default provider;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import Authentik from 'next-auth/providers/authentik';
|
|
2
|
-
|
|
3
|
-
import { CommonProviderConfig } from './sso.config';
|
|
4
|
-
|
|
5
|
-
const provider = {
|
|
6
|
-
id: 'authentik',
|
|
7
|
-
provider: Authentik({
|
|
8
|
-
...CommonProviderConfig,
|
|
9
|
-
// Specify auth scope, at least include 'openid email'
|
|
10
|
-
// all scopes in Authentik ref: https://goauthentik.io/docs/providers/oauth2
|
|
11
|
-
authorization: { params: { scope: 'openid email profile' } },
|
|
12
|
-
// TODO(NextAuth): map unique user id to `providerAccountId` field
|
|
13
|
-
// profile(profile) {
|
|
14
|
-
// return {
|
|
15
|
-
// email: profile.email,
|
|
16
|
-
// image: profile.picture,
|
|
17
|
-
// name: profile.name,
|
|
18
|
-
// providerAccountId: profile.user_id,
|
|
19
|
-
// id: profile.user_id,
|
|
20
|
-
// };
|
|
21
|
-
// },
|
|
22
|
-
}),
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export default provider;
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { type OIDCConfig, type OIDCUserConfig } from '@auth/core/providers';
|
|
2
|
-
|
|
3
|
-
import { CommonProviderConfig } from './sso.config';
|
|
4
|
-
|
|
5
|
-
interface CasdoorProfile extends Record<string, any> {
|
|
6
|
-
avatar: string;
|
|
7
|
-
displayName: string;
|
|
8
|
-
email: string;
|
|
9
|
-
emailVerified: boolean;
|
|
10
|
-
firstName: string;
|
|
11
|
-
id: string;
|
|
12
|
-
lastName: string;
|
|
13
|
-
name: string;
|
|
14
|
-
owner: string;
|
|
15
|
-
permanentAvatar: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function LobeCasdoorProvider(config: OIDCUserConfig<CasdoorProfile>): OIDCConfig<CasdoorProfile> {
|
|
19
|
-
return {
|
|
20
|
-
...CommonProviderConfig,
|
|
21
|
-
...config,
|
|
22
|
-
id: 'casdoor',
|
|
23
|
-
name: 'Casdoor',
|
|
24
|
-
profile(profile) {
|
|
25
|
-
return {
|
|
26
|
-
email: profile.email,
|
|
27
|
-
emailVerified: profile.emailVerified ? new Date() : null,
|
|
28
|
-
id: profile.id,
|
|
29
|
-
image: profile.avatar,
|
|
30
|
-
name: profile.displayName ?? profile.firstName ?? profile.lastName,
|
|
31
|
-
providerAccountId: profile.id,
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
type: 'oidc',
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const provider = {
|
|
39
|
-
id: 'casdoor',
|
|
40
|
-
provider: LobeCasdoorProvider({
|
|
41
|
-
authorization: {
|
|
42
|
-
params: { scope: 'openid profile email' },
|
|
43
|
-
},
|
|
44
|
-
clientId: process.env.AUTH_CASDOOR_ID,
|
|
45
|
-
clientSecret: process.env.AUTH_CASDOOR_SECRET,
|
|
46
|
-
issuer: process.env.AUTH_CASDOOR_ISSUER,
|
|
47
|
-
}),
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
export default provider;
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import type { OIDCConfig } from '@auth/core/providers';
|
|
2
|
-
|
|
3
|
-
import { CommonProviderConfig } from './sso.config';
|
|
4
|
-
|
|
5
|
-
export type CloudflareZeroTrustProfile = {
|
|
6
|
-
email: string;
|
|
7
|
-
name: string;
|
|
8
|
-
sub: string;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
const provider = {
|
|
12
|
-
id: 'cloudflare-zero-trust',
|
|
13
|
-
provider: {
|
|
14
|
-
...CommonProviderConfig,
|
|
15
|
-
authorization: { params: { scope: 'openid email profile' } },
|
|
16
|
-
checks: ['state', 'pkce'],
|
|
17
|
-
clientId: process.env.AUTH_CLOUDFLARE_ZERO_TRUST_ID,
|
|
18
|
-
clientSecret: process.env.AUTH_CLOUDFLARE_ZERO_TRUST_SECRET,
|
|
19
|
-
id: 'cloudflare-zero-trust',
|
|
20
|
-
issuer: process.env.AUTH_CLOUDFLARE_ZERO_TRUST_ISSUER,
|
|
21
|
-
name: 'Cloudflare Zero Trust',
|
|
22
|
-
profile(profile) {
|
|
23
|
-
return {
|
|
24
|
-
email: profile.email,
|
|
25
|
-
id: profile.sub,
|
|
26
|
-
name: profile.name ?? profile.email,
|
|
27
|
-
providerAccountId: profile.sub,
|
|
28
|
-
};
|
|
29
|
-
},
|
|
30
|
-
type: 'oidc',
|
|
31
|
-
} satisfies OIDCConfig<CloudflareZeroTrustProfile>,
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export default provider;
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { customFetch } from 'next-auth';
|
|
2
|
-
import type { OAuthConfig } from 'next-auth/providers';
|
|
3
|
-
|
|
4
|
-
interface FeishuProfile {
|
|
5
|
-
avatar_big: string;
|
|
6
|
-
avatar_middle: string;
|
|
7
|
-
avatar_thumb: string;
|
|
8
|
-
avatar_url: string;
|
|
9
|
-
en_name: string;
|
|
10
|
-
name: string;
|
|
11
|
-
open_id: string;
|
|
12
|
-
tenant_key: string;
|
|
13
|
-
union_id: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface FeishuProfileResponse {
|
|
17
|
-
data: FeishuProfile;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function Feishu(): OAuthConfig<FeishuProfileResponse> {
|
|
21
|
-
return {
|
|
22
|
-
authorization: {
|
|
23
|
-
params: {
|
|
24
|
-
scope: '',
|
|
25
|
-
},
|
|
26
|
-
url: 'https://accounts.feishu.cn/open-apis/authen/v1/authorize',
|
|
27
|
-
},
|
|
28
|
-
checks: ['state'],
|
|
29
|
-
client: {
|
|
30
|
-
token_endpoint_auth_method: 'client_secret_post',
|
|
31
|
-
},
|
|
32
|
-
clientId: process.env.AUTH_FEISHU_APP_ID,
|
|
33
|
-
clientSecret: process.env.AUTH_FEISHU_APP_SECRET,
|
|
34
|
-
[customFetch]: (url, options = {}) => {
|
|
35
|
-
if (
|
|
36
|
-
url === 'https://open.feishu.cn/open-apis/authen/v2/oauth/token' &&
|
|
37
|
-
options.method === 'POST'
|
|
38
|
-
) {
|
|
39
|
-
if (options?.headers) {
|
|
40
|
-
options.headers = {
|
|
41
|
-
...options.headers,
|
|
42
|
-
'content-type': 'application/json; charset=utf-8',
|
|
43
|
-
};
|
|
44
|
-
} else {
|
|
45
|
-
options.headers = {
|
|
46
|
-
'content-type': 'application/json; charset=utf-8',
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (options.body instanceof URLSearchParams) {
|
|
51
|
-
options.body = JSON.stringify(Object.fromEntries(options.body));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
return fetch(url, options);
|
|
56
|
-
},
|
|
57
|
-
id: 'feishu',
|
|
58
|
-
name: 'Feishu',
|
|
59
|
-
profile(profileResponse) {
|
|
60
|
-
const profile = profileResponse.data;
|
|
61
|
-
|
|
62
|
-
return {
|
|
63
|
-
id: profile.union_id,
|
|
64
|
-
image: profile.avatar_url,
|
|
65
|
-
name: profile.name,
|
|
66
|
-
providerAccountId: profile.union_id,
|
|
67
|
-
};
|
|
68
|
-
},
|
|
69
|
-
style: {
|
|
70
|
-
logo: 'https://p1-hera.feishucdn.com/tos-cn-i-jbbdkfciu3/268ec674a56a4510889f7f5ca14f1ba1~tplv-jbbdkfciu3-image:0:0.image',
|
|
71
|
-
},
|
|
72
|
-
token: 'https://open.feishu.cn/open-apis/authen/v2/oauth/token',
|
|
73
|
-
type: 'oauth',
|
|
74
|
-
userinfo: 'https://open.feishu.cn/open-apis/authen/v1/user_info',
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const provider = {
|
|
79
|
-
id: 'feishu',
|
|
80
|
-
provider: Feishu(),
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
export default provider;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { OIDCConfig } from '@auth/core/providers';
|
|
2
|
-
|
|
3
|
-
import { CommonProviderConfig } from './sso.config';
|
|
4
|
-
|
|
5
|
-
export type GenericOIDCProfile = {
|
|
6
|
-
email: string;
|
|
7
|
-
id?: string;
|
|
8
|
-
name?: string;
|
|
9
|
-
picture?: string;
|
|
10
|
-
sub: string;
|
|
11
|
-
username?: string;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const provider = {
|
|
15
|
-
id: 'generic-oidc',
|
|
16
|
-
provider: {
|
|
17
|
-
...CommonProviderConfig,
|
|
18
|
-
authorization: { params: { scope: 'email openid profile' } },
|
|
19
|
-
checks: ['state', 'pkce'],
|
|
20
|
-
clientId: process.env.AUTH_GENERIC_OIDC_ID,
|
|
21
|
-
clientSecret: process.env.AUTH_GENERIC_OIDC_SECRET,
|
|
22
|
-
id: 'generic-oidc',
|
|
23
|
-
issuer: process.env.AUTH_GENERIC_OIDC_ISSUER,
|
|
24
|
-
name: 'Generic OIDC',
|
|
25
|
-
profile(profile) {
|
|
26
|
-
return {
|
|
27
|
-
email: profile.email,
|
|
28
|
-
id: profile.sub,
|
|
29
|
-
image: profile.picture,
|
|
30
|
-
name: profile.name ?? profile.username ?? profile.email,
|
|
31
|
-
providerAccountId: profile.sub,
|
|
32
|
-
};
|
|
33
|
-
},
|
|
34
|
-
type: 'oidc',
|
|
35
|
-
} satisfies OIDCConfig<GenericOIDCProfile>,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export default provider;
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import GitHub from 'next-auth/providers/github';
|
|
2
|
-
|
|
3
|
-
import { CommonProviderConfig } from './sso.config';
|
|
4
|
-
|
|
5
|
-
const provider = {
|
|
6
|
-
id: 'github',
|
|
7
|
-
provider: GitHub({
|
|
8
|
-
...CommonProviderConfig,
|
|
9
|
-
// Specify auth scope, at least include 'openid email'
|
|
10
|
-
authorization: { params: { scope: 'read:user user:email' } },
|
|
11
|
-
profile: (profile) => {
|
|
12
|
-
return {
|
|
13
|
-
email: profile.email,
|
|
14
|
-
id: profile.id.toString(),
|
|
15
|
-
image: profile.avatar_url,
|
|
16
|
-
name: profile.name,
|
|
17
|
-
providerAccountId: profile.id.toString(),
|
|
18
|
-
};
|
|
19
|
-
},
|
|
20
|
-
}),
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export default provider;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import Google from 'next-auth/providers/google';
|
|
2
|
-
|
|
3
|
-
import { CommonProviderConfig } from './sso.config';
|
|
4
|
-
|
|
5
|
-
const provider = {
|
|
6
|
-
id: 'google',
|
|
7
|
-
provider: Google({
|
|
8
|
-
...CommonProviderConfig,
|
|
9
|
-
authorization: {
|
|
10
|
-
params: {
|
|
11
|
-
scope:
|
|
12
|
-
'openid https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email openid',
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
}),
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export default provider;
|