---
id: w4/m8/t002
title: "Dashboard settings: API Keys section — list (name/created, never secrets) + revoke with confirmation"
worker: worker4
status: done
estimate: 40m
depends_on: [w4/m8/t001]
---

## Objective

Add an API Keys section to the dashboard settings area: an Apollo-backed list of the workspace's bex-minted keys (visible to any session with `can_manage_keys`; keys have no per-user owner — this is a shared credential pool, not "my keys") showing name/client id and created date (the `APIKey` type has no last-used field; secrets are never present in list responses by design) and a revoke action behind a confirmation dialog, with optimistic-update or refetch so a revoked key disappears immediately.

## Context

- `dashboard/CLAUDE.md` before editing; stack = TanStack Start + Apollo + shadcn.
- Settings today: `dashboard/src/features/auth/pages/settings-page/` renders only the Kratos settings flow — decide placement (a sibling section on `/settings` or a settings tab) consistent with the existing routing (`dashboard/src/routes/settings.tsx`).
- GraphQL operations from m3 (t001 confirmed/extended them for sessions).

## Steps

1. Add the GraphQL query/mutation documents + generated types per the dashboard's codegen setup.
2. Build the list + empty state + revoke confirmation (shadcn dialog) in a `features/` module.
3. Wire into the settings route; loading/error states consistent with existing pages.

## Files

- `dashboard/src/features/` (new api-keys module)
- `dashboard/src/routes/settings.tsx` (or the settings page composition)

## Acceptance criteria

- [x] Logged-in user sees the workspace's bex-minted keys (no secret material anywhere in the DOM or network tab beyond the list shape).
- [x] Revoke asks for confirmation, then the key is gone from the list and its token stops working.

## Out of scope

- Mint flow (t003).

## Resolution

`dashboard/src/features/api-keys/` (new module): `api/api-keys.graphql` (list never requests `secret`), `hooks/use-api-keys.ts` + `use-revoke-api-key.ts`, `components/api-keys-panel.tsx` (Card list + empty/forbidden/generic states, mirrors `EnvVarsPanel`) + `api-key-row.tsx` (AlertDialog-gated revoke, mirrors `EnvVarRow`'s delete). Wired into `features/auth/pages/settings-page/index.tsx` as a sibling section below the Kratos flow. Documents generated by running `yarn codegen` against an in-process schema dump (no live cluster available; `internal/api.NewServer(...).newSchema()` + the `graphql-go/graphql` introspection query, fed to codegen as a local schema file) rather than hand-writing the AST — `ApiKeysDocument`/`CreateApiKeyDocument`/`RevokeApiKeyDocument` in `src/graphql/definitions.ts` are genuine codegen output. `yarn typecheck` and `yarn lint` clean.
