Skip to content

feat(web): reveal signing secrets after creation#90

Merged
jiashuoz merged 3 commits into
mainfrom
worktree-view-api-secrets
May 19, 2026
Merged

feat(web): reveal signing secrets after creation#90
jiashuoz merged 3 commits into
mainfrom
worktree-view-api-secrets

Conversation

@jiashuoz
Copy link
Copy Markdown
Contributor

Summary

  • GET /api/v1/users/me/signing-secrets now returns the full plaintext secret field alongside the existing secret_prefix. Plaintext was already stored in webhook_signing_secrets.secret (the relay needs it to sign HMACs), so this is a behavioral relaxation only — no new attack surface vs. DB-level access.
  • Settings → Webhook signing secrets table gains a per-row Show / Hide toggle and a Copy button. Default display is still the 12-char prefix.
  • API keys are intentionally not changed. They're stored as SHA-256 hashes; adding a plaintext column would be a real security regression. Users who lose an API key should delete + recreate.

Test plan

  • go test ./internal/identity/... ./internal/agent/... (serial; project requires -p 1)
  • cd web && npm test — 136/136 passing, including new Show/Hide test
  • cd web && npm run lint
  • Manual: open Settings, expand a secret with Show, hit Copy

jiashuoz and others added 3 commits May 18, 2026 16:15
The signing-secret plaintext is already stored in the DB (the relay
needs it to compute HMACs), so the previous "show once at creation"
posture was UX friction for no security gain. ListSigningSecrets now
returns the full secret alongside the prefix, and the settings page
adds a Show/Hide toggle with copy-to-clipboard per row.

API keys are deliberately not changed — they're stored as SHA-256
hashes today, and adding a plaintext column would be a real security
regression. If a user loses an API key they should delete + recreate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Drop the "save now, you can't see it again" copy on the post-create
  banner; with Show/Hide in the table that claim is no longer true.
  Banner now just announces the new secret and points at the table.
- Update the stale Go doc on handleListSigningSecrets that still
  claimed plaintext was excluded from list responses.
- Rename TestSigningSecrets_Create_ReturnsPlaintextOnce →
  ReturnsPlaintext, since the test already covers list-after-create.
- Fix the test fixture math: "abcd1234efgh".repeat(5) is 60 chars,
  not 64. Bumping to repeat(6) so the slice actually matters.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Operational hardening for the signing-secret reveal endpoint:

- Audit log each List call with user_id + count. The endpoint now
  hands out live HMAC credentials, so we want forensic breadcrumbs
  ("who pulled what when") without putting the values themselves in
  the log.
- Set Cache-Control: no-store on the List response. The Authorization
  header should already keep shared caches off it, but defense in
  depth is cheap here.

Coverage gaps called out in review:

- TestSigningSecrets_List_DoesNotLeakOtherUsers: pins the most
  load-bearing property of this endpoint — A's plaintext must never
  appear in B's list response.
- TestSigningSecrets_List_SetsNoStore: locks in the header.
- Web: clipboard mock + Copy-button test asserting writeText is
  called with the full plaintext and the label flips to "Copied".

Also tightened the SigningSecretSummary godoc — the prior wording
suggested API keys were moving away from hashes-only, which is the
opposite of the design intent.

Verified codegen round-trip: ran `make swagger`, `npm run
generate:openapi3 && generate:types`, and `datamodel-codegen` — all
three produced byte-for-byte identical output to the hand-edits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jiashuoz jiashuoz merged commit 8e74dc6 into main May 19, 2026
12 checks passed
@jiashuoz jiashuoz deleted the worktree-view-api-secrets branch May 19, 2026 01:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant