Личные credentials
CRUD над собственными ключами — владелец берётся из токена, секрет никогда не возвращается.
Личные credentials принадлежат одному пользователю: сервер выставляет owner_type=user и owner_id равным sub вашего токена на каждом вызове. Тела запросов никогда не называют владельца, а записи другого пользователя для вас невидимы — их идентификаторы отвечают тем же 404, что и несуществующие.
Жизненный цикл в шести эндпоинтах
| Шаг | Эндпоинт |
|---|---|
| Создать | POST /v1/credentials |
| Список / чтение | GET /v1/credentials · GET /v1/credentials/{id} |
| Переименовать / ротировать | PATCH /v1/credentials/{id} |
| Переключить default | POST .../make-default |
| Пауза / возобновление | POST .../disable · POST .../enable |
| Удалить | DELETE /v1/credentials/{id} |
Создание валидирует секрет по credential_schema провайдера, шифрует его и хранит рядом несекретную configuration. Deprecated-провайдеры отказывают новым записям (409); провайдер также должен вообще допускать пользовательский уровень (иначе 409 OWNER_TYPE_NOT_ALLOWED_FOR_PROVIDER).
Роли: user и provider_admin мутируют; auditor только читает (403 на записях). Всё — в рамках общих бюджетов чтения/мутаций.
Маскирование: что возвращают чтения
Каждое чтение возвращает masked_credentials вместо секрета: длинные значения сохраняют узнаваемые начало/конец (sk-1***abcd), короткие и высокорисковые поля (например, client_secret) маскируются целиком. Маска пересчитывается из plaintext при каждой записи, поэтому после ротации меняется и маска — дешёвый способ убедиться, что ротация прошла. Конфигурация возвращается как хранится, в открытую.
Plaintext существует для API ровно в двух местах, и ни одно из них не на этой плоскости: машинный resolve и операторский reveal.
Ротация — это замена
PATCH с объектом credentials заменяет весь секретный объект целиком — попольного слияния нет. Это намеренно: ротация — это «вот новый ключ», валидированный по схеме и заново зашифрованный активным ключом. Оптимистичная блокировка обязательна (version в теле или If-Match); устаревшая версия — 409 CREDENTIAL_VERSION_CONFLICT. PATCH никогда не трогает status или is_default — у них выделенные переходы (Defaults and Lifecycle).
Разобранный пример: сценарий cookbook 03.
Удаление мягкое, но немедленное
DELETE убирает запись из каждого списка и из resolve сразу; шифротекст переживает окно восстановления (по умолчанию 5 дней) до физической очистки, а повторное удаление — идемпотентный 204. Эндпоинта undelete не существует — восстановление внутри окна является операторским действием.