> ## Documentation Index
> Fetch the complete documentation index at: https://veriqa.app/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Drupal

> Вход в Drupal 10 через Veriqa: модули, три переключателя проверки, обязательный email и что с ним делать, когда канал его не отдаёт.

Drupal подключается к Veriqa штатными contrib-модулями. Правится только сторона сайта: сервер
Veriqa и его поставка не трогаются.

<Note>
  Проверено: Drupal 10 + `openid_connect` 3.0.0-alpha8 + `openid_client_advanced` 1.0.0-rc8;
  канал Telegram. Работают вход, создание пользователя, **проверка подписи `id_token` по JWKS,
  nonce и PKCE S256**.
</Note>

## 1. Модули

```bash theme={null}
composer require drush/drush "drupal/openid_connect:^3.0@alpha" "drupal/openid_client_advanced:^1.0@rc"
drush en openid_connect openid_client_advanced
```

`openid_connect` 3.0.0 — **alpha**, и это стоит учитывать при планировании. `openid_client_advanced`
тянет `firebase/php-jwt`.

## 2. Клиент и три переключателя

Configuration → People → OpenID Connect, плагин **advanced**. Заполняются `issuer_url`, три
эндпоинта (`/connect/authorize`, `/connect/token`, `/connect/userinfo`) и `scopes`.

<Warning>
  PKCE в самом `openid_connect` выключен на уровне кода (`usesPkce()` возвращает FALSE). PKCE
  S256, проверка подписи и nonce живут в `openid_client_advanced`, и **все три по умолчанию
  выключены**. «Drupal умеет PKCE» — верно только после того, как вы их включили.
</Warning>

Включите все три: `use_pkce`, `use_nonce`, `validate_signature` с
`allowed_algorithms: [RS256]`. Ключи вставляются **JSON-ом JWKS** — поле ждёт содержимое
документа `/.well-known/jwks`, а не ссылку на него.

Ещё три настройки, без которых поведение будет неожиданным:

* `openid_connect.settings.user_login_display = above` — иначе кнопки входа на форме просто не
  видно;
* `override_registration_settings` и `user.settings.register` — определяют, разрешено ли
  создавать учётные записи через провайдера.

`redirect_uri` = `{адрес сайта}/openid-connect/{id сущности клиента}`.

## 3. Drupal требует email — на каждом входе

Самое важное место рецепта. `openid_connect` отклоняет вход, если провайдер не вернул адрес:
в логе появляется `No email address provided by <provider>`, настройки обхода нет.

<Warning>
  Проверка стоит не в момент регистрации, а в построении контекста, до того как ищется учётная
  запись. Поэтому **уже зарегистрированный** пользователь без email тоже не войдёт: email нужен
  на каждом входе, а не только на первом.
</Warning>

Telegram адреса не отдаёт и не отдаст. Выход — хук, который модуль документирует сам
(`openid_connect.api.php`) и вызывает **до** проверки; правка живёт в вашем модуле, contrib и
Veriqa остаются нетронутыми:

```php mymodule.module theme={null}
/**
 * Implements hook_openid_connect_userinfo_alter().
 */
function mymodule_openid_connect_userinfo_alter(array &$userinfo, array $context): void {
  if (!empty($userinfo['email'])) {
    return;
  }

  // При дефолтном резолвере `sub` уже несёт обе части как "{channel_type}:{channel_user_id}".
  $parts = explode(':', (string) ($userinfo['sub'] ?? ''), 2);
  if (count($parts) !== 2) {
    return;
  }

  [$channelType, $channelUserId] = $parts;
  $local = preg_replace('/[^a-z0-9]+/i', '-', $channelType . '-' . $channelUserId);
  $userinfo['email'] = strtolower($local) . '@' . strtolower($channelType) . '.veriqa.invalid';
}
```

Адрес получается вида `telegram-123456789@telegram.veriqa.invalid`. Домен `.invalid`
зарезервирован [RFC 2606](https://www.rfc-editor.org/rfc/rfc2606) и гарантированно никуда не
доставляется — это осознанная цена, а не бесплатный обход:

**учётная запись с таким адресом не получит ни сброса пароля, ни уведомлений.** Для боевого
сайта это развилка, а не готовое решение: спросить email вторым шагом, включить progressive
enrichment или использовать канал Email, где адрес приезжает в claims.

### `connect_existing_users` — настройка, которую нельзя оставлять без внимания

Для нового пользователя Drupal сверяет адрес с существующими учётными записями. При включённом
`connect_existing_users` он **привяжет найденную локальную учётку** к идентичности из Veriqa.

С синтетическими адресами это безопасно: они детерминированы и уникальны на пару «канал + id».
Но как только Veriqa начнёт отдавать **настоящий** адрес (канал Email или собственный резолвер),
вход через Veriqa захватит локальный аккаунт с тем же адресом — классический захват учётной записи
через непроверенный email. Включать эту настройку осмысленно только тогда, когда вы уверены в
верифицированности адреса на стороне IdP.

## Что получится

Учётная запись создаётся с именем из `preferred_username` (`alice`), а в `authmap` появляется
запись `provider=openid_connect.veriqa, authname=telegram:123456789` — **Drupal связывает
идентичность по `sub` Veriqa**.

Отсюда следует практическое: `sub` для Drupal — ключ учётной записи. Если способ его
формирования на стороне Veriqa изменится, ранее заведённые пользователи перестанут узнаваться.

## Границы

* Проверено с каналом **Telegram**; связка Drupal с Email, WhatsApp и MAX не проверялась.
* Хук выше — пример, а не готовый модуль для продакшена: решение про адреса принимает сам сайт.


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