# Ключи OpenIddict (подпись и шифрование токенов)

Токены доступа/обновления подписываются (и в проде шифруются) ключами OpenIddict.
Конфигурация ключей — в `OpenIddictKeyConfigurator` (`src/food-market.api/Infrastructure/Security/`),
вызывается из `Program.cs` внутри `AddServer(...)`.

## Development

- Persistent RSA-ключ в `src/food-market.api/App_Data/openiddict-dev-key.xml`
  (один и тот же для подписи и шифрования).
- Переживает рестарты — выданные токены остаются валидными между перезапусками.
- **Шифрование access-token выключено** (`DisableAccessTokenEncryption`) — токен это
  обычный 3-сегментный JWT, удобно дебажить (можно прочитать на jwt.io).
- Файл `App_Data/` в `.gitignore` — ключ не коммитится.

## Production / Stage

- Отдельные **X509-сертификаты** для подписи и шифрования. Access-token шифруется
  (5-сегментный JWE).
- Путь к сертификатам — из конфигурации:

  | Ключ конфига | Env-переменная | Назначение | Дефолт |
  |---|---|---|---|
  | `OpenIddict:SigningCertPath` | `OpenIddict__SigningCertPath` | сертификат подписи | `App_Data/openiddict-signing.pfx` |
  | `OpenIddict:EncryptionCertPath` | `OpenIddict__EncryptionCertPath` | сертификат шифрования | `App_Data/openiddict-encryption.pfx` |
  | `OpenIddict:CertPassword` | `OpenIddict__CertPassword` | пароль PFX (опц.) | — |

- **Если файла нет** — генерируется persistent self-signed сертификат (RSA 2048, срок 5 лет)
  и сохраняется по пути. При следующем старте берётся тот же файл, поэтому ранее
  выданные токены остаются валидными (нет dev-ephemeral поведения, при котором каждый
  рестарт инвалидировал бы все токены).
- `App_Data` смонтирован как volume (`api-data:/app/App_Data` в `docker-compose.yml`),
  поэтому сертификаты переживают пересоздание контейнера.

### Принести собственные сертификаты

Положить готовые `.pfx` (с приватным ключом) по путям из конфига и, при наличии пароля,
задать `OpenIddict__CertPassword`. Приложение их подхватит вместо генерации self-signed.

```bash
# пример: смонтировать каталог с сертификатами и указать пути
OpenIddict__SigningCertPath=/run/secrets/oidc-signing.pfx
OpenIddict__EncryptionCertPath=/run/secrets/oidc-encryption.pfx
OpenIddict__CertPassword=<пароль или пусто>
```

### Ротация

1. Заменить/удалить `.pfx` файлы (или указать новые пути).
2. Рестарт API: при отсутствии файла сгенерируется новый сертификат.
3. **Важно:** ротация ключа подписи/шифрования инвалидирует все ранее выданные
   токены — пользователям потребуется перелогиниться. Планировать на окно обслуживания.

### Проверка (smoke)

```bash
# 5 сегментов = JWE (шифрование включено) — норма для прода
curl -s -X POST $API/connect/token -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=password&username=...&password=...&client_id=food-market-web&scope=api" \
  | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'].count('.')+1,'сегментов')"
```

Проверено локально (2026-05-27): prod-режим генерирует оба сертификата в `App_Data`,
выдаёт 5-сегментный JWE, `/api/me` → 200; после рестарта сертификаты те же
(fingerprint совпадает), токен, выданный до рестарта, остаётся валиден.
