> ## 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>

### Настройка

Внутри модуль OIDC в Overleaf использует библиотеку [passport-openidconnect](https://github.com/jaredhanson/passport-openidconnect). Если у вас возникают проблемы с настройкой OpenID Connect, стоит прочитать README для `passport-openidconnect`, чтобы понять, какую конфигурацию она ожидает.

Для включения модуля аутентификации OIDC необходима переменная окружения `EXTERNAL_AUTH`. Она определяет, какие внешние методы аутентификации активированы. Значением этой переменной является список. Если список содержит `oidc`, будет активирована аутентификация OIDC.

Например: `EXTERNAL_AUTH=ldap oidc`

При использовании метода аутентификации OIDC пользователь перенаправляется на сайт аутентификации поставщика удостоверений (IdP). Если IdP успешно аутентифицирует пользователя, в базе данных пользователей Overleaf выполняется поиск записи, содержащей поле `thirdPartyIdentifiers` следующей структуры:

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

Значение `externalUserId` должно совпадать с идентификатором пользователя в профиле, возвращаемом сервером IdP (см. переменную окружения `OVERLEAF_OIDC_USER_ID_FIELD`), а `providerId` должно совпадать с идентификатором провайдера OIDC (см. `OVERLEAF_OIDC_PROVIDER_ID`).

Если подходящая запись не найдена, в базе данных выполняется поиск пользователя, основной адрес электронной почты которого совпадает с адресом в профиле пользователя IdP:

* Если такой пользователь найден, поле `thirdPartyIdentifiers` обновляется.
* Если подходящий пользователь не найден и создание учётных записей JIT не отключено, создаётся новый пользователь с адресом электронной почты и `thirdPartyIdentifiers` из профиля IdP.

В обоих случаях говорят, что пользователь «связан» с внешним пользователем OIDC. Пользователь может отвязаться от провайдера OIDC на странице `/user/settings`.

#### Поиск значений с помощью документа обнаружения

Каждый провайдер OpenID (OP) публикует документ обнаружения (discovery document) по адресу `<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 посимвольно сравнивает его с issuer в ID-токене; любое расхождение приводит к тому, что каждый вход через OIDC завершается ошибкой:

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

  В Authentik issuer принадлежит приложению (`.../application/o/<application-slug>/`). Это не адрес сервера Authentik, хотя URL authorize, token и userinfo общие для всех приложений.
</Warning>

#### Переменные окружения

Значения следующих пяти обязательных переменных можно узнать через эндпоинт `.well-known/openid-configuration` вашего провайдера OpenID (OP), см. выше.

* `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, по умолчанию `oidc`.
* `OVERLEAF_OIDC_PROVIDER_NAME`
  * Название OP, используемое в разделе `Linked Accounts` страницы `/user/settings`, по умолчанию `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`
  * URL ссылки `Learn more` в описании OP; по умолчанию ссылки `Learn more` в описании нет.
* `OVERLEAF_OIDC_PROVIDER_HIDE_NOT_LINKED`
  * Не показывать OP на странице `/user/settings`, если учётная запись пользователя не связана с OP; по умолчанию `false`.
* `OVERLEAF_OIDC_USER_ID_FIELD`
  * Значение этого атрибута будет использоваться Overleaf как внешний идентификатор пользователя; по умолчанию `id`. Другие разумные возможные значения — `email` и `username` (соответствует claim OIDC `preferred_username`).
* `OVERLEAF_OIDC_ALLOWED_EMAIL_DOMAINS`
  * Ограничивает создание учётных записей Just-in-Time (JIT) для пользователей, аутентифицирующихся через OIDC. Если задан список доменных имён через запятую, новая учётная запись будет создана, только если домен адреса электронной почты пользователя совпадает с одним из перечисленных доменов. Если домен не совпадает, администратор должен вручную создать учётную запись пользователя с адресом электронной почты пользователя OIDC, задав либо надёжный случайный пароль, либо, что предпочтительнее, вообще без поля `hashedPassword`. Доменные имена могут начинаться с подстановочного знака `*.` для соответствия поддоменам.
    * Пример: чтобы разрешить создание учётных записей JIT для пользователей с адресами вида `name@example.com` и `name@math.example.com`:\
      `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`
  * Если заданы обе переменные окружения, в процессе входа устанавливается `user.isAdmin = true`, если профиль, возвращённый OP, содержит атрибут, указанный в `OVERLEAF_OIDC_IS_ADMIN_FIELD`, и его значение либо совпадает с `OVERLEAF_OIDC_IS_ADMIN_FIELD_VALUE`, либо является массивом, содержащим `OVERLEAF_OIDC_IS_ADMIN_FIELD_VALUE` (например, claim `groups`); в противном случае `user.isAdmin` устанавливается в `false`. Если `OVERLEAF_OIDC_IS_ADMIN_FIELD` равно `email`, для проверки совпадения используется значение атрибута `emails[0].value`.

URL перенаправления для вашего провайдера OpenID: `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 показывает client secret только при создании провайдера. Позже форма редактирования предлагает лишь **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 передаёт группы пользователя в claim `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="Проверенный variables.env для goauthentik">
  ```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.