Secret Management
Endpoints for managing client secrets. Each OAuth client can hold multiple secrets to support rotation without downtime.
All five routes require the token API license feature and resolve the client
by a lookup. The write routes (POST, PUT, DELETE) additionally require
Superuser. The plaintext secret is excluded by the model's default scope and
ignored in HAL output, so it is returned exactly once: in the create response.
GET /api/oauth-clients/{id}/secrets
List a client's secrets.
Authentication: Superuser + token API feature
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Client UUID or client_id |
Response:
A HAL collection (rel inf:oauth-client-secrets). Each row carries id, hint
(***** plus the last 8 characters), lastUsedAt (null until a token issued
with the secret is used), oauthClientId, createdAt, and updatedAt. The
plaintext secret is never present.
[
{
"id": "00000000-0000-4000-8000-000000000002",
"hint": "*****a880a7d3",
"lastUsedAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"oauthClientId": "00000000-0000-4000-8000-000000000001"
}
]
POST /api/oauth-clients/{id}/secrets
Generate a new client secret.
Authentication: Superuser + token API feature
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Client UUID or client_id |
Payload: empty
Response:
Responds 201 Created with a Location header. The server generates the secret
(a 96-character hex string from crypto.randomBytes(48)), bcrypt-hashes it for
storage, and returns the plaintext once. hint is ***** plus the last 8
characters of the plaintext.
{}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/oauth-clients/00000000-0000-4000-8000-000000000001/secrets/00000000-0000-4000-8000-000000000002"
}
},
"id": "00000000-0000-4000-8000-000000000002",
"secret": "example-secret-shown-once-on-create",
"tenant": "acme",
"oauthClientId": "00000000-0000-4000-8000-000000000001",
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z",
"hint": "*****a880a7d3",
"lastUsedAt": null
}
The plaintext secret is returned only in this response. It is bcrypt-hashed
before storage and cannot be retrieved later. Store it securely now.
GET /api/oauth-clients/{oauthClientId}/secrets/{id}
Get a single secret's metadata.
Authentication: Superuser + token API feature
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
oauthClientId | string | Client UUID or client_id |
id | string | Secret UUID |
Response:
Returns id, hint, lastUsedAt, oauthClientId, createdAt, and
updatedAt. The plaintext secret is never returned.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/oauth-clients/00000000-0000-4000-8000-000000000001/secrets/00000000-0000-4000-8000-000000000002"
}
},
"id": "00000000-0000-4000-8000-000000000002",
"hint": "*****a880a7d3",
"lastUsedAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"oauthClientId": "00000000-0000-4000-8000-000000000001"
}
PUT /api/oauth-clients/{oauthClientId}/secrets/{id}
Update a secret's metadata.
Authentication: Superuser + token API feature
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
oauthClientId | string | Client UUID or client_id |
id | string | Secret UUID |
Request Body:
There is no Joi payload schema; the payload is set directly onto the instance.
The mutable columns are hint and lastUsedAt.
{ "hint": "*****rotated1" }
Response:
Responds 200 with the updated secret; the plaintext secret is never
returned.
{
"hint": "*****rotated1"
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/oauth-clients/00000000-0000-4000-8000-000000000001/secrets/00000000-0000-4000-8000-000000000002"
}
},
"id": "00000000-0000-4000-8000-000000000002",
"hint": "*****rotated1",
"lastUsedAt": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"oauthClientId": "00000000-0000-4000-8000-000000000001"
}
DELETE /api/oauth-clients/{oauthClientId}/secrets/{id}
Delete a client secret.
Authentication: Superuser + token API feature
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
oauthClientId | string | Client UUID or client_id |
id | string | Secret UUID |
Response:
Responds 200 with an empty body (Informer's db.remove convention), not 204.
Deleting a secret does not revoke tokens already issued with it. Use the revoke endpoint to invalidate active tokens.