Updated May 8, 2026 This is the model page for API keys — what they are, how they get their permissions, what their lifecycle looks like, and the security practices that follow from the design. The Roles model itself is on Roles, scopes, and the Owner; this page focuses on the key-specific parts.Documentation Index
Fetch the complete documentation index at: https://docs.rafftechnologies.com/llms.txt
Use this file to discover all available pages before exploring further.
What an API key is
An API key is a long random secret token that authenticates a non-interactive client (a script, a CI pipeline, Terraform, a backend service) against the Raff API. Format:raff_prefix — distinctive, easy to grep for in code reviews and to detect via tools like GitGuardian ortruffleHog- A long opaque suffix — the secret part. Treat it like a password
- Sent in every authenticated request as the
X-API-Keyheader
How a key gets its permissions
Every key carries an Account Role + (optionally) a Project Role applied to one or more projects: In plain words:| The key carries | Which determines |
|---|---|
| Account Role (one — required) | The key’s account.* permissions (members, billing, audit, project list, role catalog) |
| Projects + Project Role (zero or more projects, one role applied to all of them — optional, hidden when Account Role is Owner) | The key’s project.* / vm.* / vpc.* / etc. permissions on those projects only |
| Expiration | When the key auto-revokes |
- Same role catalog as members. The Account Role / Project Role dropdowns in Create API Key list the exact same System and Custom roles you assign to members. There’s no “key-only” permission set.
- Owner = full access, no project selection needed. When the Account Role is Owner, the key has Owner-level access to every project, current and future. The Project Role / projects fields are hidden in the create dialog.
- One Project Role applied uniformly. When the Account Role is anything other than Owner, you pick one or more projects and a single Project Role; that role applies the same way on all selected projects. To give a key different roles on different projects, create one key per role.
Frozen role, mutable role definition
A key carries a reference to a role (e.g.Operator for project access on customer1) — not a snapshot of permissions. This has an important consequence:
- Editing the role definition affects every key (and member) using that role. Add
vm.consoleto your CustomCI Operatorrole, and every key with that role gainsvm.consoleaccess on next request. - Editing the key directly is not supported — there’s no “change role on this key” action. The fix is to rotate the key (Regenerate) if you want a fresh key value, or delete and recreate if you want a different role assignment.
The create-once / show-once secret lifecycle
The full key value is shown exactly once — in the API Key Created dialog right after you click Create. After that, only the prefix (raff_17d70fcf…) is visible on the dashboard’s API Keys list.
This is intentional: Raff stores only a hash of the key value, not the value itself, so even Raff staff can’t show it back to you. If you lose the key value, the only path forward is to rotate (Regenerate) — that issues a new value and invalidates the old.
Expiration
Every key has an expiration — either Never or one of the bounded presets (30 / 60 / 90 / 120 / 180 days, 1 year). The expiration is set at create time and is immutable:- An expired key authenticates with
401 Unauthorizedand is unusable until rotated. - Rotation issues a fresh key value with the same expiration setting calculated from the rotation timestamp (a key originally set to “1 year” gets another full year on rotation; a key set to “Never expires” keeps that property).
- To change a key’s expiration model (e.g. from “1 year” to “Never” or vice versa), delete and recreate with the new setting.
Lifecycle states
A key passes through a small set of states:| State | Reached by | Effect |
|---|---|---|
| Active | Successful Create | Authenticates requests; permissions taken from current role definitions |
| Expired | Reaching its expiration timestamp | Returns 401; key remains in the list with Expires: Expired until you delete or rotate |
| Rotated | Clicking Regenerate | Old value invalid immediately; new value issued. Same Active state, just a different secret |
| Deleted | Clicking the red trash icon, or via API | Authentication fails immediately; key disappears from list. Audit-log entries referencing the key remain |
Authentication, briefly
Every authenticated API request includes:One key per integration
The right granularity for keys: one key per integration, named for what it does. Examples:Production CI— the key your CI pipeline uses to deployBackups Lambda— the key your scheduled backup script usesTerraform — staging— the key your IaC uses against the staging projectDatadog Sync— the key your observability vendor uses to read VM metadata
- Rotation cheap — when one integration is compromised or being decommissioned, you rotate / delete just its key
- Audit logs readable —
apikey.id = abc123 (Backups Lambda)is more useful thanapikey.id = abc123and grepping - Scope tight — each key gets exactly the permissions its integration needs, nothing more
Security practices
A short list of practices that make API-key security boring (which is the goal):| Practice | Why |
|---|---|
| Use bounded expirations (30 / 90 / 180 days) for production keys | Forces rotation; auto-revokes forgotten keys |
| Use System or Custom roles narrower than Owner for any key that doesn’t need full access | Limits the blast radius of a leak |
| Never commit a key value to source control. Use environment variables and a secret manager (1Password, AWS Secrets Manager, GitHub Actions secrets, Vault) | Prevents the most common leak path |
| One key per integration, named for the integration | Cheap rotation, useful audit logs |
| Rotate on suspicion, not just on policy | When a key may be compromised, rotate first and investigate after |
Watch Last Used for keys you don’t recognize | A key that’s never been used or hasn’t been used in months may be a forgotten attack surface — delete it |
| Use the audit log to track who created which key, who rotated, who deleted | account.audit.view permission required |
raff_ prefix is also designed to make accidental commits detectable: GitGuardian, truffleHog, and similar secret-scanners pick it up out of the box. If you push a key by mistake, the scanner will flag it within minutes — rotate immediately and review the commit.
What you cannot do today
- Edit a key’s permissions after create — change the underlying role, or rotate to a different key
- Assign different Project Roles to different projects in one key — create separate keys
- Recover the full key after the create dialog closes — only the prefix is preserved
- Extend a key’s life past its current expiration — rotate to refresh, or delete and recreate
- Disable a key without deleting it — deletion is the only “stop” mechanism
Related
Generate an API key
Walk the create flow.
Rotate an API key
Replace a leaked or aging key.
Authentication
How keys authenticate against the API.