> ## Documentation Index
> Fetch the complete documentation index at: https://ayakaleaf-pro.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# OIDC 认证

<Info>
  此功能由 [yu-i-i/overleaf-cep](https://github.com/yu-i-i/overleaf-cep) 开发。这里我们提供一些文档，供你进行配置时参考。
</Info>

### 配置

Overleaf OIDC 模块在内部使用 [passport-openidconnect](https://github.com/jaredhanson/passport-openidconnect) 库。如果你在配置 OpenID Connect 时遇到问题，建议阅读 `passport-openidconnect` 的 README，以了解它所需的配置。

启用 OIDC 认证模块需要设置环境变量 `EXTERNAL_AUTH`。该环境变量指定启用哪些外部认证方式，其值是一个列表。如果列表中包含 `oidc`，则会启用 OIDC 认证。

例如：`EXTERNAL_AUTH=ldap oidc`

使用 OIDC 认证方式时，用户会被重定向到身份提供商（IdP）的认证站点。如果 IdP 成功认证了该用户，系统会在 Overleaf 用户数据库中查找包含如下结构的 `thirdPartyIdentifiers` 字段的记录：

```text theme={null}
thirdPartyIdentifiers: [
  {
    externalUserId: "...",
    externalData: null,
    providerId: "..."
  }
]
```

`externalUserId` 必须与 IdP 服务器返回的用户资料中的用户 ID 相匹配（参见 `OVERLEAF_OIDC_USER_ID_FIELD` 环境变量），并且 `providerId` 必须与 OIDC 提供商的 ID 相匹配（参见 `OVERLEAF_OIDC_PROVIDER_ID`）。

如果未找到匹配的记录，系统会在数据库中查找主邮箱地址与 IdP 用户资料中的邮箱相匹配的用户：

* 如果找到了这样的用户，则更新其 `thirdPartyIdentifiers` 字段。
* 如果没有找到匹配的用户，且未禁用 JIT 账户创建，则会使用 IdP 资料中的邮箱地址和 `thirdPartyIdentifiers` 创建一个新用户。

在这两种情况下，该用户都被称为已与外部 OIDC 用户"关联"。用户可以在 `/user/settings` 页面上取消与 OIDC 提供商的关联。

#### 使用发现文档查找这些值

每个 OpenID 提供商（OP）都会在 `<issuer>/.well-known/openid-configuration` 发布一个发现文档。请从中复制这些值，而不要手动输入；只要有一个字符错误，就足以导致登录失败。

<Steps>
  <Step title="找到发现 URL">
    你的 OP 会在你为 Overleaf 创建的客户端（提供商）页面上显示它。在 Authentik 中，打开 **Applications > Providers**，选择该提供商，然后查找 **OpenID Configuration URL** 和 **OpenID Configuration Issuer**：

    <Frame caption="Authentik：提供商的发现 URL 和 issuer（测试实例）">
      <img src="https://mintcdn.com/ayakaleaf-pro/TjqwH4XzxYAkHStq/images/on-premises/oidc-authentik-provider.png?fit=max&auto=format&n=TjqwH4XzxYAkHStq&q=85&s=e3cb5603d959665472b53e39b58b2775" alt="" width="1280" height="633" data-path="images/on-premises/oidc-authentik-provider.png" />
    </Frame>

    该 URL 通常如下所示：

    * Keycloak：`https://keycloak.example.com/realms/<realm>/.well-known/openid-configuration`
    * Authentik：`https://authentik.example.com/application/o/<application-slug>/.well-known/openid-configuration`
  </Step>

  <Step title="读取这些值">
    在浏览器中打开该 URL，或者在 Overleaf 服务器上运行：

    ```shell theme={null}
    curl -s https://authentik.example.com/application/o/overleaf/.well-known/openid-configuration \
      | jq '{issuer, authorization_endpoint, token_endpoint, userinfo_endpoint, end_session_endpoint}'
    ```

    Authentik 的响应如下所示：

    ```json theme={null}
    {
      "issuer": "https://authentik.example.com/application/o/overleaf/",
      "authorization_endpoint": "https://authentik.example.com/application/o/authorize/",
      "token_endpoint": "https://authentik.example.com/application/o/token/",
      "userinfo_endpoint": "https://authentik.example.com/application/o/userinfo/",
      "end_session_endpoint": "https://authentik.example.com/application/o/overleaf/end-session/"
    }
    ```

    Authentik 也会在提供商页面的下方列出这些 URL：

    <Frame caption="Authentik：提供商的端点（测试实例）">
      <img src="https://mintcdn.com/ayakaleaf-pro/TjqwH4XzxYAkHStq/images/on-premises/oidc-authentik-endpoints.png?fit=max&auto=format&n=TjqwH4XzxYAkHStq&q=85&s=55d130cbbbf27fd11aebafa1ab3f090c" alt="" width="1280" height="633" data-path="images/on-premises/oidc-authentik-endpoints.png" />
    </Frame>
  </Step>

  <Step title="将它们复制到 `variables.env`">
    | 发现文档中的字段 | 环境变量 |
    | - | - |
    | `issuer` | `OVERLEAF_OIDC_ISSUER` |
    | `authorization_endpoint` | `OVERLEAF_OIDC_AUTHORIZATION_URL` |
    | `token_endpoint` | `OVERLEAF_OIDC_TOKEN_URL` |
    | `userinfo_endpoint` | `OVERLEAF_OIDC_USER_INFO_URL` |
    | `end_session_endpoint` | `OVERLEAF_OIDC_LOGOUT_URL` |

    ```dotenv theme={null}
    OVERLEAF_OIDC_ISSUER=https://authentik.example.com/application/o/overleaf/
    OVERLEAF_OIDC_AUTHORIZATION_URL=https://authentik.example.com/application/o/authorize/
    OVERLEAF_OIDC_TOKEN_URL=https://authentik.example.com/application/o/token/
    OVERLEAF_OIDC_USER_INFO_URL=https://authentik.example.com/application/o/userinfo/
    OVERLEAF_OIDC_LOGOUT_URL=https://authentik.example.com/application/o/overleaf/end-session/
    ```
  </Step>

  <Step title="检查 Overleaf 能否访问 OP">
    Overleaf 会从其容器内部调用 token 和 userinfo 端点，因此 OP 必须能从容器内访问，而不仅仅是从你的浏览器访问：

    ```shell theme={null}
    docker exec sharelatex curl -sS -o /dev/null -w "%{http_code}\n" \
      https://authentik.example.com/application/o/overleaf/.well-known/openid-configuration
    ```

    它应当输出 `200`。
  </Step>
</Steps>

<Warning>
  请精确复制 `issuer`，包括末尾的斜杠。Overleaf 会将它与 ID 令牌中的 issuer 逐字符进行比较；任何差异都会导致所有 OIDC 登录失败，并出现以下错误：

  `{"message":{"message":"ID token not issued by expected OpenID provider."}}`

  在 Authentik 中，issuer 属于应用（`.../application/o/<application-slug>/`）。它不是 Authentik 服务器的地址，尽管 authorize、token 和 userinfo URL 由所有应用共享。
</Warning>

#### 环境变量

以下五个必需变量的值可以通过你的 OpenID 提供商（OP）的 `.well-known/openid-configuration` 端点获取，参见上文。

* `OVERLEAF_OIDC_ISSUER` <strong>（必需）</strong>
* `OVERLEAF_OIDC_AUTHORIZATION_URL` <strong>（必需）</strong>
* `OVERLEAF_OIDC_TOKEN_URL` <strong>（必需）</strong>
* `OVERLEAF_OIDC_USER_INFO_URL` <strong>（必需）</strong>
* `OVERLEAF_OIDC_LOGOUT_URL` <strong>（必需）</strong>

以下两个必需变量的值将由你的 OP 管理员提供

* `OVERLEAF_OIDC_CLIENT_ID` <strong>（必需）</strong>
* `OVERLEAF_OIDC_CLIENT_SECRET` <strong>（必需）</strong>
* `OVERLEAF_OIDC_SCOPE`
  * 默认值：`openid profile email`
* `OVERLEAF_OIDC_PROVIDER_ID`
  * OP 的任意 ID，默认为 `oidc`。
* `OVERLEAF_OIDC_PROVIDER_NAME`
  * OP 的名称，用于 `/user/settings` 页面的 `Linked Accounts` 部分，默认为 `OIDC Provider`。
* `OVERLEAF_OIDC_IDENTITY_SERVICE_NAME`
  * 身份服务的显示名称，用于登录页面（默认值：`Log in with $OVERLEAF_OIDC_PROVIDER_NAME`）。
* `OVERLEAF_OIDC_PROVIDER_DESCRIPTION`
  * OP 的描述，用于 `Linked Accounts` 部分（默认值：`Log in with $OVERLEAF_OIDC_PROVIDER_NAME`）。
* `OVERLEAF_OIDC_PROVIDER_INFO_LINK`
  * OP 描述中的 `Learn more` URL，默认：描述中不显示 `Learn more` 链接。
* `OVERLEAF_OIDC_PROVIDER_HIDE_NOT_LINKED`
  * 如果用户账户未与 OP 关联，则不在 `/user/settings` 页面上显示该 OP，默认为 `false`。
* `OVERLEAF_OIDC_USER_ID_FIELD`
  * Overleaf 会将该属性的值用作外部用户 ID，默认为 `id`。其他合理的取值还有 `email` 和 `username`（对应 OIDC 的 `preferred_username` 声明）。
* `OVERLEAF_OIDC_ALLOWED_EMAIL_DOMAINS`
  * 限制通过 OIDC 认证的用户的即时（JIT）账户创建。如果设置为以逗号分隔的域名列表，则只有当用户邮箱地址的域名与列表中的某个域名匹配时，才会创建新账户。如果域名不匹配，管理员必须使用该 OIDC 用户的邮箱地址手动创建用户账户，并设置一个强随机密码，或者最好完全不设置 `hashedPassword` 字段。域名可以以 `*.` 通配符开头，以匹配子域名。
    * 示例：允许邮箱地址形如 `name@example.com` 和 `name@math.example.com` 的用户进行 JIT 账户创建：\
      `OVERLEAF_OIDC_ALLOWED_EMAIL_DOMAINS=example.com, *.example.com`
    * 示例：完全禁用 JIT 账户创建：\
      `OVERLEAF_OIDC_ALLOWED_EMAIL_DOMAINS=`
* `OVERLEAF_OIDC_UPDATE_USER_DETAILS_ON_LOGIN`
  * 如果设置为 `true`，则在登录时更新用户的 `first_name` 和 `last_name` 字段，并禁用 `/user/settings` 页面上的用户详细信息表单。
* `OVERLEAF_OIDC_IS_ADMIN_FIELD` 和 `OVERLEAF_OIDC_IS_ADMIN_FIELD_VALUE`
  * 当这两个环境变量都已设置时，如果 OP 返回的用户资料包含 `OVERLEAF_OIDC_IS_ADMIN_FIELD` 指定的属性，且其值与 `OVERLEAF_OIDC_IS_ADMIN_FIELD_VALUE` 匹配，或者是包含 `OVERLEAF_OIDC_IS_ADMIN_FIELD_VALUE` 的数组（例如 `groups` 声明），登录过程会将 `user.isAdmin` 更新为 `true`，否则将 `user.isAdmin` 设置为 `false`。如果 `OVERLEAF_OIDC_IS_ADMIN_FIELD` 为 `email`，则使用属性 `emails[0].value` 的值进行匹配检查。

你的 OpenID 提供商的重定向 URL 为 `https://my-overleaf-instance.com/oidc/login/callback`。

<Accordion title="variables.env 示例文件">
  ```dotenv title="variables.env" wrap theme={null}
  OVERLEAF_APP_NAME="Our Overleaf Instance"

  ENABLED_LINKED_FILE_TYPES=project_file,project_output_file,url

  # Enables Thumbnail generation using ImageMagick
  ENABLE_CONVERSIONS=true

  # Disables email confirmation requirement
  EMAIL_CONFIRMATION_DISABLED=true

  ## Nginx
  # NGINX_WORKER_PROCESSES=4
  # NGINX_WORKER_CONNECTIONS=768

  ## Set for TLS via nginx-proxy
  # OVERLEAF_BEHIND_PROXY=true
  # OVERLEAF_SECURE_COOKIE=true

  OVERLEAF_SITE_URL=http://my-overleaf-instance.com
  OVERLEAF_NAV_TITLE=Our Overleaf Instance
  # OVERLEAF_HEADER_IMAGE_URL=http://somewhere.com/mylogo.png
  OVERLEAF_ADMIN_EMAIL=support@example.com

  OVERLEAF_LEFT_FOOTER=[{"text": "Contact your support team", "url": "mailto:support@example.com"}]
  OVERLEAF_RIGHT_FOOTER=[{"text":"Hello, I am on the Right", "url":"https://github.com/yu-i-i/overleaf-cep"}]

  OVERLEAF_EMAIL_FROM_ADDRESS=team@example.com
  OVERLEAF_EMAIL_SMTP_HOST=smtp.example.com
  OVERLEAF_EMAIL_SMTP_PORT=587
  OVERLEAF_EMAIL_SMTP_SECURE=false
  # OVERLEAF_EMAIL_SMTP_USER=
  # OVERLEAF_EMAIL_SMTP_PASS=
  # OVERLEAF_EMAIL_SMTP_NAME=
  OVERLEAF_EMAIL_SMTP_LOGGER=false
  OVERLEAF_EMAIL_SMTP_TLS_REJECT_UNAUTH=true
  OVERLEAF_EMAIL_SMTP_IGNORE_TLS=false
  OVERLEAF_CUSTOM_EMAIL_FOOTER=This system is run by department x

  OVERLEAF_PROXY_LEARN=true
  NAV_HIDE_POWERED_BY=true

  #################
  ## OIDC for CE ##
  #################

  EXTERNAL_AUTH=oidc

  OVERLEAF_OIDC_PROVIDER_ID=oidc
  OVERLEAF_OIDC_ISSUER=https://keycloak.provider.com/realms/example
  OVERLEAF_OIDC_AUTHORIZATION_URL=https://keycloak.provider.com/realms/example/protocol/openid-connect/auth
  OVERLEAF_OIDC_TOKEN_URL=https://keycloak.provider.com/realms/example/protocol/openid-connect/token
  OVERLEAF_OIDC_USER_INFO_URL=https://keycloak.provider.com/realms/example/protocol/openid-connect/userinfo
  OVERLEAF_OIDC_LOGOUT_URL=https://keycloak.provider.com/realms/example/protocol/openid-connect/logout
  OVERLEAF_OIDC_CLIENT_ID=Overleaf-OIDC
  OVERLEAF_OIDC_CLIENT_SECRET=DoNotUseThisATGgaAcTgCcATgGATTACAagGtTCaGcGTAG
  OVERLEAF_OIDC_IDENTITY_SERVICE_NAME='Log in with Keycloak OIDC Provider'
  OVERLEAF_OIDC_PROVIDER_NAME=OIDC Keycloak Provider
  OVERLEAF_OIDC_PROVIDER_INFO_LINK=https://openid.net
  OVERLEAF_OIDC_IS_ADMIN_FIELD=email
  OVERLEAF_OIDC_IS_ADMIN_FIELD_VALUE=overleaf.admin@example.com
  OVERLEAF_OIDC_UPDATE_USER_DETAILS_ON_LOGIN=false
  ```
</Accordion>

## 分步指南：goauthentik

本节介绍一套已在 [goauthentik](https://goauthentik.io/) 上测试通过的配置。请将 `https://overleaf.example.com` 替换为你的 `OVERLEAF_SITE_URL`，并将 `https://authentik.example.com` 替换为你的 Authentik 地址。

<Steps>
  <Step title="创建提供商">
    在 Authentik 中，打开 **Applications > Providers**，点击 **New Provider**，选择 **OAuth2/OpenID Provider** 并点击 **Next**。

    * **Client Type**：`Confidential`。
    * **Redirect URIs**（位于 **Protocol settings** 下）：添加 `https://overleaf.example.com/oidc/login/callback`，匹配模式为 `Strict`。
    * 现在就复制 **Client ID** 和 **Client Secret**，分别填入 `OVERLEAF_OIDC_CLIENT_ID` 和 `OVERLEAF_OIDC_CLIENT_SECRET`。

    <Frame caption="Authentik：新提供商的 Client ID 和 Client Secret">
      <img src="https://mintcdn.com/ayakaleaf-pro/TjqwH4XzxYAkHStq/images/on-premises/oidc-authentik-create.png?fit=max&auto=format&n=TjqwH4XzxYAkHStq&q=85&s=f127a92eaf3063714e9af515fe97c263" alt="" width="1120" height="808" data-path="images/on-premises/oidc-authentik-create.png" />
    </Frame>

    <Warning>
      Authentik 仅在你创建提供商时显示客户端密钥。之后编辑表单中只提供 **Modify**，它会用一个新密钥替换原有密钥。
    </Warning>
  </Step>

  <Step title="创建应用">
    打开 **Applications > Applications**，创建一个新应用，为其设置名称和 slug（例如 `overleaf`），并选择该提供商。slug 会成为 issuer 的一部分：`https://authentik.example.com/application/o/overleaf/`。
  </Step>

  <Step title="复制 URL">
    按照上文[使用发现文档查找这些值](#使用发现文档查找这些值)填写这五个 URL。
  </Step>

  <Step title="映射管理员（可选）">
    Authentik 会以 `groups` 声明（一个数组）发送用户所属的组。要让 Authentik 组 `Admins` 的成员成为 Overleaf 的管理员：

    ```dotenv theme={null}
    OVERLEAF_OIDC_IS_ADMIN_FIELD=groups
    OVERLEAF_OIDC_IS_ADMIN_FIELD_VALUE=Admins
    ```

    <Warning>
      管理员标志会在每次 OIDC 登录时更新。如果字段或值有误，所有通过 OIDC 登录的管理员都会失去管理员权限，包括在 launchpad 中创建的管理员。请先使用另一个管理员账户测试该映射。
    </Warning>
  </Step>
</Steps>

<Accordion title="经过测试的 goauthentik variables.env">
  ```dotenv title="variables.env" wrap theme={null}
  EXTERNAL_AUTH=oidc
  OVERLEAF_OIDC_PROVIDER_ID=authentik
  OVERLEAF_OIDC_IDENTITY_SERVICE_NAME=Log in with Authentik
  OVERLEAF_OIDC_ISSUER=https://authentik.example.com/application/o/overleaf/
  OVERLEAF_OIDC_AUTHORIZATION_URL=https://authentik.example.com/application/o/authorize/
  OVERLEAF_OIDC_TOKEN_URL=https://authentik.example.com/application/o/token/
  OVERLEAF_OIDC_USER_INFO_URL=https://authentik.example.com/application/o/userinfo/
  OVERLEAF_OIDC_LOGOUT_URL=https://authentik.example.com/application/o/overleaf/end-session/
  OVERLEAF_OIDC_CLIENT_ID=<Client ID>
  OVERLEAF_OIDC_CLIENT_SECRET=<Client Secret>
  OVERLEAF_OIDC_USER_ID_FIELD=username
  OVERLEAF_OIDC_IS_ADMIN_FIELD=groups
  OVERLEAF_OIDC_IS_ADMIN_FIELD_VALUE=Admins
  OVERLEAF_OIDC_UPDATE_USER_DETAILS_ON_LOGIN=true
  ```
</Accordion>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.