@lobehub/lobehub 2.0.0-next.132 → 2.0.0-next.134

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/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.134](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.133...v2.0.0-next.134)
6
+
7
+ <sup>Released on **2025-11-29**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Betterauth public url auto detect from VERCEL_URL.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Betterauth public url auto detect from VERCEL_URL, closes [#10493](https://github.com/lobehub/lobe-chat/issues/10493) ([b5bf8ad](https://github.com/lobehub/lobe-chat/commit/b5bf8ad))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ## [Version 2.0.0-next.133](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.132...v2.0.0-next.133)
31
+
32
+ <sup>Released on **2025-11-29**</sup>
33
+
34
+ #### 🐛 Bug Fixes
35
+
36
+ - **misc**: Betterauth name should mapped to fullName.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's fixed
44
+
45
+ - **misc**: Betterauth name should mapped to fullName, closes [#10490](https://github.com/lobehub/lobe-chat/issues/10490) ([7babdc1](https://github.com/lobehub/lobe-chat/commit/7babdc1))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ## [Version 2.0.0-next.132](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.131...v2.0.0-next.132)
6
56
 
7
57
  <sup>Released on **2025-11-29**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "fixes": [
5
+ "Betterauth public url auto detect from VERCEL_URL."
6
+ ]
7
+ },
8
+ "date": "2025-11-29",
9
+ "version": "2.0.0-next.134"
10
+ },
11
+ {
12
+ "children": {
13
+ "fixes": [
14
+ "Betterauth name should mapped to fullName."
15
+ ]
16
+ },
17
+ "date": "2025-11-29",
18
+ "version": "2.0.0-next.133"
19
+ },
2
20
  {
3
21
  "children": {
4
22
  "fixes": [
@@ -39,12 +39,18 @@ By setting the environment variables `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CL
39
39
 
40
40
  To enable Better Auth in LobeChat, set the following environment variables:
41
41
 
42
- | Environment Variable | Type | Description |
43
- | -------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
44
- | `NEXT_PUBLIC_ENABLE_BETTER_AUTH` | Required | Set to `1` to enable Better Auth service |
45
- | `AUTH_SECRET` | Required | Key used to encrypt session tokens. Generate using: `openssl rand -base64 32` |
46
- | `NEXT_PUBLIC_AUTH_URL` | Optional | The URL accessible from the browser for Better Auth callbacks. Only set this if the default generated URL is incorrect |
47
- | `AUTH_SSO_PROVIDERS` | Optional | Comma-separated list of enabled SSO providers, e.g., `google,github,microsoft` |
42
+ | Environment Variable | Type | Description |
43
+ | -------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
44
+ | `NEXT_PUBLIC_ENABLE_BETTER_AUTH` | Required | Set to `1` to enable Better Auth service |
45
+ | `AUTH_SECRET` | Required | Key used to encrypt session tokens. Generate using: `openssl rand -base64 32` |
46
+ | `NEXT_PUBLIC_AUTH_URL` | Required | The browser-accessible base URL for Better Auth (e.g., `http://localhost:3010`, `https://lobechat.com`). Optional for Vercel deployments (auto-detected from `VERCEL_URL`) |
47
+ | `AUTH_SSO_PROVIDERS` | Optional | Comma-separated list of enabled SSO providers, e.g., `google,github,microsoft` |
48
+
49
+ <Callout type={'error'}>
50
+ **Important**: Better Auth is currently only suitable for **fresh deployments**. If you are already using NextAuth or Clerk and have existing user data in your database, **do not switch to Better Auth yet**, otherwise existing users will not be able to log in.
51
+
52
+ We are developing user data migration tools from NextAuth/Clerk to Better Auth. Documentation will be updated once the migration solution is complete. For progress updates, please follow [GitHub Issue #10456](https://github.com/lobehub/lobe-chat/issues/10456).
53
+ </Callout>
48
54
 
49
55
  <Callout type={'warning'}>
50
56
  If you build/deploy with the official Docker image, the defaults keep **NextAuth enabled** and **Better
@@ -37,12 +37,18 @@ LobeChat 与 Clerk 做了深度集成,能够为用户提供一个更加安全
37
37
 
38
38
  要在 LobeChat 中启用 Better Auth,请设置以下环境变量:
39
39
 
40
- | 环境变量 | 类型 | 描述 |
41
- | -------------------------------- | -- | ------------------------------------------------ |
42
- | `NEXT_PUBLIC_ENABLE_BETTER_AUTH` | 必选 | 设置为 `1` 以启用 Better Auth 服务 |
43
- | `AUTH_SECRET` | 必选 | 用于加密会话令牌的密钥。使用以下命令生成:`openssl rand -base64 32` |
44
- | `NEXT_PUBLIC_AUTH_URL` | 可选 | 浏览器可访问的 Better Auth 回调 URL。仅在默认生成的 URL 不正确时设置 |
45
- | `AUTH_SSO_PROVIDERS` | 可选 | 启用的 SSO 提供商列表,以逗号分隔,例如 `google,github,microsoft` |
40
+ | 环境变量 | 类型 | 描述 |
41
+ | -------------------------------- | -- | ---------------------------------------------------------------------------------------------------------------- |
42
+ | `NEXT_PUBLIC_ENABLE_BETTER_AUTH` | 必选 | 设置为 `1` 以启用 Better Auth 服务 |
43
+ | `AUTH_SECRET` | 必选 | 用于加密会话令牌的密钥。使用以下命令生成:`openssl rand -base64 32` |
44
+ | `NEXT_PUBLIC_AUTH_URL` | 必选 | 浏览器可访问的 Better Auth 基础 URL(例如 `http://localhost:3010`、`https://lobechat.com`)。Vercel 部署时可选(会自动从 `VERCEL_URL` 获取) |
45
+ | `AUTH_SSO_PROVIDERS` | 可选 | 启用的 SSO 提供商列表,以逗号分隔,例如 `google,github,microsoft` |
46
+
47
+ <Callout type={'error'}>
48
+ **重要提示**:Better Auth 目前仅适用于**全新部署**的场景。如果你已经使用 NextAuth 或 Clerk 并且数据库中存在用户数据,**请暂时不要切换到 Better Auth**,否则现有用户将无法登录。
49
+
50
+ 我们正在开发从 NextAuth/Clerk 到 Better Auth 的用户数据迁移工具,迁移方案完成后会更新文档。相关进度请关注 [GitHub Issue #10456](https://github.com/lobehub/lobe-chat/issues/10456)。
51
+ </Callout>
46
52
 
47
53
  <Callout type={'warning'}>
48
54
  若使用官方 Docker 镜像构建 / 部署,默认是 **开启 NextAuth、关闭 Better Auth**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.132",
3
+ "version": "2.0.0-next.134",
4
4
  "description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -1,4 +1,7 @@
1
- export const enableClerk = !!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY;
1
+ export const enableClerk =
2
+ process.env.NEXT_PUBLIC_ENABLE_CLERK_AUTH === '1'
3
+ ? true
4
+ : !!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY;
2
5
  export const enableBetterAuth = process.env.NEXT_PUBLIC_ENABLE_BETTER_AUTH === '1';
3
6
  export const enableNextAuth = process.env.NEXT_PUBLIC_ENABLE_NEXT_AUTH === '1';
4
7
  export const enableAuth = enableClerk || enableBetterAuth || enableNextAuth || false;
@@ -4,6 +4,8 @@ import { RequestFilteringAgentOptions, useAgent as ssrfAgent } from 'request-fil
4
4
  /**
5
5
  * SSRF-safe fetch implementation for server-side use
6
6
  * Uses request-filtering-agent to prevent requests to private IP addresses
7
+ *
8
+ * @see https://lobehub.com/docs/self-hosting/environment-variables/basic#ssrf-allow-private-ip-address
7
9
  */
8
10
  // eslint-disable-next-line no-undef
9
11
  export const ssrfSafeFetch = async (url: string, options?: RequestInit): Promise<Response> => {
@@ -31,7 +33,8 @@ export const ssrfSafeFetch = async (url: string, options?: RequestInit): Promise
31
33
  } catch (error) {
32
34
  console.error('SSRF-safe fetch error:', error);
33
35
  throw new Error(
34
- `SSRF-safe fetch failed: ${error instanceof Error ? error.message : String(error)}`,
36
+ `SSRF-safe fetch failed: ${error instanceof Error ? error.message : String(error)}. ` +
37
+ 'See: https://lobehub.com/docs/self-hosting/environment-variables/basic#ssrf-allow-private-ip-address',
35
38
  );
36
39
  }
37
40
  };
package/src/auth.ts CHANGED
@@ -21,6 +21,42 @@ const enableMagicLink = authEnv.NEXT_PUBLIC_ENABLE_MAGIC_LINK;
21
21
 
22
22
  const { socialProviders, genericOAuthProviders } = initBetterAuthSSOProviders();
23
23
 
24
+ /**
25
+ * Normalize a URL-like string to an origin with https fallback.
26
+ */
27
+ const normalizeOrigin = (url?: string) => {
28
+ if (!url) return undefined;
29
+
30
+ try {
31
+ const normalizedUrl = url.startsWith('http') ? url : `https://${url}`;
32
+
33
+ return new URL(normalizedUrl).origin;
34
+ } catch {
35
+ return undefined;
36
+ }
37
+ };
38
+
39
+ /**
40
+ * Build trusted origins with env override and Vercel-aware defaults.
41
+ */
42
+ const getTrustedOrigins = () => {
43
+ if (authEnv.AUTH_TRUSTED_ORIGINS) {
44
+ const originsFromEnv = authEnv.AUTH_TRUSTED_ORIGINS.split(',')
45
+ .map((item) => normalizeOrigin(item.trim()))
46
+ .filter(Boolean) as string[];
47
+
48
+ if (originsFromEnv.length > 0) return Array.from(new Set(originsFromEnv));
49
+ }
50
+
51
+ const defaults = [
52
+ authEnv.NEXT_PUBLIC_AUTH_URL,
53
+ normalizeOrigin(process.env.VERCEL_BRANCH_URL),
54
+ normalizeOrigin(process.env.VERCEL_URL),
55
+ ].filter(Boolean) as string[];
56
+
57
+ return defaults.length > 0 ? Array.from(new Set(defaults)) : undefined;
58
+ };
59
+
24
60
  export const auth = betterAuth({
25
61
  account: {
26
62
  accountLinking: {
@@ -32,6 +68,7 @@ export const auth = betterAuth({
32
68
  // Use renamed env vars (fallback to next-auth vars is handled in src/envs/auth.ts)
33
69
  baseURL: authEnv.NEXT_PUBLIC_AUTH_URL,
34
70
  secret: authEnv.AUTH_SECRET,
71
+ trustedOrigins: getTrustedOrigins(),
35
72
 
36
73
  database: drizzleAdapter(serverDB, {
37
74
  provider: 'pg',
@@ -104,14 +141,15 @@ export const auth = betterAuth({
104
141
 
105
142
  user: {
106
143
  additionalFields: {
107
- fullName: {
144
+ username: {
108
145
  required: false,
109
146
  type: 'string',
110
147
  },
111
148
  },
112
149
  fields: {
113
150
  image: 'avatar',
114
- name: 'username',
151
+ // NOTE: use drizzle filed instead of db field, so use fullName instead of full_name
152
+ name: 'fullName',
115
153
  },
116
154
  modelName: 'users',
117
155
  },
package/src/envs/auth.ts CHANGED
@@ -2,6 +2,37 @@
2
2
  import { createEnv } from '@t3-oss/env-nextjs';
3
3
  import { z } from 'zod';
4
4
 
5
+ import { enableBetterAuth, enableClerk, enableNextAuth } from '@/const/auth';
6
+
7
+ /**
8
+ * Resolve public auth URL with compatibility fallbacks for NextAuth and Vercel deployments.
9
+ */
10
+ const resolvePublicAuthUrl = () => {
11
+ if (process.env.NEXT_PUBLIC_AUTH_URL) return process.env.NEXT_PUBLIC_AUTH_URL;
12
+
13
+ if (process.env.NEXTAUTH_URL) {
14
+ try {
15
+ return new URL(process.env.NEXTAUTH_URL).origin;
16
+ } catch {
17
+ // ignore invalid NEXTAUTH_URL
18
+ }
19
+ }
20
+
21
+ if (process.env.VERCEL_URL) {
22
+ try {
23
+ const normalizedVercelUrl = process.env.VERCEL_URL.startsWith('http')
24
+ ? process.env.VERCEL_URL
25
+ : `https://${process.env.VERCEL_URL}`;
26
+
27
+ return new URL(normalizedVercelUrl).origin;
28
+ } catch {
29
+ // ignore invalid Vercel URL
30
+ }
31
+ }
32
+
33
+ return undefined;
34
+ };
35
+
5
36
  declare global {
6
37
  // eslint-disable-next-line @typescript-eslint/no-namespace
7
38
  namespace NodeJS {
@@ -16,6 +47,7 @@ declare global {
16
47
  NEXT_PUBLIC_AUTH_URL?: string;
17
48
  NEXT_PUBLIC_AUTH_EMAIL_VERIFICATION?: string;
18
49
  AUTH_SSO_PROVIDERS?: string;
50
+ AUTH_TRUSTED_ORIGINS?: string;
19
51
 
20
52
  // ===== Next Auth ===== //
21
53
  NEXT_AUTH_SECRET?: string;
@@ -134,6 +166,7 @@ export const getAuthConfig = () => {
134
166
  // ---------------------------------- better auth ----------------------------------
135
167
  AUTH_SECRET: z.string().optional(),
136
168
  AUTH_SSO_PROVIDERS: z.string().optional().default(''),
169
+ AUTH_TRUSTED_ORIGINS: z.string().optional(),
137
170
 
138
171
  // ---------------------------------- next auth ----------------------------------
139
172
  NEXT_AUTH_SECRET: z.string().optional(),
@@ -228,23 +261,22 @@ export const getAuthConfig = () => {
228
261
 
229
262
  runtimeEnv: {
230
263
  // Clerk
231
- NEXT_PUBLIC_ENABLE_CLERK_AUTH: !!process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
264
+ NEXT_PUBLIC_ENABLE_CLERK_AUTH: enableClerk,
232
265
  NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY: process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY,
233
266
  CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
234
267
  CLERK_WEBHOOK_SECRET: process.env.CLERK_WEBHOOK_SECRET,
235
268
 
236
269
  // ---------------------------------- better auth ----------------------------------
237
- NEXT_PUBLIC_ENABLE_BETTER_AUTH: process.env.NEXT_PUBLIC_ENABLE_BETTER_AUTH === '1',
238
- // Fallback to NEXTAUTH_URL origin for seamless migration from next-auth
239
- NEXT_PUBLIC_AUTH_URL:
240
- process.env.NEXT_PUBLIC_AUTH_URL ||
241
- (process.env.NEXTAUTH_URL ? new URL(process.env.NEXTAUTH_URL).origin : undefined),
270
+ NEXT_PUBLIC_ENABLE_BETTER_AUTH: enableBetterAuth,
271
+ // Fallback to NEXTAUTH_URL origin or Vercel deployment domain for seamless migration from next-auth
272
+ NEXT_PUBLIC_AUTH_URL: resolvePublicAuthUrl(),
242
273
  NEXT_PUBLIC_AUTH_EMAIL_VERIFICATION: process.env.NEXT_PUBLIC_AUTH_EMAIL_VERIFICATION === '1',
243
274
  NEXT_PUBLIC_ENABLE_MAGIC_LINK: process.env.NEXT_PUBLIC_ENABLE_MAGIC_LINK === '1',
244
275
  // Fallback to NEXT_AUTH_SECRET for seamless migration from next-auth
245
276
  AUTH_SECRET: process.env.AUTH_SECRET || process.env.NEXT_AUTH_SECRET,
246
277
  // Fallback to NEXT_AUTH_SSO_PROVIDERS for seamless migration from next-auth
247
278
  AUTH_SSO_PROVIDERS: process.env.AUTH_SSO_PROVIDERS || process.env.NEXT_AUTH_SSO_PROVIDERS,
279
+ AUTH_TRUSTED_ORIGINS: process.env.AUTH_TRUSTED_ORIGINS,
248
280
 
249
281
  // better-auth env for Cognito provider is different from next-auth's one
250
282
  AUTH_COGNITO_DOMAIN: process.env.AUTH_COGNITO_DOMAIN,
@@ -252,7 +284,7 @@ export const getAuthConfig = () => {
252
284
  AUTH_COGNITO_USERPOOL_ID: process.env.AUTH_COGNITO_USERPOOL_ID,
253
285
 
254
286
  // ---------------------------------- next auth ----------------------------------
255
- NEXT_PUBLIC_ENABLE_NEXT_AUTH: process.env.NEXT_PUBLIC_ENABLE_NEXT_AUTH === '1',
287
+ NEXT_PUBLIC_ENABLE_NEXT_AUTH: enableNextAuth,
256
288
  NEXT_AUTH_SSO_PROVIDERS: process.env.NEXT_AUTH_SSO_PROVIDERS,
257
289
  NEXT_AUTH_SECRET: process.env.NEXT_AUTH_SECRET,
258
290
  NEXT_AUTH_DEBUG: !!process.env.NEXT_AUTH_DEBUG,
@@ -31,9 +31,9 @@ const UserUpdater = memo(() => {
31
31
  // Preserve avatar from settings, don't override with auth provider value
32
32
  avatar: userAvatar || '',
33
33
  email: betterAuthUser.email,
34
- fullName: betterAuthUser.fullName,
34
+ fullName: betterAuthUser.name,
35
35
  id: betterAuthUser.id,
36
- username: betterAuthUser.name,
36
+ username: betterAuthUser.username,
37
37
  } as LobeUser;
38
38
 
39
39
  // Update user data in store
@@ -104,7 +104,7 @@ export const initBetterAuthSSOProviders = () => {
104
104
  if (config) {
105
105
  // the generic oidc callback url is /api/auth/oauth2/callback/{providerId}
106
106
  // different from builtin providers' /api/auth/callback/{providerId}
107
- config.redirectURI = `${authEnv.NEXT_PUBLIC_AUTH_URL}/api/auth/callback/${definition.id}`;
107
+ config.redirectURI = `${authEnv.NEXT_PUBLIC_AUTH_URL || ''}/api/auth/callback/${definition.id}`;
108
108
  genericOAuthProviders.push(config);
109
109
  }
110
110
  }
@@ -5,7 +5,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
5
 
6
6
  // Mock dependencies
7
7
  vi.mock('@/const/auth', () => ({
8
+ enableBetterAuth: false,
8
9
  enableClerk: false,
10
+ enableNextAuth: false,
9
11
  }));
10
12
 
11
13
  vi.mock('@/envs/app', () => ({
@@ -29,7 +29,9 @@ vi.mock('@/server/modules/S3');
29
29
  vi.mock('@/server/services/user');
30
30
  vi.mock('@/server/services/nextAuthUser');
31
31
  vi.mock('@/const/auth', () => ({
32
+ enableBetterAuth: false,
32
33
  enableClerk: true,
34
+ enableNextAuth: false,
33
35
  }));
34
36
 
35
37
  describe('userRouter', () => {