Credentials vault: secrets the model never sees
Store portal logins so values are typed inside the browser on one registered site only — never read back, never in a prompt, a log or a replay.
Last updated:
Designed around what it refuses
The vault has no read-back endpoint, and never will; listing credentials returns field names only. The URL you set at creation defines the one registrable site the credential may ever be typed on — a login captured for portal.example.com cannot be released anywhere else.
The planner never touches a value either. It sees opaque placeholders, and a placeholder without a matching vault grant is refused outright rather than typed literally. Resolution happens inside the browser at the moment of typing, which is why a password never enters a prompt, a log line or a session replay.
Create and list over the API
Requires: api-key kek
BASE="https://browserberg.com"
AUTH="Authorization: Bearer $BROWSERBERG_API_KEY"
JSON="Content-Type: application/json"
# Create: the URL defines the only site this credential may ever be typed on.
curl -s -X POST "$BASE/v1/credentials" -H "$AUTH" -H "$JSON" -d '{
"name": "Example portal",
"url": "https://portal.example.com/login",
"fields": { "username": "buchhaltung@firma.example", "password": "not-a-real-password" },
"nonSecretFields": ["username"]
}' | python3 -m json.tool
# List: field NAMES only. There is no read-back endpoint, by design.
curl -s "$BASE/v1/credentials" -H "$AUTH" \
| python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin)["credentials"], indent=2))'
{
"credential": {
"id": "cred_xxxxxxxx",
"name": "Example portal",
"grantUrl": "https://portal.example.com/login",
"fields": [
"username",
"password"
],
"hasTotp": false,
"nonSecretFields": [
"username"
],
"createdAt": "2026-01-01T00:00:00.000Z",
"lastUsedAt": null,
"revokedAt": null
}
}
[
{
"id": "cred_xxxxxxxx",
"name": "Example portal",
"grantUrl": "https://portal.example.com/login",
"fields": [
"password",
"username"
],
"hasTotp": false,
"nonSecretFields": [
"username"
],
"createdAt": "2026-01-01T00:00:00.000Z",
"lastUsedAt": null,
"revokedAt": null
},
{
"id": "cred_xxxxxxxx",
"name": "Example portal",
"grantUrl": "https://portal.example.com/login",
"fields": [
"password",
"username"
],
"hasTotp": false,
"nonSecretFields": [
"username"
],
"createdAt": "2026-01-01T00:00:00.000Z",
"lastUsedAt": null,
"revokedAt": null
},
{
"id": "cred_xxxxxxxx",
"name": "Example portal",
"grantUrl": "https://portal.example.com/login",
"fields": [
"password",
"username"
],
"hasTotp": false,
"nonSecretFields": [
"username"
],
"createdAt": "2026-01-01T00:00:00.000Z",
"lastUsedAt": null,
"revokedAt": null
},
{
"id": "cred_xxxxxxxx",
"name": "Example portal",
"grantUrl": "https://portal.example.com/login",
"fields": [
"password",
"username"
],
"hasTotp": false,
"nonSecretFields": [
"username"
],
"createdAt": "2026-01-01T00:00:00.000Z",
"lastUsedAt": null,
"revokedAt": null
},
{
"id": "cred_xxxxxxxx",
"name": "Example portal",
"grantUrl": "https://portal.example.com/login",
"fields": [
"password",
"username"
],
"hasTotp": false,
"nonSecretFields": [
"username"
],
"createdAt": "2026-01-01T00:00:00.000Z",
"lastUsedAt": null,
"revokedAt": null
}
]
TOTP, usage and revocation
If a portal asks for one-time codes, add a totpSeed at creation; codes are generated server-side from the seed each time a login needs one, so the seed follows the same rule as every other field — it never leaves the vault.
Credentials are used in two places: act requests that pass credentialIds, and the login block of a workflow. DELETE /v1/credentials/:id is revocation — the credential stops being usable, which is the guarantee that matters.
Note · Self-hosted: a key provider is required
On a self-hosted deployment the vault needs a key provider — OVHcloud KMS, or a local KEK outside production. Without one, credential endpoints answer 503 capacity_unavailable and name the missing configuration.
Note · In the dashboard
The Anmeldedaten screen lists credentials by name and metadata, creates one with its fields and an optional TOTP seed, and revokes. Creating and revoking are owner actions; a member sees the list. No value is ever read back, there or here.