Причины:
- Выбор неподходящего flow (например, implicit для server-to-server).
- Хранение client_secret в открытом виде в коде или конфигах.
- Отсутствие валидации JWT (signature, exp, iss, aud).
- Использование HTTP вместо HTTPS.
- Необновление refresh-токенов или их бессрочное хранение.
Решение (Machine-to-Machine / Client Credentials):
1. Выделите OAuth2-сервер (Keycloak, Dex, самописный на Python+Flask-OAuthlib).
2. Создайте клиента с типом `confidential` и grant type `client_credentials`.
3. Получение токена:
bash
curl -X POST https://auth.internal/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=my-api" \
-d "client_secret=secret-here"4. Храните client_secret в Vault / Docker Secrets / зашифрованном env-файле (не в репозитории!).
5. Валидация токена в API (пример FastAPI + PyJWT):
python
import jwt
async def verify_token(access_token: str):
try:
payload = jwt.decode(
access_token,
public_key, # RS256, скачайте public key из /jwks
algorithms=["RS256"],
audience="https://api.internal",
issuer="https://auth.internal"
)
return payload["sub"] # или client_id
except jwt.PyJWTError:
raise HTTPException(status_code=401)6. Ограничения:
- Токен JWT – короткоживущий (например, 10–15 мин).
- Обновляйте ключи подписи и rotate client_secret по расписанию.
- Все эндпоинты аутентификации – только через TLS (HTTPS).
- Запретите логирование access_token (mask в логах).
Дополнительно (повышение безопасности):
- Добавьте проверку по IP/сети (allowlist для client_id).
- Используйте mTLS для дополнительного слоя аутентификации между сервисами.
- Включите rate limiting на /token endpoint.