Repository navigation
Show when each API key was last used - #1140
Draft
AnthonyRonning wants to merge 1 commit into
Draft
AnthonyRonning wants to merge 1 commit into
AnthonyRonning wants to merge 1 commit into
Conversation
Give each API key a random, non-secret public_id. OpenSecret sends it as api_key_id in the usage event of API-key requests, and the API key settings read each key's latest billed use from the billing server by that ID. The key, its hash and its name stay in the enclave. The TypeScript and Rust SDK key types gain an optional public_id, so they keep working against servers that predate it. Refs #1138 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HhSn98TEgLj9EwtFekv8Qy
Contributor
|
Maple development preview: https://a4779125.maple-ca8.pages.dev Commit: Uses development API, billing, flags and PCR configuration. Cloudflare Access applies. |
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by T · project thread
Before: Settings → API keys lists each key's name and creation date, with no way to tell whether a key is still in use.
After: each key also shows when it was last used ("Last used Oct 11, 2026, 12:34 PM"), or "No use recorded yet". If usage can't be loaded, or the server predates this change, the list looks exactly as it does today.
Each API key gets a random, non-secret
public_id, the only key identifier that leaves the enclave: billing tracks usage under that ID, while the key, its hash and its name stay in OpenSecret.How: a migration adds a unique
user_api_keys.public_idthat defaults togen_random_uuid(), so existing keys each get their own. API-key auth now carries it asAuthMethod::ApiKey { public_id }, and usage events from API-key requests include it as an optionalapi_key_id; app (JWT) requests leave it out. The key list and create responses returnpublic_id, and the TypeScript and Rust SDK types gain it as an optional field, so they keep working against older servers (no SDK release here; the app reads it through its own type). The settings page reads billing'sGET /v1/maple/api-keysand matches its entries to keys bypublic_id.Big thanks to benthecarman, whose #1123 first brought "last used" to these keys. This keeps that feature and moves its bookkeeping to the billing side, as discussed there.
Billing side: MaplePrivacyLabs/maple-billing-server#120. Refs #1138. Per-key spend and budgets (#1139) are left for later; billing's response is one object per key so they can be added there.
Rollout order
Dev first, then Prod. Two steps must come in order; every other mix stays compatible.
public_idwhen it checks, lists or creates API keys, so on an unmigrated database those requests return 500; other app requests are unaffected. The old enclave ignores the new column, so the migration can run early. Filling the column rewritesuser_api_keysonce, and startup doesn't run migrations.Mixed states stay compatible: usage events from app requests are unchanged, and billing ignores the new
api_key_iduntil its side ships. Existing clients and both SDKs ignore the extrapublic_idin key responses, so no SDK release is needed. When one does ship, note that the RustApiKeyandApiKeyCreateResponsestructs gain a field, which matters only to code that builds them by hand.Rollback: either server can roll back at any time. Revert a migration only after its server is back on the old code, and avoid reverting the OpenSecret one once keys are in use: re-running it gives every key a new ID, which orphans its usage history.
Notes for review
Testing
cargo fmt --check,cargo clippy --all-targets -- -D warnings,cargo test(789 passed, 32 ignored), and the disposable-database helper with--redo-latest: 21 AEAD/database tests, 2 OAuth database tests and 8 callback tests passed, none skipped. That includes the newdb_api_key_auth_attributes_requests_to_the_key_public_id, which authenticates a key through the real middleware against Postgres.clippy --all-targets --all-features -D warnings,cargo test --lib(118 passed) and docs.format:check, build and the credential-free tests (291 passed, 3 skipped).scripts/ci/frontend.sh(format, lint with 0 errors, typecheck, and 1307 tests passed, including new settings-page and billing-client tests).public_idon key create and list.Environment differences: OpenSecret ran in a reduced Nix shell with the same locked nixpkgs, rust-overlay and
rust-toolchain.toml, because the default shell's BWS input can't be downloaded in this sandbox, and the database helper ran its Postgres as a non-root user. The frontend script ran with the SDK shell's pinned bun 1.3.5 instead of.#ci. Not run: an in-app check against a running stack.🤖 Generated with Claude Code
https://claude.ai/code/session_01HhSn98TEgLj9EwtFekv8Qy
Generated by Claude Code
<source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-light-v3.svg"><img alt="View with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/view-with-codesmith-dark-v3.svg">https://backend.blacksmith.sh/track/enable-autofix?expires=1794297911&installation_model_id=441606&pr_number=1140&ref=codesmith_pr_footer&repository=MaplePrivacyLabs%2FMaple&return_to=https%3A%2F%2Fgithub.com%2FMaplePrivacyLabs%2FMaple%2Fpull%2F1140&signature=8f775fd0a6f8ef7a6b5d0c6bb8e408524758c6e601adc244e73ea09c314c3688"><picture><source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"><img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg">Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.