feat: api keys#1703
Conversation
move API key handlers and route scope into oss all server modes - prism, query, standalone - share the same webscope
WalkthroughAdds tenant-scoped API key HTTP endpoints for create, delete, list, validate, and fetch, plus route registration and revocation-sync error handling. ChangesAPI key HTTP surface
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 OpenGrep (1.23.0)src/apikeys.rs┌──────────────┐ �[32m✔�[39m �[1mOpengrep OSS�[0m [00.12][ERROR]: unable to find a config; path src/handlers/http/apikeys.rs┌──────────────┐ �[32m✔�[39m �[1mOpengrep OSS�[0m [00.13][ERROR]: unable to find a config; path Comment |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/handlers/http/apikeys.rs`:
- Around line 37-40: The tenant-admin check in the API key authorization flow is
bypassing RBAC aggregation by reading user.roles directly, so group-derived
admins can be denied. Update the authorization logic in the relevant API key
handler/utility that contains this admin gate to use the same runtime RBAC
permission path used elsewhere, rather than the cached direct role set on user.
Ensure the check recalculates permissions on each authorization decision so
dynamic/group-based admin grants are honored.
- Around line 277-293: The API-key deletion flow in the handler that calls
sync_user_deletion_with_ingestors currently logs sync failures but still returns
a successful response, which can mislead callers about revocation status. Update
the delete path so cluster sync is part of the success contract: if
sync_user_deletion_with_ingestors fails, return a retryable/pending-revocation
response instead of the success JSON, or otherwise only emit success after the
sync completes. Keep the fix localized to the deletion handler around the
existing tracing::error and HttpResponse::Ok response.
- Around line 199-214: The API key flow is persisting and re-serving the raw
bearer secret through the metadata and fetch paths. Update the api key creation
and storage logic around User::new_api_key, get_metadata, put_metadata, and
Users.put_user so only a hash or fingerprint is stored, while the raw secret is
returned once from create. Then adjust the GET/list handlers in this module so
they return masked API key metadata only and never expose the secret again.
- Around line 183-187: Role validation is happening before acquiring
UPDATE_LOCK, so the check can race with concurrent tenant role changes before
the API-key user update is persisted. Move the validate_roles(&body.roles,
&tenant_id) call inside the same locked section in the apikeys handler, after
the UPDATE_LOCK::lock().await guard is acquired and before any storage writes,
so the validation and update run atomically.
- Around line 311-320: The validate_api_key handler currently accepts any
authenticated tenant identity, which makes it usable as a secret-validity
oracle. Update validate_api_key to enforce the same admin gate used elsewhere by
calling verify_admin(&req)? before checking the request body, and keep the
existing collect_tenant_api_keys and ApiKeyError handling unchanged unless
needed to pass the admin check context.
In `@src/handlers/http/modal/server.rs`:
- Around line 233-234: The fetch route wired in server::resource("/{key_id}") to
apikeys::get_api_key is returning the full ApiKeyResponse, including the secret
api_key. Update get_api_key and its response type so this endpoint only returns
masked/non-sensitive metadata for an existing key, and keep full secret exposure
limited to the creation flow where the key is first generated.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 6b18c45a-227d-4dfe-a646-159e30e69d52
📒 Files selected for processing (4)
src/handlers/http/apikeys.rssrc/handlers/http/mod.rssrc/handlers/http/modal/query_server.rssrc/handlers/http/modal/server.rs
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/handlers/http/apikeys.rs (1)
255-272: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy liftMake revocation ordering compensatable before remote side effects.
If
sync_user_deletion_with_ingestorssucceeds butget_metadata/put_metadatafails afterward, remote nodes have revoked the key while this node keeps it in metadata andUsers. Consider a pending-revocation/tombstone or compensation flow so local persistence failure cannot leave split cluster auth state.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/handlers/http/apikeys.rs` around lines 255 - 272, The revocation flow in the API-key handler applies the remote cluster deletion before local metadata updates, which can leave split auth state if get_metadata or put_metadata fails afterward. Update the revocation path in the apikeys handler around sync_user_deletion_with_ingestors and the subsequent metadata mutation so local persistence is committed first or is made compensatable via a pending-revocation/tombstone state, and only then perform the remote side effect; if the remote call must stay first, add a retryable compensation path so a local failure cannot strand the key revoked on other nodes but still present in local Users/metadata.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/apikeys.rs`:
- Around line 52-53: The `ApiKeyError::RevocationSyncFailed` variant currently
carries the full sync error into its `Display` text, which will be exposed to
clients via `ResponseError`. Update `src/apikeys.rs` so this error variant uses
a generic client-safe message, and keep the detailed `e.to_string()` only in the
logging path in `src/handlers/http/apikeys.rs` where the revocation sync failure
is recorded. Use the `RevocationSyncFailed` symbol and its handling in the HTTP
apikeys handler to make sure the client response no longer leaks internal sync
details.
---
Outside diff comments:
In `@src/handlers/http/apikeys.rs`:
- Around line 255-272: The revocation flow in the API-key handler applies the
remote cluster deletion before local metadata updates, which can leave split
auth state if get_metadata or put_metadata fails afterward. Update the
revocation path in the apikeys handler around sync_user_deletion_with_ingestors
and the subsequent metadata mutation so local persistence is committed first or
is made compensatable via a pending-revocation/tombstone state, and only then
perform the remote side effect; if the remote call must stay first, add a
retryable compensation path so a local failure cannot strand the key revoked on
other nodes but still present in local Users/metadata.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 10190542-8132-4c4a-a263-db496f2a9244
📒 Files selected for processing (2)
src/apikeys.rssrc/handlers/http/apikeys.rs
move API key handlers and route scope into oss
all server modes - prism, query, standalone - share the same webscope
Summary by CodeRabbit
/apikeys.