Files
hr-appeals/server/README.md
T
gorbenko.pavel f1caa62f28
Tests / frontend-test (pull_request) Successful in 3m14s
refactor: сертификат и ключ в каталоге secrets/, один параметр на каталог
Локально путь к сертификату вёл в ~/Downloads у каждого свой, а в контейнере
задавался двумя отдельными переменными. Теперь каталог один и подменяется
целиком через SECRETS_DIR: по умолчанию secrets/ в корне репозитория, в
контейнере /certs (смонтированный каталог с хоста, GRAPH_CERT_DIR не меняется).

Имена файлов внутри фиксированы, поэтому GRAPH_CERT_PATH и GRAPH_KEY_PATH
больше не нужны. Содержимое secrets/ в .gitignore, кроме README.

Отсутствие файлов теперь даёт понятную ошибку вместо ENOENT — на свежем
клоне это основной сценарий отказа.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 13:34:37 +05:00

78 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# hr-appeals-auth
Сервис получает app-only токен Azure AD (JWT client
assertion) и используется для авторизованных запросов к внутреннему API
`api.tnsu.kz`. Сам токен наружу не отдаётся — из HTTP-эндпоинтов сервиса
доступны только `/healthz` и `/diag/token` (последний подтверждает, что
токен получен, но не возвращает его значение). Детали получения токена — в
[graphAuth.ts](src/graphAuth.ts).
## Переменные окружения
| Переменная | Назначение |
|---|---|
| `GRAPH_TENANT_ID` | Tenant ID Azure AD |
| `GRAPH_CLIENT_ID` | Client ID App Registration, к которому привязан сертификат `SPFxDeploy` |
| `SECRETS_DIR` | Каталог с `SPFxDeploy_cert.pem` и `SPFxDeploy_key.pem` (имена файлов фиксированы). По умолчанию — [`secrets/`](../secrets/README.md) в корне репозитория; в контейнере `/certs`, куда смонтирован каталог с хоста. Задавать нужно только чтобы подменить каталог целиком |
| `GRAPH_SCOPE` | OAuth-scope запрашиваемого токена. По умолчанию — App ID URI самого `api.tnsu.kz` (`api://9232d9e2-.../.default`), задавать не нужно. Токен для `https://graph.microsoft.com/.default` тут не подойдёт: `api.tnsu.kz` проверяет `aud` входящего JWT и отвечает 401 |
| `PORT` | Порт HTTP-сервера сервиса, по умолчанию `3000` (локально — `3100`, см. `.env.example`) |
## Локальный запуск
Из корня репозитория `npm run dev` поднимает сервис вместе с фронтендом. Отдельно:
```bash
cp .env.example .env # tenant/client id и порт
npm run dev # tsc + запуск с чтением .env (--env-file, Node 20+)
```
Сертификат и ключ при этом должны лежать в [`secrets/`](../secrets/README.md) —
в git они не хранятся.
Проверить, что авторизация работает: `curl http://localhost:3100/diag/token` →
`{"ok":true}`. Если вернулась ошибка — в ней будет ответ Azure AD целиком.
## Как обратиться к api.tnsu.kz с авторизацией
Токен запрашивается через `getAppOnlyToken()` и передаётся в заголовке
`Authorization: Bearer <token>`. Функция сама кэширует токен до истечения,
повторно вызывать её на каждый запрос не накладно — за сеть она сходит
только когда кэш устарел.
```ts
import { getAppOnlyToken } from './graphAuth';
async function callApiTnsu(path: string, init: RequestInit = {}) {
const token = await getAppOnlyToken();
const response = await fetch(`https://api.tnsu.kz${path}`, {
...init,
headers: {
...init.headers,
Authorization: `Bearer ${token}`
}
});
if (!response.ok) {
throw new Error(`api.tnsu.kz ответил ${response.status}: ${await response.text()}`);
}
return response.json();
}
```
Перед тем как писать реальные вызовы, убедитесь, что обмен сертификата на
токен вообще работает — на запущенном сервисе:
```bash
curl http://localhost:3000/diag/token
# {"ok":true} — сертификат подошёл, токен получен и закэширован
# {"ok":false,"error":"..."} — см. текст ошибки: неверный tenant/client id,
# истёкший сертификат, неверный scope и т.п.
```
Если `/diag/token` отвечает `ok:true`, но реальный вызов `api.tnsu.kz`
падает с `401`/`403` — вероятная причина в `GRAPH_SCOPE`: токен получен, но
выпущен не для этого API (Azure AD не проверяет аудиторию на этапе выдачи
токена — она проверяется уже на стороне `api.tnsu.kz`).