OAuth Client: Public и Confidential
Client — приложение, которое запрашивает авторизацию. Тип клиента определяет, может ли
приложение безопасно хранить client_secret.
Public
public подходит для SPA и других приложений, где код или настройки доступны пользователю.
Secret не используется. Для браузерного входа применяйте Authorization Code Flow с PKCE.
Confidential
confidential подходит для backend-приложения. client_secret хранится только на сервере и
используется при обмене authorization code.
Практика
Не помещайте client_secret в JavaScript bundle, localStorage, публичный конфигурационный
файл или Git. Тип client не равен типу платформы: это характеристика способности хранить секрет.
Что настраивается у App
При создании App указывается clientId, проект, тип клиента, grant types и Redirect URI.
В backend DTO также присутствуют имя и описание приложения. Конфигурация возвращает client_id,
client_secret, client_type, grant_types и redirect_uris.
Secret показывается отдельно и должен обрабатываться как credential. Если нужно прочитать или изменить secret в кабинете, backend требует подтверждение паролем пользователя.
Как выбрать тип
Задайте два вопроса:
- Где выполняется exchange authorization code?
- Может ли это место хранить secret вне доступа пользователя?
Если exchange выполняется в браузере, выбирайте Public и PKCE. Если exchange выполняется в вашем backend, выбирайте Confidential и храните secret на сервере.
Один и тот же продукт может иметь несколько App: Public для SPA и Confidential для server-rendered приложения. Не нужно использовать один secret во всех клиентах.
Типичные ошибки
- публиковать Confidential secret в
.envс префиксомNEXT_PUBLIC_; - выбирать Confidential только потому, что используется Next.js;
- регистрировать один Redirect URI для разных приложений без необходимости;
- считать
client_idсекретом и прятать его от браузера; - использовать неподдерживаемый grant type вместо
authorization_codeиrefresh_token.
Как проверить результат
- Public App не содержит secret в bundle;
- Confidential secret присутствует только на backend;
- Redirect URI принадлежит нужному App;
- grant types соответствуют реальному flow;
- после утечки secret он заменён, а старое значение больше не используется.
Client ID не является паролем
client_id участвует в открытом authorization request и может быть известен браузеру. Его
задача — выбрать App. Secret подтверждает право Confidential client выполнять token request.
Поэтому client ID можно передавать в frontend, а secret — нельзя.
App и Project
Project является контейнером для приложений и границей организации конфигурации. App связывает
конкретный клиент с Project и содержит его Redirect URI. Не смешивайте projectId и внутренний
UUID проекта: backend использует их в разных операциях. Перед API-запросом проверьте, какой
идентификатор требует конкретный endpoint.
Смена secret
Если secret был раскрыт, одной смены переменной окружения недостаточно: новый secret должен быть установлен в backend, старый больше не должен использоваться, а активные сессии и логи нужно оценить. Не показывайте secret в документации или debug response.
Проверка архитектуры
Нарисуйте путь:
браузер -> callback -> backend или SDK -> token endpoint -> API
Место, где происходит обмен code, должно совпадать с типом App. Если на схеме secret оказывается после границы браузера, тип и flow выбраны неверно.
Как это реализовано в Authoriza
У App есть client_id, тип, grant types и список Redirect URI. Поддержанные grant types
backend-контракта включают authorization_code и refresh_token, а методы аутентификации
клиента — none и client_secret_basic.
Чем Authoriza может быть полезна
Если вам нужно заранее разделить browser client и server client, модель Public/Confidential в Authoriza помогает зафиксировать эту границу в настройках App. Сначала определите архитектуру, затем откройте выбор типа подключения.