# API Key Management UI: anlegen, rotieren, widerrufen

> Bau eine API Key Management UI in React: Keys mit Scopes und Ablauf anlegen, das Secret einmal zeigen, kopieren, rotieren, widerrufen, nur den Hash speichern.

- Autor: [Serban Rusu](https://wingo-ui.com/blog/authors/serban), Founder of Wingo UI
- Veröffentlicht: 6. Nov. 2026
- Kategorie: [Praxis: Screens und Apps](https://wingo-ui.com/de/blog/category/build)
- Lesezeit: 10 Min.
- Kanonische URL: https://wingo-ui.com/de/blog/api-key-management-ui
- Englische Fassung: https://wingo-ui.com/blog/api-key-management-ui

## Kurz gesagt

Eine API Key Management UI listet jeden Key mit Namen, maskiertem Präfix, Scopes, letzter Nutzung und Ablaufdatum und lässt die Nutzer Keys anlegen, umbenennen, rotieren und widerrufen. Das Secret erscheint genau einmal, direkt nach dem Anlegen oder Rotieren, mit einem Copy-Button, und der Server speichert nur einen Hash davon. In React startest du mit dem Block API Keys Page von Wingo UI und übergibst eigene Handler zum Anlegen, Rotieren, Umbenennen und Widerrufen.

Dein Produkt hat eine API, also braucht deine Einstellungsseite eine API Key Management UI: einen Screen, auf dem Entwickler ihre API-Keys verwalten: einen Key anlegen, ihn in eine Umgebungsvariable kopieren und ihn später rotieren oder widerrufen, ohne ein Support-Ticket aufzumachen. Was du zum Thema findest, ist meist das eine oder das andere: ein Block aus einer Galerie, der eine Tabelle mit einem maskierten String rendert, oder Anbieter-Doku dazu, wie man Keys speichert. Kaum jemand verbindet beides. Dieser Guide deckt beide Hälften ab: den Screen (Anlegen mit Scopes und Ablaufdatum, das Secret einmal zeigen, kopieren, rotieren, umbenennen, widerrufen) und das, was das Backend dafür liefern muss (einen Hash speichern, ein Präfix anzeigen), gebaut in Next.js mit dem Block [API Keys Page](https://wingo-ui.com/components/api-keys-page).

## Was braucht eine API Key Management UI?

Sie braucht fünf Dinge: eine Liste, die man schnell überblickt, einen Anlege-Dialog mit Scopes und Ablaufdatum, eine einmalige Anzeige des Secrets, abgesichertes Rotieren und Widerrufen sowie Limits mit Warnungen. Gutes API Key UI Design deckt alle fünf ab, denn jedes davon verhindert einen bestimmten Fehler:

1. **Eine Liste, die ein Mensch überblicken kann.** Name, ein maskiertes Präfix (`ak_live_3f9a••••`), Status, Scopes, Erstelldatum, letzte Nutzung und Ablauf. An „Zuletzt genutzt vor 3 Stunden“ erkennt jemand, ob ein Key gefahrlos weg kann.
2. **Bewusst anlegen.** Ein Name, die Scopes, die der Key nutzen darf, und ein Ablaufdatum. Ein Key ohne Namen wird zu „Key 4“, und niemand traut sich, ihn zu widerrufen.
3. **Eine einmalige Anzeige.** Das Secret erscheint ein einziges Mal, bereits markiert, mit einem Copy-Button und dem Hinweis, dass es nicht noch einmal angezeigt wird.
4. **Rotieren und Widerrufen nur mit Bestätigung.** Beides legt laufende Integrationen lahm, also fragt beides vorher nach, und Widerrufen ist rot.
5. **Limits und Warnungen.** Ein Limit für aktive Keys je nach Plan, das Create key mit Begründung deaktiviert, und ein gelber Hinweis „Läuft in 5 Tagen ab“, bevor ein Key still aufhört zu funktionieren.

Der Block API Keys Page bringt alle fünf mit. Probier es aus: Öffne das Zeilenmenü bei „CI pipeline“, rotier den Key und leg dann einen neuen an.

> Live-Demo (API Keys Page): Öffne das Menü einer Zeile, um zu rotieren, umzubenennen oder zu widerrufen, oder drück Create key: Wähl Scopes und ein Ablaufdatum und kopier dann das Secret aus der einmaligen Anzeige. Probier sie unter [API Keys Page](https://wingo-ui.com/components/api-keys-page) aus und installier sie mit `npx wingo-ui@latest add api-keys-page`.

## Was sollte der Server für jeden Key speichern?

Einen Hash des Secrets und ein kurzes Präfix, nie das Secret selbst. Das Präfix dient nur der Anzeige, damit Nutzer ihre Keys auseinanderhalten können. Über den Hash findest du den Key, wenn eine Anfrage ankommt. Laut der [Doku zu API-Keys von Stripe](https://docs.stripe.com/keys) (geprüft im November 2026) wird ein Secret Key, den du im Live-Modus anlegst, nur einmal angezeigt und lässt sich später nicht mehr aufdecken; wer ihn verliert, rotiert ihn. Genau dieses Modell solltest du übernehmen.

Ein Key-Format mit erkennbarem Präfix hilft außerdem Secret-Scannern. GitHub hat seine Präfixe `ghp_`, `gho_` und verwandte sowie eine Prüfsumme in [einem Beitrag vom April 2021](https://github.blog/engineering/platform-security/behind-githubs-new-authentication-token-formats/) erklärt: Der Unterstrich ist kein Base64-Zeichen, deshalb sehen zufällige Strings selten wie Tokens aus, und ein Doppelklick markiert das ganze Token. Aus demselben Grund nutzt du im Rest des Keys nur Buchstaben und Ziffern.

```ts
// server/api-keys.ts
import { createHash, randomBytes, randomInt } from "node:crypto"

const ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

function randomBase62(length: number) {
  return Array.from({ length }, () => ALPHABET[randomInt(ALPHABET.length)]).join("")
}

export function sha256(value: string) {
  return createHash("sha256").update(value).digest("hex")
}

// ak_live_3f9a_<32 zufällige Zeichen>; gespeichert werden nur Präfix und Hash
export function newApiKey() {
  const prefix = `ak_live_${randomBytes(2).toString("hex")}`
  const secret = `${prefix}_${randomBase62(32)}`
  return { prefix, secret, hash: sha256(secret) }
}
```

Zweiunddreißig Base62-Zeichen liefern etwa 190 Bit Entropie, also reicht ein schnelles SHA-256 mit Unique-Index. Ein langsamer Passwort-Hash wie bcrypt schützt Passwörter, die sich erraten lassen; hier würde er nur jede API-Anfrage verlangsamen. Eine Anfrage zu prüfen ist ein einziger Lookup über den Index:

```ts
// server/authenticate.ts
import { db } from "@/server/db" // dein Data Layer (Drizzle, Prisma, SQL)
import { sha256 } from "@/server/api-keys"

export async function authenticate(request: Request) {
  const secret = request.headers.get("authorization")?.replace(/^Bearer\s+/i, "")
  if (!secret?.startsWith("ak_live_")) return null
  const key = await db.apiKey.findUnique({ where: { hash: sha256(secret) } })
  if (!key || key.revokedAt || (key.expiresAt && key.expiresAt < new Date())) return null
  // lastUsedAt höchstens einmal pro Minute schreiben, nicht bei jeder Anfrage
  if (!key.lastUsedAt || Date.now() - key.lastUsedAt.getTime() > 60_000) {
    await db.apiKey.update({ where: { id: key.id }, data: { lastUsedAt: new Date() } })
  }
  return key
}
```

Der Status wird abgeleitet, nicht gespeichert: Ein Key mit `revokedAt` ist widerrufen, ein Key nach `expiresAt` ist abgelaufen, alles andere ist aktiv. Der Block behandelt einen aktiven Key, dessen Datum vorbei ist, ebenfalls als abgelaufen. So bleibt die Liste ehrlich, auch wenn deine Daten hinterherhinken.

## Wie zeigst du das Secret nur einmal?

Zeig es im selben Dialog, der es erzeugt hat, fokussiert und markiert, und mach es schwer, den Dialog aus Versehen zu schließen. Im Block tauscht der Dialog nach einem Klick auf Create key das Formular gegen ein schreibgeschütztes Feld mit dem Secret, einen [Copy Button](https://wingo-ui.com/components/copy-button) darin und eine Warnung. Done bleibt deaktiviert, bis du kopierst oder „I saved this key somewhere safe“ anhakst, und bis dahin bewirken Klicks außerhalb und Escape nichts. Das Secret landet nie in einem Toast, in der URL oder im Storage, und es verschwindet aus dem Speicher, sobald der Dialog schließt.

> Live-Demo (API Keys Page): Der Anlege-Dialog: Gib dem Key einen Namen, wähl Scopes und ein Ablaufdatum, drück Create key und kopier das Secret, bevor Done aktiv wird. Probier sie unter [API Keys Page](https://wingo-ui.com/components/api-keys-page) aus und installier sie mit `npx wingo-ui@latest add api-keys-page`.

Dieselbe Anzeige erscheint nach dem Rotieren, mit dem Namen des Keys im Titel. Damit ist die häufigste Support-Anfrage zu Keys abgedeckt: „Ich habe meinen Key verloren.“ Die Antwort ist Rotieren, nie „wir schicken ihn dir per E-Mail“. Egal, wie der Button in deiner UI zum Generieren von API-Keys heißt (Create key, New token, Generate): Das Secret sollte im Browser nur existieren, solange dieser Dialog offen ist.

## Wie verbindest du die API Keys Page mit Next.js?

Installier den Block, leg die Listen für Scopes und Ablaufzeiten in ein gemeinsames Modul und übergib vier Server Actions als Handler. Die Installation bringt Dialog, Tabelle, Copy Button, Alert Dialog und den Rest mit:

```bash
npx wingo-ui@latest add api-keys-page
```

Leg die Listen für Scopes und Ablaufzeiten in ein einfaches Modul, das sowohl die Client-Ansicht als auch die Server Actions importieren. Die eigenen Defaults des Blocks liegen in einer Client-Datei, und ein Server-Modul sollte keine Werte aus so einer Datei importieren.

```ts
// app/(app)/settings/api-keys/keys-config.ts
import type { ApiKeyExpiryOption, ApiKeyScope } from "@/components/blocks/api-keys-page-data"

export const SCOPES: ApiKeyScope[] = [
  { value: "orders:read", label: "Bestellungen lesen", description: "Bestellungen auflisten und abrufen" },
  { value: "orders:write", label: "Bestellungen schreiben", description: "Bestellungen anlegen, ändern und erstatten" },
  { value: "webhooks", label: "Webhooks", description: "Webhook-Endpunkte verwalten" },
]

export const EXPIRY: ApiKeyExpiryOption[] = [
  { value: "30d", label: "30 Tage", days: 30 },
  { value: "90d", label: "90 Tage", days: 90 },
  { value: "1y", label: "1 Jahr", days: 365 },
]
```

Dass es keine Option „Nie“ gibt, ist eine Produktentscheidung. Sie erzwingt Rotation, kostet dich aber eine E-Mail, die vor dem Ablauf rausgehen muss.

Die Server Actions geben ein Ergebnisobjekt zurück, statt einen Fehler zu werfen. Der [Guide zur Fehlerbehandlung von Next.js](https://nextjs.org/docs/app/getting-started/error-handling) (geprüft im November 2026) empfiehlt, erwartbare Fehler als Rückgabewerte zu modellieren, und Production-Builds geben die Meldung eines auf dem Server geworfenen Fehlers nicht an den Client weiter. Ein geworfenes „Du hast das Limit von 10 Keys erreicht“ käme im Dialog also nur als allgemeiner Fehler an.

```ts
// app/(app)/settings/api-keys/actions.ts
"use server"

import type { ApiKey } from "@/components/blocks/api-keys-page-data"
import type { ApiKeyCreateInput } from "@/components/blocks/api-keys-page"
import { db } from "@/server/db"
import { newApiKey } from "@/server/api-keys"
import { requireAdmin } from "@/server/dal"
import { EXPIRY, SCOPES } from "./keys-config"

type Result<T> = { ok: true; data: T } | { ok: false; error: string }
const DAY = 86_400_000

export async function createKey(input: ApiKeyCreateInput): Promise<Result<{ key: ApiKey; secret: string }>> {
  const { user, workspaceId } = await requireAdmin()
  const expiry = EXPIRY.find((option) => option.value === input.expiresIn)
  const scopes = input.scopes.filter((scope) => SCOPES.some((s) => s.value === scope))
  if (!input.name.trim() || !expiry || scopes.length === 0) return { ok: false, error: "Gib einen Namen, einen Scope und ein Ablaufdatum an." }

  // zählt, was der Block zählt: nicht widerrufen und nicht abgelaufen
  const active = await db.apiKey.count({
    where: { workspaceId, revokedAt: null, OR: [{ expiresAt: null }, { expiresAt: { gt: new Date() } }] },
  })
  if (active >= 10) return { ok: false, error: "Du hast das Limit von 10 Keys erreicht. Widerruf zuerst einen." }

  const { prefix, secret, hash } = newApiKey()
  const row = await db.apiKey.create({
    data: {
      workspaceId,
      name: input.name.trim(),
      prefix,
      hash,
      scopes,
      createdBy: user.name,
      expiresAt: expiry.days === null ? null : new Date(Date.now() + expiry.days * DAY),
    },
  })
  // ein Renew ersetzt den abgelaufenen Key, aus dem er entstanden ist
  if (input.renews) await db.apiKey.update({ where: { id: input.renews, workspaceId }, data: { revokedAt: new Date() } })

  const key: ApiKey = {
    id: row.id,
    name: row.name,
    prefix: row.prefix,
    scopes: row.scopes,
    createdAt: row.createdAt.getTime(),
    lastUsedAt: null,
    expiresAt: row.expiresAt?.getTime() ?? null,
    createdBy: row.createdBy,
    status: "active",
  }
  return { ok: true, data: { key, secret } }
}

export async function rollKey(id: string): Promise<Result<{ secret: string }>> {
  const { workspaceId } = await requireAdmin()
  const { prefix, secret, hash } = newApiKey()
  await db.apiKey.update({ where: { id, workspaceId, revokedAt: null }, data: { prefix, hash, lastUsedAt: null } })
  return { ok: true, data: { secret } }
}

export async function revokeKey(id: string): Promise<Result<null>> {
  const { workspaceId } = await requireAdmin()
  await db.apiKey.update({ where: { id, workspaceId }, data: { revokedAt: new Date() } })
  return { ok: true, data: null }
}

export async function renameKey(id: string, name: string): Promise<Result<null>> {
  const { workspaceId } = await requireAdmin()
  if (!name.trim()) return { ok: false, error: "Der Name darf nicht leer sein." }
  await db.apiKey.update({ where: { id, workspaceId }, data: { name: name.trim() } })
  return { ok: true, data: null }
}
```

Jede Action beschränkt die Abfrage auf den Workspace des Aufrufers. Der Client schickt eine id, und der Server entscheidet, ob diese id zum Aufrufer gehört. Die Limitprüfung zählt nur Keys, die weder widerrufen noch abgelaufen sind, nach derselben Regel, die der Block für `maxKeys` nutzt. Ein alter, abgelaufener Key blockiert also nie einen neuen. `requireAdmin()` folgt dem Data Access Layer aus dem [Next.js-Admin-Dashboard-Tutorial](https://wingo-ui.com/de/blog/nextjs-admin-dashboard-tutorial): Es prüft die Session und gibt in dieser Version den angemeldeten Nutzer und die id seines Workspaces zurück.

Die Client-Ansicht macht aus einem fehlgeschlagenen Ergebnis wieder einen Fehler. Den zeigt der Block direkt im Formular an, und die Eingaben bleiben stehen:

```tsx
// app/(app)/settings/api-keys/keys-view.tsx
"use client"

import { ApiKeysPage } from "@/components/blocks/api-keys-page"
import type { ApiKey } from "@/components/blocks/api-keys-page-data"
import { createKey, renameKey, revokeKey, rollKey } from "./actions"
import { EXPIRY, SCOPES } from "./keys-config"

async function unwrap<T>(result: Promise<{ ok: true; data: T } | { ok: false; error: string }>) {
  const res = await result
  if (!res.ok) throw new Error(res.error)
  return res.data
}

export function KeysView({ keys }: { keys: ApiKey[] }) {
  return (
    <ApiKeysPage
      defaultKeys={keys}
      scopes={SCOPES}
      expiryOptions={EXPIRY}
      defaultExpiry="90d"
      maxKeys={10}
      docsHref="/docs/api"
      onCreate={(input) => unwrap(createKey(input))}
      onRoll={(id) => unwrap(rollKey(id))}
      onRename={(id, name) => unwrap(renameKey(id, name))}
      onRevoke={(id) => unwrap(revokeKey(id))}
    />
  )
}
```

Die Server-Datei `page.tsx` lädt die Keys des Workspaces, wandelt sie in `ApiKey` mit Zeitstempeln als Zahlen um und rendert `<KeysView keys={keys} />`. Sie kann auch ein Abschnitt einer größeren [React Settings Page](https://wingo-ui.com/de/blog/react-settings-page) sein.

## Sollte Rotieren das alte Secret sofort beenden?

Nicht immer: Beende es sofort, wenn ein Key geleakt ist, und erlaube bei einer geplanten API Key Rotation eine kurze Überlappung. Der Standardtext des Blocks sagt, dass das aktuelle Secret sofort aufhört zu funktionieren. Das ist nach einem Leak die sichere Wahl. Stripe geht bei geplanter Rotation den anderen Weg: Laut seiner [Doku zur Rotation](https://docs.stripe.com/keys) funktionieren Stand November 2026 der alte und der neue Key bis zu 7 Tage lang, wenn du im Dashboard rotierst. So können Integrationen ohne Ausfall umziehen.

Wenn du ein Übergangsfenster willst, behalte den alten Hash in einer zweiten Spalte mit eigenem Ablauf, akzeptier in `authenticate` beide und pass den Bestätigungstext an, damit er stimmt:

```tsx
<ApiKeysPage
  labels={{ rollDescription: "Das aktuelle Secret funktioniert noch 24 Stunden, danach nicht mehr. Aktualisiere deine Apps bis dahin." }}
  onRoll={(id) => unwrap(rollKey(id))}
/>
```

Widerrufen wirkt in beiden Fällen sofort. Die Bestätigungen fürs Rotieren und Widerrufen folgen dem Muster aus dem [Alert Dialog](https://wingo-ui.com/components/alert-dialog): Der Fokus startet auf Cancel, der Action-Button sagt, was er tut, und bei einer fehlgeschlagenen Anfrage wackelt die Karte kurz, und der Fehler erscheint an Ort und Stelle.

## Wann brauchst du stattdessen eine Data Table?

Wenn du Keys über alle Workspaces hinweg auflistest, für den Support oder einen internen Admin-Bereich. Der Block nutzt eine einfache Tabelle, weil ein Workspace selten mehr als ein Dutzend Keys hat. Eine Support-Ansicht über alle Kunden ist etwas anderes: Tausende Keys, gesucht nach Präfix, gefiltert nach Status und Ersteller. Das ist ein Fall für die [Data Table](https://wingo-ui.com/components/data-table), mit einer `badge`-Spalte für den Status, `relative`-Spalten für letzte Nutzung und Ablauf und `rowActions` zum Widerrufen. Halte die einmalige Anzeige ganz aus dieser Ansicht heraus. Der Support soll einen Key widerrufen, aber nie sehen können.

## Wie verhält sie sich auf dem Smartphone und mit der Tastatur?

Auf dem Smartphone wechselt sie zu Karten und Bottom Sheets, und mit der Tastatur lässt sie sich komplett bedienen. Unter 768px wird jeder Key zur Karte, das Zeilenmenü öffnet sich als Bottom Sheet, und der Anlege-Dialog ist ein Bottom Sheet mit Buttons über die volle Breite. Beim Öffnen des Dialogs steht der Cursor im Feld Name, Enter sendet ab, und das Feld mit dem Secret bekommt den Fokus, bereits markiert. Copy oder Cmd+C ist also nur einen Schritt entfernt. Schließt sich der Dialog, kehrt der Fokus zum Menü-Button der Zeile oder zu Create key zurück. Fehlende Angaben stehen direkt am Feld, nicht nur in einem Toast. An solchen Details zeigt sich, ob ein API Keys Page Design funktioniert oder nur im Screenshot gut aussieht.

## Mit welchem React API Key Manager solltest du starten?

Starte mit dem Block von Wingo, wenn du den ganzen Lebenszyklus eines Keys an deine Handler anbinden willst, und mit dem Block von shadcn.io, wenn deine Scopes ein Raster aus Ressourcen und Zugriffsstufen sind. Beide kosten Geld:

| Option | Umfang (Stand November 2026) | Preis |
|---|---|---|
| [shadcn.io „Settings API Keys“](https://www.shadcn.io/blocks/radix/settings-api-keys) | Key-Tabelle, Zugriff None / Read / Write pro Ressource, ein Request-Tester, Karten auf dem Smartphone. Die einmalige Anzeige ist ein eigener Block; die Seite nennt weder Widerrufen noch Rotieren noch Ablauf | Teil von shadcn.io Pro |
| [Wingo UI API Keys Page](https://wingo-ui.com/components/api-keys-page) | Anlegen mit Scopes und Ablauf, einmalige Anzeige, Kopieren, Rotieren, Umbenennen, Widerrufen, Erneuern, Key-Limit, Ablaufwarnungen, Smartphone-Layout | Pro, ab $8 im Monat ([Preise](https://wingo-ui.com/de/pricing)) |

Der Block von shadcn.io passt besser, wenn du seinen Tester willst, mit dem man einen Request direkt ausprobiert. Den hat der Wingo-Block nicht. Weitere Screens wie diesen findest du in der Kategorie [Praxis: Screens und Apps](https://wingo-ui.com/de/blog/category/build) oder im Guide zur [Role Management UI](https://wingo-ui.com/de/blog/role-management-ui), der auf einer Team-Einstellungsseite gut zu den Keys passt. Ereignisse rund um Keys (angelegt, rotiert, widerrufen) gehören außerdem in eine [Audit Log UI](https://wingo-ui.com/de/blog/audit-log-ui), die zeigt, wer welchen Key wann geändert hat.

## Nächster Schritt

Installier den Block mit `npx wingo-ui@latest add api-keys-page`, häng seine vier Handler an deine Server Actions und behalte den Hash auf dem Server. Der Copy Button, den er nutzt, ist mit einem kostenlosen Konto frei verfügbar; die API Keys Page selbst gehört zu Pro.

## Komponenten in diesem Artikel

- [API Keys Page](https://wingo-ui.com/components/api-keys-page) (Pro): The developer settings screen for API keys: list, create with scopes and expiry, reveal the secret once, copy, roll, rename and revoke. Installation: `npx wingo-ui@latest add api-keys-page`
- [Copy Button](https://wingo-ui.com/components/copy-button) (Free): A React copy to clipboard button for IBANs, tax IDs, links and API keys: an icon button with a tooltip, a labelled button and CopyText. Installation: `npx wingo-ui@latest add copy-button`
- [Alert Dialog](https://wingo-ui.com/components/alert-dialog) (Pro): A React alert dialog for confirmations: an async confirm that loads, fails inline and shakes, plus an await confirm() API. Installation: `npx wingo-ui@latest add alert-dialog`
- [Data Table](https://wingo-ui.com/components/data-table) (Pro): A React data table on TanStack Table: search, filters, sorting, bulk actions, pinning, resizing, virtualization and cards on phones. Installation: `npx wingo-ui@latest add data-table`

## Häufige Fragen

### Sollten Nutzer einen API-Key nach dem Anlegen noch einmal sehen können?

Bei Server-Keys nicht. Zeig das Secret einmal, speicher nur einen Hash und biete Rotieren an, wenn jemand den Key verliert. Abrufbare Keys brauchen Verschlüsselung im Ruhezustand und einen Weg zum Entschlüsseln, also mehr Code, den du schützen musst, für wenig Gewinn.

### Wie speichere ich API-Keys in der Datenbank?

Speicher einen SHA-256-Hash des ganzen Keys mit Unique-Index und dazu ein kurzes Präfix für die Anzeige. Eingehende Keys findest du, indem du sie hashst. Ein zufälliger Key mit 190 Bit Entropie braucht keinen langsamen Passwort-Hash.

### Was ist der Unterschied zwischen Rotieren und Widerrufen eines API-Keys?

Widerrufen beendet den Key endgültig. Rotieren behält Namen, Scopes und Historie des Keys, stellt aber ein neues Secret aus. Die Nutzer ändern also eine Umgebungsvariable, statt den Key neu anzulegen.

### Warum haben API-Keys ein Präfix wie sk_live_ oder ghp_?

Ein Präfix verrät Menschen und Secret-Scannern, was der String ist und zu welcher Umgebung er gehört. GitHub hat seinen Tokens im April 2021 Präfixe und eine Prüfsumme gegeben, damit sich geleakte Tokens mit wenigen Fehlalarmen erkennen lassen.

### Wie sollte eine API-Keys-Seite auf dem Smartphone funktionieren?

Mach aus der Tabelle eine Karte pro Key, öffne das Zeilenmenü als Bottom Sheet und zeig die Dialoge zum Anlegen und für die Anzeige des Secrets als Bottom Sheets mit Buttons über die volle Breite. Der Copy-Button zählt dort am meisten, denn ein Secret mit 45 Zeichen per Hand auf einem Touchscreen zu markieren geht leicht schief.

---

Quelle: https://wingo-ui.com/de/blog/api-key-management-ui
