@lobehub/lobehub 2.0.0-next.343 → 2.0.0-next.345
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/.cursor/rules/i18n.mdc +1 -1
- package/.cursor/rules/modal-imperative.mdc +162 -0
- package/.cursor/rules/rules-index.mdc +1 -0
- package/.env.example +0 -14
- package/.eslintrc.js +8 -1
- package/CHANGELOG.md +66 -0
- package/Dockerfile +3 -13
- package/README.md +3 -5
- package/README.zh-CN.md +3 -5
- package/changelog/v1.json +24 -0
- package/docs/self-hosting/advanced/auth/clerk-to-betterauth.mdx +11 -42
- package/docs/self-hosting/advanced/auth/clerk-to-betterauth.zh-CN.mdx +10 -41
- package/e2e/src/support/webServer.ts +2 -0
- package/locales/ar/error.json +0 -4
- package/locales/bg-BG/error.json +0 -4
- package/locales/de-DE/error.json +0 -4
- package/locales/en-US/error.json +0 -4
- package/locales/es-ES/error.json +0 -4
- package/locales/fa-IR/error.json +0 -4
- package/locales/fr-FR/error.json +0 -4
- package/locales/it-IT/error.json +0 -4
- package/locales/ja-JP/error.json +0 -4
- package/locales/ko-KR/error.json +0 -4
- package/locales/nl-NL/error.json +0 -4
- package/locales/pl-PL/error.json +0 -4
- package/locales/pt-BR/error.json +0 -4
- package/locales/ru-RU/error.json +0 -4
- package/locales/tr-TR/error.json +0 -4
- package/locales/vi-VN/error.json +0 -4
- package/locales/zh-CN/error.json +0 -4
- package/locales/zh-TW/error.json +0 -4
- package/package.json +7 -9
- package/packages/builtin-agents/package.json +2 -0
- package/packages/builtin-agents/src/agents/agent-builder/index.ts +4 -2
- package/packages/builtin-agents/src/agents/group-agent-builder/index.ts +4 -2
- package/packages/builtin-agents/src/agents/page-agent/index.ts +5 -2
- package/packages/builtin-tool-cloud-sandbox/src/ExecutionRuntime/index.ts +161 -12
- package/packages/context-engine/src/engine/messages/MessagesEngine.ts +9 -9
- package/packages/context-engine/src/providers/GroupContextInjector.ts +19 -33
- package/packages/context-engine/src/providers/__tests__/GroupContextInjector.test.ts +79 -43
- package/packages/context-engine/src/providers/__tests__/__snapshots__/GroupContextInjector.test.ts.snap +5 -15
- package/packages/database/src/repositories/userMemory/__tests__/UserMemoryTopicRepository.test.ts +24 -3
- package/packages/model-bank/src/modelProviders/comfyui.ts +0 -1
- package/packages/model-bank/src/modelProviders/fal.ts +0 -1
- package/packages/types/src/fetch.ts +1 -2
- package/packages/utils/src/server/__tests__/auth.test.ts +0 -47
- package/packages/utils/src/server/auth.ts +1 -9
- package/scripts/_shared/checkDeprecatedClerkEnv.js +42 -0
- package/scripts/changelogWorkflow/buildStaticChangelog.ts +2 -1
- package/scripts/clerk-to-betterauth/_internal/types.ts +53 -20
- package/scripts/clerk-to-betterauth/export-clerk-users-with-api.ts +43 -36
- package/scripts/countEnWord.ts +1 -1
- package/scripts/electronWorkflow/modifiers/appCode.mts +2 -131
- package/scripts/i18nWorkflow/protectedPatterns.ts +1 -2
- package/scripts/prebuild.mts +10 -8
- package/scripts/serverLauncher/startServer.js +23 -5
- package/src/app/(backend)/middleware/auth/index.test.ts +8 -4
- package/src/app/(backend)/middleware/auth/index.ts +0 -15
- package/src/app/(backend)/middleware/auth/utils.test.ts +0 -28
- package/src/app/(backend)/middleware/auth/utils.ts +2 -17
- package/src/app/(backend)/webapi/chat/[provider]/route.test.ts +3 -51
- package/src/app/(backend)/webapi/models/[provider]/route.test.ts +8 -4
- package/src/app/[variants]/(auth)/next-auth/signin/AuthSignInBox.tsx +7 -6
- package/src/app/[variants]/(auth)/signup/[[...signup]]/page.tsx +1 -16
- package/src/app/[variants]/(main)/home/_layout/Body/Agent/List/index.tsx +1 -1
- package/src/app/[variants]/(main)/home/features/InputArea/SkillInstallBanner.tsx +13 -13
- package/src/app/[variants]/(main)/home/features/RecentPage/Item.tsx +2 -2
- package/src/app/[variants]/(main)/settings/hooks/useCategory.tsx +3 -21
- package/src/app/[variants]/(main)/settings/profile/features/AvatarRow.tsx +1 -2
- package/src/app/[variants]/(main)/settings/security/index.tsx +1 -22
- package/src/app/[variants]/(main)/settings/skill/features/KlavisSkillItem.tsx +12 -14
- package/src/app/[variants]/(main)/settings/skill/features/LobehubSkillItem.tsx +8 -14
- package/src/app/[variants]/(main)/settings/skill/index.tsx +7 -5
- package/src/app/[variants]/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +2 -35
- package/src/app/[variants]/(mobile)/me/(home)/__tests__/useCategory.test.tsx +0 -20
- package/src/app/[variants]/(mobile)/me/(home)/features/UserBanner.tsx +1 -2
- package/src/app/[variants]/(mobile)/me/profile/features/Category.tsx +3 -13
- package/src/app/[variants]/(mobile)/settings/_layout/Header.tsx +2 -3
- package/src/app/[variants]/share/t/[id]/_layout/index.tsx +1 -1
- package/src/app/[variants]/share/t/[id]/index.tsx +1 -1
- package/src/app/robots.tsx +1 -1
- package/src/envs/auth.ts +2 -27
- package/src/envs/llm.ts +2 -2
- package/src/features/AgentSetting/AgentPlugin/index.tsx +9 -12
- package/src/features/ChatInput/ActionBar/Tools/index.tsx +7 -5
- package/src/features/ChatMiniMap/utils.ts +1 -1
- package/src/features/CommandMenu/SearchResults.tsx +1 -1
- package/src/features/Conversation/ChatList/components/AutoScroll/DebugInspector.tsx +166 -0
- package/src/features/Conversation/ChatList/components/AutoScroll/index.tsx +86 -0
- package/src/features/Conversation/ChatList/components/VirtualizedList.tsx +11 -17
- package/src/features/Conversation/Messages/AgentCouncil/components/AutoScrollShadow.tsx +25 -14
- package/src/features/Conversation/Messages/AgentCouncil/components/CouncilMember.tsx +1 -1
- package/src/features/IntegrationDetailModal/IntegrationDetailContent.tsx +305 -0
- package/src/features/IntegrationDetailModal/index.tsx +21 -283
- package/src/features/MCPPluginDetail/Deployment/index.tsx +1 -1
- package/src/features/MCPPluginDetail/Schema/Prompts.tsx +1 -1
- package/src/features/MCPPluginDetail/Schema/Tools.tsx +1 -1
- package/src/features/ProfileEditor/AgentTool.tsx +14 -20
- package/src/features/ResourceManager/components/Explorer/MasonryView/MasonryFileItem/NoteFileItem.tsx +1 -1
- package/src/features/SkillStore/LobeHubList/index.tsx +50 -87
- package/src/features/SkillStore/Search/index.tsx +1 -1
- package/src/features/SkillStore/{Content.tsx → SkillStoreContent.tsx} +3 -8
- package/src/features/SkillStore/index.tsx +15 -33
- package/src/features/User/UserPanel/PanelContent.tsx +0 -8
- package/src/features/User/__tests__/PanelContent.test.tsx +1 -35
- package/src/features/User/__tests__/UserAvatar.test.tsx +30 -57
- package/src/features/User/__tests__/useMenu.test.tsx +2 -43
- package/src/layout/AuthProvider/index.tsx +0 -5
- package/src/libs/next/config/define-config.ts +6 -0
- package/src/libs/next/proxy/createRouteMatcher.test.ts +121 -0
- package/src/libs/next/proxy/createRouteMatcher.ts +18 -0
- package/src/libs/next/proxy/define-config.ts +4 -53
- package/src/libs/next-auth/adapter/index.ts +1 -2
- package/src/libs/oidc-provider/provider.test.ts +5 -316
- package/src/libs/trpc/lambda/context.test.ts +0 -13
- package/src/libs/trpc/lambda/context.ts +3 -22
- package/src/libs/trpc/middleware/userAuth.ts +2 -4
- package/src/libs/trusted-client/getSessionUser.ts +2 -17
- package/src/locales/default/error.ts +0 -6
- package/src/locales/default/index.ts +0 -2
- package/src/proxy.ts +0 -1
- package/src/server/routers/lambda/__tests__/user.test.ts +0 -71
- package/src/server/routers/lambda/user.ts +6 -63
- package/src/server/services/changelog/index.test.ts +3 -2
- package/src/server/services/changelog/index.ts +1 -1
- package/src/server/services/user/index.ts +0 -83
- package/src/services/chat/index.ts +1 -2
- package/src/services/chat/mecha/agentConfigResolver.test.ts +43 -0
- package/src/services/chat/mecha/agentConfigResolver.ts +3 -1
- package/src/store/chat/slices/aiChat/actions/__tests__/streamingExecutor.test.ts +58 -14
- package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +10 -2
- package/src/store/user/slices/auth/action.test.ts +1 -81
- package/src/store/user/slices/auth/action.ts +3 -28
- package/src/store/user/slices/auth/initialState.ts +1 -18
- package/src/store/user/slices/auth/selectors.test.ts +2 -127
- package/src/store/user/slices/auth/selectors.ts +1 -21
- package/src/utils/errorResponse.ts +1 -4
- package/src/utils/markdownToTxt.ts +20 -0
- package/locales/ar/clerk.json +0 -545
- package/locales/bg-BG/clerk.json +0 -545
- package/locales/de-DE/clerk.json +0 -545
- package/locales/en-US/clerk.json +0 -545
- package/locales/es-ES/clerk.json +0 -545
- package/locales/fa-IR/clerk.json +0 -545
- package/locales/fr-FR/clerk.json +0 -545
- package/locales/it-IT/clerk.json +0 -545
- package/locales/ja-JP/clerk.json +0 -545
- package/locales/ko-KR/clerk.json +0 -545
- package/locales/nl-NL/clerk.json +0 -545
- package/locales/pl-PL/clerk.json +0 -545
- package/locales/pt-BR/clerk.json +0 -545
- package/locales/ru-RU/clerk.json +0 -545
- package/locales/tr-TR/clerk.json +0 -545
- package/locales/vi-VN/clerk.json +0 -545
- package/locales/zh-CN/clerk.json +0 -545
- package/locales/zh-TW/clerk.json +0 -545
- package/src/app/(backend)/api/webhooks/clerk/__tests__/fixtures/createUser.json +0 -73
- package/src/app/(backend)/api/webhooks/clerk/route.ts +0 -95
- package/src/app/(backend)/api/webhooks/clerk/validateRequest.ts +0 -22
- package/src/app/[variants]/(auth)/login/[[...login]]/page.tsx +0 -27
- package/src/app/[variants]/(main)/settings/security/features/ClerkProfile.tsx +0 -67
- package/src/features/Conversation/ChatList/components/AutoScroll.tsx +0 -25
- package/src/layout/AuthProvider/Clerk/UserUpdater.tsx +0 -40
- package/src/layout/AuthProvider/Clerk/index.tsx +0 -54
- package/src/layout/AuthProvider/Clerk/useAppearance.ts +0 -133
- package/src/libs/clerk-auth/index.test.ts +0 -216
- package/src/libs/clerk-auth/index.ts +0 -80
- package/src/locales/default/clerk.ts +0 -677
- package/src/server/services/user/index.test.ts +0 -220
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { type NextRequest } from 'next/server';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { createRouteMatcher } from './createRouteMatcher';
|
|
5
|
+
|
|
6
|
+
// Helper to create a mock NextRequest with a given pathname
|
|
7
|
+
const createMockRequest = (pathname: string): NextRequest =>
|
|
8
|
+
({
|
|
9
|
+
nextUrl: { pathname },
|
|
10
|
+
}) as NextRequest;
|
|
11
|
+
|
|
12
|
+
describe('createRouteMatcher', () => {
|
|
13
|
+
describe('exact path matching', () => {
|
|
14
|
+
it('should match exact paths', () => {
|
|
15
|
+
const matcher = createRouteMatcher(['/signin', '/signup']);
|
|
16
|
+
|
|
17
|
+
expect(matcher(createMockRequest('/signin'))).toBe(true);
|
|
18
|
+
expect(matcher(createMockRequest('/signup'))).toBe(true);
|
|
19
|
+
expect(matcher(createMockRequest('/login'))).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should not match partial paths without wildcard', () => {
|
|
23
|
+
const matcher = createRouteMatcher(['/api']);
|
|
24
|
+
|
|
25
|
+
expect(matcher(createMockRequest('/api'))).toBe(true);
|
|
26
|
+
expect(matcher(createMockRequest('/api/users'))).toBe(false);
|
|
27
|
+
expect(matcher(createMockRequest('/api/'))).toBe(false);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('wildcard pattern matching', () => {
|
|
32
|
+
it('should match paths with (.*) wildcard', () => {
|
|
33
|
+
const matcher = createRouteMatcher(['/api/auth(.*)']);
|
|
34
|
+
|
|
35
|
+
expect(matcher(createMockRequest('/api/auth'))).toBe(true);
|
|
36
|
+
expect(matcher(createMockRequest('/api/auth/'))).toBe(true);
|
|
37
|
+
expect(matcher(createMockRequest('/api/auth/callback'))).toBe(true);
|
|
38
|
+
expect(matcher(createMockRequest('/api/auth/callback/google'))).toBe(true);
|
|
39
|
+
expect(matcher(createMockRequest('/api/other'))).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should match /share(.*) pattern for public share pages', () => {
|
|
43
|
+
const matcher = createRouteMatcher(['/share(.*)']);
|
|
44
|
+
|
|
45
|
+
expect(matcher(createMockRequest('/share'))).toBe(true);
|
|
46
|
+
expect(matcher(createMockRequest('/share/'))).toBe(true);
|
|
47
|
+
expect(matcher(createMockRequest('/share/abc123'))).toBe(true);
|
|
48
|
+
expect(matcher(createMockRequest('/share/t/abc123'))).toBe(true);
|
|
49
|
+
// Note: /shared also matches because (.*) matches 'd' - use /share/(.*) for strict matching
|
|
50
|
+
expect(matcher(createMockRequest('/shared'))).toBe(true);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should match /trpc(.*) pattern', () => {
|
|
54
|
+
const matcher = createRouteMatcher(['/trpc(.*)']);
|
|
55
|
+
|
|
56
|
+
expect(matcher(createMockRequest('/trpc'))).toBe(true);
|
|
57
|
+
expect(matcher(createMockRequest('/trpc/user.get'))).toBe(true);
|
|
58
|
+
expect(matcher(createMockRequest('/trpc/chat.create'))).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should match /next-auth/(.*) pattern', () => {
|
|
62
|
+
const matcher = createRouteMatcher(['/next-auth/(.*)']);
|
|
63
|
+
|
|
64
|
+
expect(matcher(createMockRequest('/next-auth/'))).toBe(true);
|
|
65
|
+
expect(matcher(createMockRequest('/next-auth/signin'))).toBe(true);
|
|
66
|
+
expect(matcher(createMockRequest('/next-auth/callback/github'))).toBe(true);
|
|
67
|
+
expect(matcher(createMockRequest('/next-auth'))).toBe(false); // no trailing slash or path
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('multiple patterns', () => {
|
|
72
|
+
it('should match any of multiple patterns', () => {
|
|
73
|
+
const matcher = createRouteMatcher(['/api/auth(.*)', '/signin', '/share(.*)']);
|
|
74
|
+
|
|
75
|
+
expect(matcher(createMockRequest('/api/auth/callback'))).toBe(true);
|
|
76
|
+
expect(matcher(createMockRequest('/signin'))).toBe(true);
|
|
77
|
+
expect(matcher(createMockRequest('/share/abc'))).toBe(true);
|
|
78
|
+
expect(matcher(createMockRequest('/other'))).toBe(false);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('special regex characters', () => {
|
|
83
|
+
it('should escape special regex characters in patterns', () => {
|
|
84
|
+
const matcher = createRouteMatcher(['/api/v1.0/users']);
|
|
85
|
+
|
|
86
|
+
expect(matcher(createMockRequest('/api/v1.0/users'))).toBe(true);
|
|
87
|
+
expect(matcher(createMockRequest('/api/v1X0/users'))).toBe(false); // . should not match any char
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should handle patterns with multiple special characters', () => {
|
|
91
|
+
const matcher = createRouteMatcher(['/oauth/consent/(.*)']);
|
|
92
|
+
|
|
93
|
+
expect(matcher(createMockRequest('/oauth/consent/'))).toBe(true);
|
|
94
|
+
expect(matcher(createMockRequest('/oauth/consent/abc123'))).toBe(true);
|
|
95
|
+
expect(matcher(createMockRequest('/oauth/consent'))).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('edge cases', () => {
|
|
100
|
+
it('should handle root path', () => {
|
|
101
|
+
const matcher = createRouteMatcher(['/']);
|
|
102
|
+
|
|
103
|
+
expect(matcher(createMockRequest('/'))).toBe(true);
|
|
104
|
+
expect(matcher(createMockRequest('/anything'))).toBe(false);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should handle empty patterns array', () => {
|
|
108
|
+
const matcher = createRouteMatcher([]);
|
|
109
|
+
|
|
110
|
+
expect(matcher(createMockRequest('/'))).toBe(false);
|
|
111
|
+
expect(matcher(createMockRequest('/any/path'))).toBe(false);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should be case sensitive', () => {
|
|
115
|
+
const matcher = createRouteMatcher(['/API/auth(.*)']);
|
|
116
|
+
|
|
117
|
+
expect(matcher(createMockRequest('/API/auth/callback'))).toBe(true);
|
|
118
|
+
expect(matcher(createMockRequest('/api/auth/callback'))).toBe(false);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type NextRequest } from 'next/server';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Creates a route matcher function that checks if a request path matches any of the given patterns
|
|
5
|
+
* @param patterns Array of route patterns - supports `(.*)` as wildcard
|
|
6
|
+
* @returns Function that returns true if the request matches any pattern
|
|
7
|
+
*/
|
|
8
|
+
export function createRouteMatcher(patterns: string[]) {
|
|
9
|
+
const regexPatterns = patterns.map((pattern) => {
|
|
10
|
+
// Escape all special regex chars (including parentheses), then restore (.*) to wildcard
|
|
11
|
+
const regexStr = pattern
|
|
12
|
+
.replaceAll(/[$()*+.?[\\\]^{|}]/g, '\\$&')
|
|
13
|
+
.replaceAll('\\(\\.\\*\\)', '.*');
|
|
14
|
+
return new RegExp(`^${regexStr}$`);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
return (req: NextRequest) => regexPatterns.some((regex) => regex.test(req.nextUrl.pathname));
|
|
18
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
|
|
2
1
|
import debug from 'debug';
|
|
3
2
|
import { type NextRequest, NextResponse } from 'next/server';
|
|
4
3
|
import { UAParser } from 'ua-parser-js';
|
|
@@ -14,10 +13,11 @@ import { type Locales } from '@/locales/resources';
|
|
|
14
13
|
import { parseBrowserLanguage } from '@/utils/locale';
|
|
15
14
|
import { RouteVariants } from '@/utils/server/routeVariants';
|
|
16
15
|
|
|
16
|
+
import { createRouteMatcher } from './createRouteMatcher';
|
|
17
|
+
|
|
17
18
|
// Create debug logger instances
|
|
18
19
|
const logDefault = debug('middleware:default');
|
|
19
20
|
const logNextAuth = debug('middleware:next-auth');
|
|
20
|
-
const logClerk = debug('middleware:clerk');
|
|
21
21
|
const logBetterAuth = debug('middleware:better-auth');
|
|
22
22
|
|
|
23
23
|
// OIDC session pre-sync constant
|
|
@@ -171,11 +171,9 @@ export function defineConfig() {
|
|
|
171
171
|
'/trpc(.*)',
|
|
172
172
|
// next auth
|
|
173
173
|
'/next-auth/(.*)',
|
|
174
|
-
// clerk
|
|
175
|
-
'/login',
|
|
176
|
-
'/signup',
|
|
177
174
|
// better auth
|
|
178
175
|
'/signin',
|
|
176
|
+
'/signup',
|
|
179
177
|
'/verify-email',
|
|
180
178
|
'/reset-password',
|
|
181
179
|
// oauth
|
|
@@ -253,48 +251,6 @@ export function defineConfig() {
|
|
|
253
251
|
return response;
|
|
254
252
|
});
|
|
255
253
|
|
|
256
|
-
const clerkAuthMiddleware = clerkMiddleware(
|
|
257
|
-
async (auth, req) => {
|
|
258
|
-
logClerk('Clerk middleware processing request: %s %s', req.method, req.url);
|
|
259
|
-
|
|
260
|
-
// when enable auth protection, only public route is not protected, others are all protected
|
|
261
|
-
const isProtected = appEnv.ENABLE_AUTH_PROTECTION
|
|
262
|
-
? !isPublicRoute(req)
|
|
263
|
-
: isProtectedRoute(req);
|
|
264
|
-
|
|
265
|
-
logClerk('Route protection status: %s, %s', req.url, isProtected ? 'protected' : 'public');
|
|
266
|
-
|
|
267
|
-
if (isProtected) {
|
|
268
|
-
logClerk('Protecting route: %s', req.url);
|
|
269
|
-
await auth.protect();
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
const response = defaultMiddleware(req);
|
|
273
|
-
|
|
274
|
-
const data = await auth();
|
|
275
|
-
logClerk('Clerk auth status: %O', {
|
|
276
|
-
isSignedIn: !!data.userId,
|
|
277
|
-
userId: data.userId,
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
// If OIDC is enabled and Clerk user is logged in, add OIDC session pre-sync header
|
|
281
|
-
if (authEnv.ENABLE_OIDC && data.userId) {
|
|
282
|
-
logClerk('OIDC session pre-sync: Setting %s = %s', OIDC_SESSION_HEADER, data.userId);
|
|
283
|
-
response.headers.set(OIDC_SESSION_HEADER, data.userId);
|
|
284
|
-
} else if (authEnv.ENABLE_OIDC) {
|
|
285
|
-
logClerk('No Clerk user detected, not setting OIDC session sync header');
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
return response;
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
// https://github.com/lobehub/lobe-chat/pull/3084
|
|
292
|
-
clockSkewInMs: 60 * 60 * 1000,
|
|
293
|
-
signInUrl: '/login',
|
|
294
|
-
signUpUrl: '/signup',
|
|
295
|
-
},
|
|
296
|
-
);
|
|
297
|
-
|
|
298
254
|
const betterAuthMiddleware = async (req: NextRequest) => {
|
|
299
255
|
logBetterAuth('BetterAuth middleware processing request: %s %s', req.method, req.url);
|
|
300
256
|
|
|
@@ -343,16 +299,11 @@ export function defineConfig() {
|
|
|
343
299
|
logDefault('Middleware configuration: %O', {
|
|
344
300
|
enableAuthProtection: appEnv.ENABLE_AUTH_PROTECTION,
|
|
345
301
|
enableBetterAuth: authEnv.NEXT_PUBLIC_ENABLE_BETTER_AUTH,
|
|
346
|
-
enableClerk: authEnv.NEXT_PUBLIC_ENABLE_CLERK_AUTH,
|
|
347
302
|
enableNextAuth: authEnv.NEXT_PUBLIC_ENABLE_NEXT_AUTH,
|
|
348
303
|
enableOIDC: authEnv.ENABLE_OIDC,
|
|
349
304
|
});
|
|
350
305
|
|
|
351
306
|
return {
|
|
352
|
-
middleware: authEnv.
|
|
353
|
-
? clerkAuthMiddleware
|
|
354
|
-
: authEnv.NEXT_PUBLIC_ENABLE_NEXT_AUTH
|
|
355
|
-
? nextAuthMiddleware
|
|
356
|
-
: betterAuthMiddleware,
|
|
307
|
+
middleware: authEnv.NEXT_PUBLIC_ENABLE_NEXT_AUTH ? nextAuthMiddleware : betterAuthMiddleware,
|
|
357
308
|
};
|
|
358
309
|
}
|
|
@@ -23,8 +23,7 @@ interface BackendAdapterResponse {
|
|
|
23
23
|
export const dateKeys = ['expires', 'emailVerified'];
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* @description LobeNextAuthDbAdapter is implemented to handle the database operations
|
|
27
|
-
* for NextAuth, this function do the same things as `src/app/api/webhooks/clerk/route.ts`
|
|
26
|
+
* @description LobeNextAuthDbAdapter is implemented to handle the database operations for NextAuth
|
|
28
27
|
* @returns {Adapter}
|
|
29
28
|
*/
|
|
30
29
|
export function LobeNextAuthDbAdapter(): Adapter {
|
|
@@ -6,7 +6,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
6
6
|
// Mock dependencies
|
|
7
7
|
vi.mock('@/envs/auth', () => ({
|
|
8
8
|
enableBetterAuth: false,
|
|
9
|
-
enableClerk: false,
|
|
10
9
|
enableNextAuth: false,
|
|
11
10
|
}));
|
|
12
11
|
|
|
@@ -38,280 +37,8 @@ describe('OIDC Provider - Market Client Integration', () => {
|
|
|
38
37
|
vi.resetModules();
|
|
39
38
|
});
|
|
40
39
|
|
|
41
|
-
describe('resolveClerkAccount', () => {
|
|
42
|
-
it('should return undefined when Clerk is disabled', async () => {
|
|
43
|
-
// Import with Clerk disabled
|
|
44
|
-
vi.doMock('@/const/auth', () => ({
|
|
45
|
-
enableClerk: false,
|
|
46
|
-
}));
|
|
47
|
-
|
|
48
|
-
// Note: resolveClerkAccount is not exported, but we can test its behavior
|
|
49
|
-
// through the findAccount method with market client
|
|
50
|
-
// For now, we'll test the constants and basic setup
|
|
51
|
-
const module = await import('./provider');
|
|
52
|
-
expect(module.API_AUDIENCE).toBe('urn:lobehub:chat');
|
|
53
|
-
|
|
54
|
-
vi.doUnmock('@/const/auth');
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
it('should handle market client ID constant', () => {
|
|
58
|
-
// The MARKET_CLIENT_ID should match the client in config
|
|
59
|
-
expect(MARKET_CLIENT_ID).toBe('lobehub-market');
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
describe('resolveClerkAccount - with Clerk enabled', () => {
|
|
64
|
-
it('should resolve Clerk user with full profile', async () => {
|
|
65
|
-
const mockClerkUser = {
|
|
66
|
-
id: 'user_123',
|
|
67
|
-
fullName: 'John Doe',
|
|
68
|
-
firstName: 'John',
|
|
69
|
-
lastName: 'Doe',
|
|
70
|
-
username: 'johndoe',
|
|
71
|
-
imageUrl: 'https://example.com/avatar.jpg',
|
|
72
|
-
primaryEmailAddressId: 'email_1',
|
|
73
|
-
emailAddresses: [
|
|
74
|
-
{
|
|
75
|
-
id: 'email_1',
|
|
76
|
-
emailAddress: 'john@example.com',
|
|
77
|
-
verification: { status: 'verified' },
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const mockClerkClient = {
|
|
83
|
-
users: {
|
|
84
|
-
getUser: vi.fn().mockResolvedValue(mockClerkUser),
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
vi.doMock('@/const/auth', () => ({
|
|
89
|
-
enableClerk: true,
|
|
90
|
-
}));
|
|
91
|
-
|
|
92
|
-
vi.doMock('@clerk/nextjs/server', () => ({
|
|
93
|
-
clerkClient: vi.fn().mockResolvedValue(mockClerkClient),
|
|
94
|
-
}));
|
|
95
|
-
|
|
96
|
-
// Import the provider module to access resolveClerkAccount behavior
|
|
97
|
-
const module = await import('./provider');
|
|
98
|
-
|
|
99
|
-
// Verify the module loads correctly
|
|
100
|
-
expect(module.API_AUDIENCE).toBe('urn:lobehub:chat');
|
|
101
|
-
|
|
102
|
-
vi.doUnmock('@/const/auth');
|
|
103
|
-
vi.doUnmock('@clerk/nextjs/server');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should handle Clerk user with only username', async () => {
|
|
107
|
-
const mockClerkUser = {
|
|
108
|
-
id: 'user_123',
|
|
109
|
-
fullName: null,
|
|
110
|
-
firstName: null,
|
|
111
|
-
lastName: null,
|
|
112
|
-
username: 'johndoe',
|
|
113
|
-
imageUrl: null,
|
|
114
|
-
primaryEmailAddressId: 'email_1',
|
|
115
|
-
emailAddresses: [
|
|
116
|
-
{
|
|
117
|
-
id: 'email_1',
|
|
118
|
-
emailAddress: 'john@example.com',
|
|
119
|
-
verification: { status: 'verified' },
|
|
120
|
-
},
|
|
121
|
-
],
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
const mockClerkClient = {
|
|
125
|
-
users: {
|
|
126
|
-
getUser: vi.fn().mockResolvedValue(mockClerkUser),
|
|
127
|
-
},
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
vi.doMock('@/const/auth', () => ({
|
|
131
|
-
enableClerk: true,
|
|
132
|
-
}));
|
|
133
|
-
|
|
134
|
-
vi.doMock('@clerk/nextjs/server', () => ({
|
|
135
|
-
clerkClient: vi.fn().mockResolvedValue(mockClerkClient),
|
|
136
|
-
}));
|
|
137
|
-
|
|
138
|
-
const module = await import('./provider');
|
|
139
|
-
expect(module.API_AUDIENCE).toBe('urn:lobehub:chat');
|
|
140
|
-
|
|
141
|
-
vi.doUnmock('@/const/auth');
|
|
142
|
-
vi.doUnmock('@clerk/nextjs/server');
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
it('should handle Clerk user with firstName and lastName', async () => {
|
|
146
|
-
const mockClerkUser = {
|
|
147
|
-
id: 'user_123',
|
|
148
|
-
fullName: null,
|
|
149
|
-
firstName: 'John',
|
|
150
|
-
lastName: 'Doe',
|
|
151
|
-
username: null,
|
|
152
|
-
imageUrl: null,
|
|
153
|
-
primaryEmailAddressId: 'email_1',
|
|
154
|
-
emailAddresses: [
|
|
155
|
-
{
|
|
156
|
-
id: 'email_1',
|
|
157
|
-
emailAddress: 'john@example.com',
|
|
158
|
-
verification: { status: 'verified' },
|
|
159
|
-
},
|
|
160
|
-
],
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
const mockClerkClient = {
|
|
164
|
-
users: {
|
|
165
|
-
getUser: vi.fn().mockResolvedValue(mockClerkUser),
|
|
166
|
-
},
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
vi.doMock('@/const/auth', () => ({
|
|
170
|
-
enableClerk: true,
|
|
171
|
-
}));
|
|
172
|
-
|
|
173
|
-
vi.doMock('@clerk/nextjs/server', () => ({
|
|
174
|
-
clerkClient: vi.fn().mockResolvedValue(mockClerkClient),
|
|
175
|
-
}));
|
|
176
|
-
|
|
177
|
-
const module = await import('./provider');
|
|
178
|
-
expect(module.API_AUDIENCE).toBe('urn:lobehub:chat');
|
|
179
|
-
|
|
180
|
-
vi.doUnmock('@/const/auth');
|
|
181
|
-
vi.doUnmock('@clerk/nextjs/server');
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
it('should handle Clerk user not found', async () => {
|
|
185
|
-
const mockClerkClient = {
|
|
186
|
-
users: {
|
|
187
|
-
getUser: vi.fn().mockResolvedValue(null),
|
|
188
|
-
},
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
vi.doMock('@/const/auth', () => ({
|
|
192
|
-
enableClerk: true,
|
|
193
|
-
}));
|
|
194
|
-
|
|
195
|
-
vi.doMock('@clerk/nextjs/server', () => ({
|
|
196
|
-
clerkClient: vi.fn().mockResolvedValue(mockClerkClient),
|
|
197
|
-
}));
|
|
198
|
-
|
|
199
|
-
const module = await import('./provider');
|
|
200
|
-
expect(module.API_AUDIENCE).toBe('urn:lobehub:chat');
|
|
201
|
-
|
|
202
|
-
vi.doUnmock('@/const/auth');
|
|
203
|
-
vi.doUnmock('@clerk/nextjs/server');
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it('should handle Clerk API error', async () => {
|
|
207
|
-
const mockClerkClient = {
|
|
208
|
-
users: {
|
|
209
|
-
getUser: vi.fn().mockRejectedValue(new Error('Clerk API error')),
|
|
210
|
-
},
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
vi.doMock('@/const/auth', () => ({
|
|
214
|
-
enableClerk: true,
|
|
215
|
-
}));
|
|
216
|
-
|
|
217
|
-
vi.doMock('@clerk/nextjs/server', () => ({
|
|
218
|
-
clerkClient: vi.fn().mockResolvedValue(mockClerkClient),
|
|
219
|
-
}));
|
|
220
|
-
|
|
221
|
-
const module = await import('./provider');
|
|
222
|
-
expect(module.API_AUDIENCE).toBe('urn:lobehub:chat');
|
|
223
|
-
|
|
224
|
-
vi.doUnmock('@/const/auth');
|
|
225
|
-
vi.doUnmock('@clerk/nextjs/server');
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
it('should handle email without verification', async () => {
|
|
229
|
-
const mockClerkUser = {
|
|
230
|
-
id: 'user_123',
|
|
231
|
-
fullName: 'John Doe',
|
|
232
|
-
firstName: 'John',
|
|
233
|
-
lastName: 'Doe',
|
|
234
|
-
username: 'johndoe',
|
|
235
|
-
imageUrl: 'https://example.com/avatar.jpg',
|
|
236
|
-
primaryEmailAddressId: 'email_1',
|
|
237
|
-
emailAddresses: [
|
|
238
|
-
{
|
|
239
|
-
id: 'email_1',
|
|
240
|
-
emailAddress: 'john@example.com',
|
|
241
|
-
verification: null,
|
|
242
|
-
},
|
|
243
|
-
],
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
const mockClerkClient = {
|
|
247
|
-
users: {
|
|
248
|
-
getUser: vi.fn().mockResolvedValue(mockClerkUser),
|
|
249
|
-
},
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
vi.doMock('@/const/auth', () => ({
|
|
253
|
-
enableClerk: true,
|
|
254
|
-
}));
|
|
255
|
-
|
|
256
|
-
vi.doMock('@clerk/nextjs/server', () => ({
|
|
257
|
-
clerkClient: vi.fn().mockResolvedValue(mockClerkClient),
|
|
258
|
-
}));
|
|
259
|
-
|
|
260
|
-
const module = await import('./provider');
|
|
261
|
-
expect(module.API_AUDIENCE).toBe('urn:lobehub:chat');
|
|
262
|
-
|
|
263
|
-
vi.doUnmock('@/const/auth');
|
|
264
|
-
vi.doUnmock('@clerk/nextjs/server');
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
it('should use first email when no primary email is set', async () => {
|
|
268
|
-
const mockClerkUser = {
|
|
269
|
-
id: 'user_123',
|
|
270
|
-
fullName: 'John Doe',
|
|
271
|
-
firstName: 'John',
|
|
272
|
-
lastName: 'Doe',
|
|
273
|
-
username: 'johndoe',
|
|
274
|
-
imageUrl: 'https://example.com/avatar.jpg',
|
|
275
|
-
primaryEmailAddressId: null,
|
|
276
|
-
emailAddresses: [
|
|
277
|
-
{
|
|
278
|
-
id: 'email_2',
|
|
279
|
-
emailAddress: 'john.first@example.com',
|
|
280
|
-
verification: { status: 'verified' },
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
id: 'email_3',
|
|
284
|
-
emailAddress: 'john.second@example.com',
|
|
285
|
-
verification: { status: 'verified' },
|
|
286
|
-
},
|
|
287
|
-
],
|
|
288
|
-
};
|
|
289
|
-
|
|
290
|
-
const mockClerkClient = {
|
|
291
|
-
users: {
|
|
292
|
-
getUser: vi.fn().mockResolvedValue(mockClerkUser),
|
|
293
|
-
},
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
vi.doMock('@/const/auth', () => ({
|
|
297
|
-
enableClerk: true,
|
|
298
|
-
}));
|
|
299
|
-
|
|
300
|
-
vi.doMock('@clerk/nextjs/server', () => ({
|
|
301
|
-
clerkClient: vi.fn().mockResolvedValue(mockClerkClient),
|
|
302
|
-
}));
|
|
303
|
-
|
|
304
|
-
const module = await import('./provider');
|
|
305
|
-
expect(module.API_AUDIENCE).toBe('urn:lobehub:chat');
|
|
306
|
-
|
|
307
|
-
vi.doUnmock('@/const/auth');
|
|
308
|
-
vi.doUnmock('@clerk/nextjs/server');
|
|
309
|
-
});
|
|
310
|
-
});
|
|
311
|
-
|
|
312
40
|
describe('Market Client Logic', () => {
|
|
313
41
|
it('should identify market client correctly', () => {
|
|
314
|
-
// The market client should route to Clerk resolution
|
|
315
42
|
expect(MARKET_CLIENT_ID).toBe('lobehub-market');
|
|
316
43
|
});
|
|
317
44
|
|
|
@@ -445,32 +172,7 @@ describe('OIDC Provider - Market Client Integration', () => {
|
|
|
445
172
|
});
|
|
446
173
|
|
|
447
174
|
describe('Business Logic Scenarios', () => {
|
|
448
|
-
describe('Scenario 1:
|
|
449
|
-
it('should route market client to Clerk when enableClerk is true', () => {
|
|
450
|
-
// Business: When user accesses from marketplace, use Clerk for SSO
|
|
451
|
-
const scenario = {
|
|
452
|
-
client: 'lobehub-market',
|
|
453
|
-
authProvider: 'Clerk',
|
|
454
|
-
useCase: 'Marketplace SSO - users login via Clerk on marketplace',
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
expect(scenario.client).toBe(MARKET_CLIENT_ID);
|
|
458
|
-
expect(scenario.authProvider).toBe('Clerk');
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
it('should return undefined for market client when Clerk is disabled', () => {
|
|
462
|
-
// Business: Market requires Clerk, if disabled, auth fails
|
|
463
|
-
const scenario = {
|
|
464
|
-
client: 'lobehub-market',
|
|
465
|
-
clerkEnabled: false,
|
|
466
|
-
expectedResult: 'undefined (auth fails)',
|
|
467
|
-
};
|
|
468
|
-
|
|
469
|
-
expect(scenario.expectedResult).toBe('undefined (auth fails)');
|
|
470
|
-
});
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
describe('Scenario 2: Desktop Client + Local Database', () => {
|
|
175
|
+
describe('Scenario 1: Desktop Client + Local Database', () => {
|
|
474
176
|
it('should use local UserModel for desktop client', () => {
|
|
475
177
|
// Business: Desktop app uses local database for user management
|
|
476
178
|
const scenario = {
|
|
@@ -484,7 +186,7 @@ describe('OIDC Provider - Market Client Integration', () => {
|
|
|
484
186
|
});
|
|
485
187
|
});
|
|
486
188
|
|
|
487
|
-
describe('Scenario
|
|
189
|
+
describe('Scenario 2: Mobile Client + Local Database', () => {
|
|
488
190
|
it('should use local UserModel for mobile client', () => {
|
|
489
191
|
// Business: Mobile app uses local database for user management
|
|
490
192
|
const scenario = {
|
|
@@ -498,22 +200,9 @@ describe('OIDC Provider - Market Client Integration', () => {
|
|
|
498
200
|
});
|
|
499
201
|
});
|
|
500
202
|
|
|
501
|
-
describe('Scenario
|
|
502
|
-
it('should generate
|
|
503
|
-
// Business:
|
|
504
|
-
const marketClaims = {
|
|
505
|
-
source: 'Clerk API',
|
|
506
|
-
fields: ['sub', 'name', 'picture', 'email', 'email_verified'],
|
|
507
|
-
nameResolution: 'fullName || firstName+lastName || username || id',
|
|
508
|
-
};
|
|
509
|
-
|
|
510
|
-
expect(marketClaims.source).toBe('Clerk API');
|
|
511
|
-
expect(marketClaims.fields).toContain('name');
|
|
512
|
-
expect(marketClaims.fields).toContain('email');
|
|
513
|
-
});
|
|
514
|
-
|
|
515
|
-
it('should generate database-based claims for non-market clients', () => {
|
|
516
|
-
// Business: Desktop/Mobile users get profile/email from local DB
|
|
203
|
+
describe('Scenario 3: Claims Generation', () => {
|
|
204
|
+
it('should generate database-based claims for clients', () => {
|
|
205
|
+
// Business: Users get profile/email from local DB
|
|
517
206
|
const localClaims = {
|
|
518
207
|
source: 'UserModel (PostgreSQL/PGLite)',
|
|
519
208
|
fields: ['sub', 'name', 'picture', 'email', 'email_verified'],
|
|
@@ -8,7 +8,6 @@ describe('createContextInner', () => {
|
|
|
8
8
|
|
|
9
9
|
expect(context).toMatchObject({
|
|
10
10
|
authorizationHeader: undefined,
|
|
11
|
-
clerkAuth: undefined,
|
|
12
11
|
marketAccessToken: undefined,
|
|
13
12
|
nextAuth: undefined,
|
|
14
13
|
oidcAuth: undefined,
|
|
@@ -59,18 +58,6 @@ describe('createContextInner', () => {
|
|
|
59
58
|
expect(context.oidcAuth).toEqual(oidcAuth);
|
|
60
59
|
});
|
|
61
60
|
|
|
62
|
-
it('should create context with Clerk auth data', async () => {
|
|
63
|
-
const clerkAuth = {
|
|
64
|
-
userId: 'clerk-user-id',
|
|
65
|
-
sessionId: 'session-id',
|
|
66
|
-
getToken: async () => 'clerk-token',
|
|
67
|
-
} as any;
|
|
68
|
-
|
|
69
|
-
const context = await createContextInner({ clerkAuth });
|
|
70
|
-
|
|
71
|
-
expect(context.clerkAuth).toBe(clerkAuth);
|
|
72
|
-
});
|
|
73
|
-
|
|
74
61
|
it('should create context with NextAuth user data', async () => {
|
|
75
62
|
const nextAuth = {
|
|
76
63
|
id: 'next-auth-user-id',
|
|
@@ -7,11 +7,10 @@ import { type NextRequest } from 'next/server';
|
|
|
7
7
|
import {
|
|
8
8
|
LOBE_CHAT_AUTH_HEADER,
|
|
9
9
|
LOBE_CHAT_OIDC_AUTH_HEADER,
|
|
10
|
+
authEnv,
|
|
10
11
|
enableBetterAuth,
|
|
11
|
-
enableClerk,
|
|
12
12
|
enableNextAuth,
|
|
13
|
-
|
|
14
|
-
import { ClerkAuth, type IClerkAuth } from '@/libs/clerk-auth';
|
|
13
|
+
} from '@/envs/auth';
|
|
15
14
|
import { validateOIDCJWT } from '@/libs/oidc-provider/jwt';
|
|
16
15
|
|
|
17
16
|
// Create context logger namespace
|
|
@@ -41,7 +40,6 @@ export interface OIDCAuth {
|
|
|
41
40
|
|
|
42
41
|
export interface AuthContext {
|
|
43
42
|
authorizationHeader?: string | null;
|
|
44
|
-
clerkAuth?: IClerkAuth;
|
|
45
43
|
clientIp?: string | null;
|
|
46
44
|
jwtPayload?: ClientSecretPayload | null;
|
|
47
45
|
marketAccessToken?: string;
|
|
@@ -59,7 +57,6 @@ export interface AuthContext {
|
|
|
59
57
|
*/
|
|
60
58
|
export const createContextInner = async (params?: {
|
|
61
59
|
authorizationHeader?: string | null;
|
|
62
|
-
clerkAuth?: IClerkAuth;
|
|
63
60
|
clientIp?: string | null;
|
|
64
61
|
marketAccessToken?: string;
|
|
65
62
|
nextAuth?: User;
|
|
@@ -72,7 +69,6 @@ export const createContextInner = async (params?: {
|
|
|
72
69
|
|
|
73
70
|
return {
|
|
74
71
|
authorizationHeader: params?.authorizationHeader,
|
|
75
|
-
clerkAuth: params?.clerkAuth,
|
|
76
72
|
clientIp: params?.clientIp,
|
|
77
73
|
marketAccessToken: params?.marketAccessToken,
|
|
78
74
|
nextAuth: params?.nextAuth,
|
|
@@ -163,22 +159,7 @@ export const createLambdaContext = async (request: NextRequest): Promise<LambdaC
|
|
|
163
159
|
}
|
|
164
160
|
}
|
|
165
161
|
|
|
166
|
-
// If OIDC is not enabled or validation fails, try
|
|
167
|
-
if (enableClerk) {
|
|
168
|
-
log('Attempting Clerk authentication');
|
|
169
|
-
const clerkAuth = new ClerkAuth();
|
|
170
|
-
const result = clerkAuth.getAuthFromRequest(request);
|
|
171
|
-
auth = result.clerkAuth;
|
|
172
|
-
userId = result.userId;
|
|
173
|
-
log('Clerk authentication result, userId: %s', userId || 'not authenticated');
|
|
174
|
-
|
|
175
|
-
return createContextInner({
|
|
176
|
-
clerkAuth: auth,
|
|
177
|
-
...commonContext,
|
|
178
|
-
userId,
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
162
|
+
// If OIDC is not enabled or validation fails, try other authentication methods
|
|
182
163
|
if (enableBetterAuth) {
|
|
183
164
|
log('Attempting Better Auth authentication');
|
|
184
165
|
try {
|