From ac2bf688046ad774182ef1143be3727527bcd36c Mon Sep 17 00:00:00 2001
From: Zhijie He <hezhijie0327@hotmail.com>
Date: Tue, 27 Aug 2024 21:09:09 +0800
Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20Supports=20Cloudflare=20Zer?=
 =?UTF-8?q?o=20Trust=20login=20(#3624)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

* ✨ feat: Supports Cloudflare Zero Trust login

* 📝 docs: add doc for Cloudflare Zero Trust

* ♻️ refactor: cleanup

* ♻️ refactor: rollback checks
---
 .../auth/next-auth/cloudflare-zero-trust.mdx  | 68 +++++++++++++++++++
 .../next-auth/cloudflare-zero-trust.zh-CN.mdx | 63 +++++++++++++++++
 .../environment-variables/auth.mdx            | 23 +++++++
 .../environment-variables/auth.zh-CN.mdx      | 23 +++++++
 src/config/auth.ts                            | 10 +++
 .../sso-providers/cloudflare-zero-trust.ts    | 35 ++++++++++
 src/libs/next-auth/sso-providers/index.ts     |  3 +-
 7 files changed, 224 insertions(+), 1 deletion(-)
 create mode 100644 docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.mdx
 create mode 100644 docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.zh-CN.mdx
 create mode 100644 src/libs/next-auth/sso-providers/cloudflare-zero-trust.ts

diff --git a/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.mdx b/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.mdx
new file mode 100644
index 0000000000000..7193af36b2684
--- /dev/null
+++ b/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.mdx
@@ -0,0 +1,68 @@
+---
+title: Configuring Cloudflare Zero Trust Authentication Service for LobeChat
+description: >-
+  Learn how to configure Cloudflare Zero Trust for Single Sign-On (SSO) for LobeChat,
+  including creating an application provider, setting environment variables, and
+  deployment instructions.
+tags:
+  - Cloudflare Zero Trust
+  - Single Sign-On (SSO)
+  - LobeChat Authentication
+  - Environment Variables
+  - Deployment Instructions
+---
+
+# Configuring Cloudflare Zero Trust Authentication Service
+
+## Cloudflare Zero Trust Configuration Flow
+
+<Steps>
+### Creating an Application in Cloudflare Zero Trust
+
+We assume you are already familiar with using the Cloudflare Zero Trust platform and that your LobeChat instance is deployed at `https://chat.example.com`.
+
+First, we need to visit `https://one.dash.cloudflare.com/` and navigate to `Access - Applications`.
+
+![image](https://github.com/user-attachments/assets/4d671a7c-5d94-4c4b-b4fd-71a5a0e9d227)
+
+Now, on the current page, click `Add an application` and select `SaaS`.
+
+![image](https://github.com/user-attachments/assets/3da4c8c4-88c6-40a9-8005-6a0a44aa3b1f)
+
+In the `Application` text box, enter the application name, such as `LobeChat SSO`. Then click `Select OIDC`, followed by clicking `Add application`.
+
+![image](https://github.com/user-attachments/assets/16cd9aef-c87b-48a4-95c0-b666082e7515)
+
+At this point, you have successfully created a SaaS application named `LobeChat SSO` in Cloudflare Zero Trust.
+
+Next, we need to enter `https://chat.example.com/api/auth/callback/cloudflare-zero-trust` in the `Redirect URLs` field (note that `chat.example.com` should be replaced with your instance's address).
+
+![image](https://github.com/user-attachments/assets/433fdce4-0af5-417f-b80d-163c2d4f02f6)
+
+Finally, scroll down the page and record the following three values: `Client secret`, `Client ID`, and `Issuer`. You will need these for setting the environment variables when deploying LobeChat.
+
+![image](https://github.com/user-attachments/assets/2dd3cde5-fa0d-4f52-b82b-28d9e89379a0)
+
+### Configure Environment Variables
+
+When deploying LobeChat, you need to configure the following environment variables:
+
+| Environment Variable | Type | Description |
+| --- | --- | --- |
+| `NEXT_AUTH_SECRET` | Required | The secret used to encrypt Auth.js session tokens. You can generate a secret using the following command: `openssl rand -base64 32` |
+| `NEXT_AUTH_SSO_PROVIDERS` | Required | Select the SSO provider for LoboChat. Use `cloudflare-zero-trust` for Cloudflare Zero Trust. |
+| `CLOUDFLARE_ZERO_TRUST_CLIENT_ID` | Required | The Client ID from the Cloudflare Zero Trust application provider details page |
+| `CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET` | Required | The Client Secret from the Cloudflare Zero Trust application provider details page |
+| `CLOUDFLARE_ZERO_TRUST_ISSUER` | Required | The OpenID Configuration Issuer from the Cloudflare Zero Trust application provider details page |
+| `NEXTAUTH_URL` | Optional | This URL is used to specify the callback address for Auth.js when performing OAuth authentication. It only needs to be set when the default generated redirect address is incorrect. `https://example.com/api/auth` |
+
+  <Callout type={'tip'}>
+    Go to  [📘 Environment Variables](/docs/self-hosting/environment-variable#Cloudflare%20Zero%20Trust) for details about the variables.
+
+</Callout>
+</Steps>
+
+<Callout type={'info'}>
+  After a successful deployment, users will be able to use LobeChat by authenticating with the users
+  configured in Cloudflare Zero Trust.
+</Callout>
diff --git a/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.zh-CN.mdx b/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.zh-CN.mdx
new file mode 100644
index 0000000000000..759cc59c1d0d9
--- /dev/null
+++ b/docs/self-hosting/advanced/auth/next-auth/cloudflare-zero-trust.zh-CN.mdx
@@ -0,0 +1,63 @@
+---
+title: 在 LobeChat 中配置 Cloudflare Zero Trust 身份验证服务
+description: 学习如何在 LobeChat 中配置 Cloudflare Zero Trust 身份验证服务,包括创建提供程序、配置环境变量和部署 LobeChat。详细步骤和必要环境变量设置。
+tags:
+  - Cloudflare Zero Trust
+  - 身份验证
+  - 单点登录
+  - 环境变量
+  - LobeChat
+---
+
+# 配置 Cloudflare Zero Trust 身份验证服务
+
+## Cloudflare Zero Trust 配置流程
+
+<Steps>
+### 在 Cloudflare Zero Trust 中创建应用
+
+我们现在默认您已经了解了如何使用 Cloudflare Zero Trust 平台且假设您的 LobeChat 实例部署在 `https://chat.example.com` 中。
+
+首先我们需要访问 `https://one.dash.cloudflare.com/` 并前往 `Access - Applications` 中。
+
+![image](https://github.com/user-attachments/assets/4d671a7c-5d94-4c4b-b4fd-71a5a0e9d227)
+
+现在,在所在页面点击 `Add an application` 并选择 `SaaS`。
+
+![image](https://github.com/user-attachments/assets/3da4c8c4-88c6-40a9-8005-6a0a44aa3b1f)
+
+在 `Application` 文本框内填入应用名称,如:`LobeChat SSO`,然后点击 `Select OIDC` 后点击 `Add applicaiton`
+
+![image](https://github.com/user-attachments/assets/16cd9aef-c87b-48a4-95c0-b666082e7515)
+
+至此您已成功在 Clouflare Zero Trust 中创建了一个名为 `LobeChat SSO` 的 SaaS 应用。
+
+接下来我们需要在 `Redirect URLs` 中填入 `https://chat.example.com/api/auth/callback/cloudflare-zero-trust`(注意此处的 `chat.example.com` 需要替换为您的实例地址)
+![image](https://github.com/user-attachments/assets/433fdce4-0af5-417f-b80d-163c2d4f02f6)
+
+最后我们将页面往下滚动,您将需要记录以下三个值 `Client secret`, `Client ID` 及 `Issuer` 以备后续部署 LobeChat 环境变量使用。
+
+![image](https://github.com/user-attachments/assets/2dd3cde5-fa0d-4f52-b82b-28d9e89379a0)
+
+### 配置环境变量
+
+在部署 LobeChat 时,你需要配置以下环境变量:
+
+| 环境变量 | 类型 | 描述 |
+| --- | --- | --- |
+| `NEXT_AUTH_SECRET` | 必选 | 用于加密 Auth.js 会话令牌的密钥。您可以使用以下命令生成秘钥: `openssl rand -base64 32` |
+| `NEXT_AUTH_SSO_PROVIDERS` | 必选 | 选择 LoboChat 的单点登录提供商。使用 Cloudflare Zero Trust 请填写 `cloudflare-zero-trust`。 |
+| `CLOUDFLARE_ZERO_TRUST_CLIENT_ID` | 必选 | 在 Cloudflare Zero Trust 生成的 `Client ID`,示例值是 `lobe-chat` |
+| `CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET` | 必选 | 在 Cloudflare Zero Trust 生成的 `Client secret`,示例值是 `insecure_secret` |
+| `CLOUDFLARE_ZERO_TRUST_ISSUER` | 必选 | 在 Cloudflare Zero Trust 生成的 `Issuer`,例如 `https://example.cloudflareaccess.com/cdn-cgi/access/sso/oidc/7db0f` |
+| `NEXTAUTH_URL` | 可选 | 该 URL 用于指定 Auth.js 在执行 OAuth 验证时的回调地址,当默认生成的重定向地址发生不正确时才需要设置。`https://chat.example.com/api/auth` |
+
+  <Callout type={'tip'}>
+    前往 [📘 环境变量](/docs/self-hosting/environment-variable#Cloudflare%20Zero%20Trust) 可查阅相关变量详情。
+
+</Callout>
+</Steps>
+
+<Callout type={'info'}>
+  部署成功后,用户将可以使用 Cloudflare Zero Trust 中配置的用户通过身份认证并使用 LobeChat。
+</Callout>
diff --git a/docs/self-hosting/environment-variables/auth.mdx b/docs/self-hosting/environment-variables/auth.mdx
index 5a8b8d1705fbe..974a6a065e860 100644
--- a/docs/self-hosting/environment-variables/auth.mdx
+++ b/docs/self-hosting/environment-variables/auth.mdx
@@ -132,6 +132,29 @@ LobeChat provides a complete authentication service capability when deployed. Th
 - Default: `-`
 - Example: `https://sso.example.com`
 
+### Cloudflare Zero Trust
+
+#### `CLOUDFLARE_ZERO_TRUST_CLIENT_ID`
+
+- Type: Required
+- Description: Client ID of the Cloudflare Zero Trust provider application. You can access it [here][auth0-client-page] and navigate to the application settings to view.
+- Default: `-`
+- Example: `lobe-chat`
+
+#### `CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET`
+
+- Type: Required
+- Description: The plaintext of the Client Secret for the Cloudflare Zero Trust provider
+- Default: `-`
+- Example: `insecure_secret`
+
+#### `CLOUDFLARE_ZERO_TRUST_ISSUER`
+
+- Type: Required
+- Description: Issuer of the Cloudflare Zero Trust provider application.
+- Default: `-`
+- Example: `https://sso.example.com`
+
 ### Github
 
 #### `GITHUB_CLIENT_ID`
diff --git a/docs/self-hosting/environment-variables/auth.zh-CN.mdx b/docs/self-hosting/environment-variables/auth.zh-CN.mdx
index 69fe17ec7146f..96bd8eb64eff6 100644
--- a/docs/self-hosting/environment-variables/auth.zh-CN.mdx
+++ b/docs/self-hosting/environment-variables/auth.zh-CN.mdx
@@ -130,6 +130,29 @@ LobeChat 在部署时提供了完善的身份验证服务能力,以下是相
 - 默认值: `-`
 - 示例: `https://sso.example.com`
 
+### Cloudflare Zero Trust
+
+#### `CLOUDFLARE_ZERO_TRUST_CLIENT_ID`
+
+- 类型:必选
+- 描述: Cloudflare Zero Trust 提供程序的 Client ID
+- 默认值: `-`
+- 示例: `lobe-chat`
+
+#### `CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET`
+
+- 类型:必选
+- 描述: Cloudflare Zero Trust 提供程序的 Client Secret 的明文
+- 默认值: `-`
+- 示例: `insecure_secret`
+
+#### `CLOUDFLARE_ZERO_TRUST_ISSUER`
+
+- 类型:必选
+- 描述: Cloudflare Zero Trust 提供程序的 OpenID Connect 颁发者
+- 默认值: `-`
+- 示例: `https://sso.example.com`
+
 ### Github
 
 #### `GITHUB_CLIENT_ID`
diff --git a/src/config/auth.ts b/src/config/auth.ts
index 0c64df8b7485d..0dbbd06123a7e 100644
--- a/src/config/auth.ts
+++ b/src/config/auth.ts
@@ -86,6 +86,11 @@ export const getAuthConfig = () => {
       AUTHELIA_CLIENT_SECRET: z.string().optional(),
       AUTHELIA_ISSUER: z.string().optional(),
 
+      // Cloudflare Zero Trust
+      CLOUDFLARE_ZERO_TRUST_CLIENT_ID: z.string().optional(),
+      CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET: z.string().optional(),
+      CLOUDFLARE_ZERO_TRUST_ISSUER: z.string().optional(),
+      
       // ZITADEL
       ZITADEL_CLIENT_ID: z.string().optional(),
       ZITADEL_CLIENT_SECRET: z.string().optional(),
@@ -133,6 +138,11 @@ export const getAuthConfig = () => {
       AUTHELIA_CLIENT_SECRET: process.env.AUTHELIA_CLIENT_SECRET,
       AUTHELIA_ISSUER: process.env.AUTHELIA_ISSUER,
 
+      // Cloudflare Zero Trust
+      CLOUDFLARE_ZERO_TRUST_CLIENT_ID: process.env.CLOUDFLARE_ZERO_TRUST_CLIENT_ID,
+      CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET: process.env.CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET,
+      CLOUDFLARE_ZERO_TRUST_ISSUER: process.env.CLOUDFLARE_ZERO_TRUST_ISSUER,
+      
       // ZITADEL
       ZITADEL_CLIENT_ID: process.env.ZITADEL_CLIENT_ID,
       ZITADEL_CLIENT_SECRET: process.env.ZITADEL_CLIENT_SECRET,
diff --git a/src/libs/next-auth/sso-providers/cloudflare-zero-trust.ts b/src/libs/next-auth/sso-providers/cloudflare-zero-trust.ts
new file mode 100644
index 0000000000000..2f0911f65c5a5
--- /dev/null
+++ b/src/libs/next-auth/sso-providers/cloudflare-zero-trust.ts
@@ -0,0 +1,35 @@
+import type { OIDCConfig } from '@auth/core/providers';
+
+import { authEnv } from '@/config/auth';
+
+import { CommonProviderConfig } from './sso.config';
+
+export type CloudflareZeroTrustProfile = {
+  email: string;
+  name: string;
+  sub: string;
+};
+
+const provider = {
+  id: 'cloudflare-zero-trust',
+  provider: {
+    ...CommonProviderConfig,
+    authorization: { params: { scope: 'openid email profile' } },
+    checks: ['state', 'pkce'],
+    clientId: authEnv.CLOUDFLARE_ZERO_TRUST_CLIENT_ID,
+    clientSecret: authEnv.CLOUDFLARE_ZERO_TRUST_CLIENT_SECRET,
+    id: 'cloudflare-zero-trust',
+    issuer: authEnv.CLOUDFLARE_ZERO_TRUST_ISSUER,
+    name: 'Cloudflare Zero Trust',
+    profile(profile) {
+      return {
+        email: profile.email,
+        name: profile.name,
+        providerAccountId: profile.sub,
+      };
+    },
+    type: 'oidc',
+  } satisfies OIDCConfig<CloudflareZeroTrustProfile>,
+};
+
+export default provider;
diff --git a/src/libs/next-auth/sso-providers/index.ts b/src/libs/next-auth/sso-providers/index.ts
index 32ca6dffb4b7c..1b97ec38d6ade 100644
--- a/src/libs/next-auth/sso-providers/index.ts
+++ b/src/libs/next-auth/sso-providers/index.ts
@@ -2,8 +2,9 @@ import Auth0 from './auth0';
 import Authelia from './authelia';
 import Authentik from './authentik';
 import AzureAD from './azure-ad';
+import CloudflareZeroTrust from './cloudflare-zero-trust';
 import Github from './github';
 import Logto from './logto';
 import Zitadel from './zitadel';
 
-export const ssoProviders = [Auth0, Authentik, AzureAD, Github, Zitadel, Authelia, Logto];
+export const ssoProviders = [Auth0, Authentik, AzureAD, Github, Zitadel, Authelia, Logto, CloudflareZeroTrust];
\ No newline at end of file