> ## 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，以了解它所需的設定方式。

必須設定環境變數 `EXTERNAL_AUTH` 才能啟用 OIDC 驗證模組。此環境變數用於指定要啟用哪些外部驗證方式，其值為一個清單。如果清單中包含 `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 建立的用戶端（提供者）頁面上顯示此 URL。在 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 token 中的 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`（對應 `preferred_username` OIDC claim）。
* `OVERLEAF_OIDC_ALLOWED_EMAIL_DOMAINS`
  * 限制透過 OIDC 驗證之使用者的即時（Just-in-Time，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` claim），登入流程便會將 `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` claim（一個陣列）傳送使用者所屬的群組。若要讓 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.