Персональні credentials
CRUD над власними ключами — власник береться з токена, а секрет назад не повертається.
Персональні credentials належать одному користувачеві: сервер на кожному виклику ставить owner_type=user і owner_id = sub вашого токена. Тіла запитів ніколи не називають власника, а чужі записи для вас невидимі — їхні id відповідають тим самим 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); провайдер також мусить взагалі допускати рівень user (інакше — 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 замінює весь секретний об'єкт — жодного поелементного merge. Це навмисно: ротація — це «ось новий ключ», провалідований проти схеми й перешифрований активним ключем. Оптимістичне блокування обов'язкове (version у тілі або If-Match); застаріла версія — 409 CREDENTIAL_VERSION_CONFLICT. PATCH ніколи не торкається status чи is_default — для них є окремі переходи (Defaults and Lifecycle).
Розібраний приклад: сценарій cookbook 03.
Видалення м'яке, але миттєве
DELETE одразу прибирає запис з усіх списків і з resolve; шифротекст переживає вікно відновлення (за замовчуванням 5 днів) до фізичного purge, а повтор видалення — ідемпотентний 204. Ендпоїнта undelete немає — відновлення в межах вікна є дією оператора.