Agent Wranglers

API security Required

Store API keys as hashes

Show each API key once, store only its hash, and let clients hold two keys at a time so they can rotate.

How to do it

Make keys from at least 32 random bytes with a short prefix, such as exs_live_, so secret scanners can find leaked ones. Store a SHA-256 hash and the last four characters. Look keys up by hash, never by plain text. Let each key carry scopes, an owner and an expiry. Allow revoking one key without touching the other.

Example

import { createHash, randomBytes } from 'node:crypto'

const KEY_PREFIX = 'exs_live_'
const hashKey = key => createHash('sha256').update(key).digest('hex')

function issueApiKey() {
  const key = KEY_PREFIX + randomBytes(32).toString('base64url')
  return { shownOnce: key, stored: { hash: hashKey(key), lastFour: key.slice(-4) } }
}
import hashlib, secrets

KEY_PREFIX = "exs_live_"

def hash_key(key: str) -> str:
    return hashlib.sha256(key.encode()).hexdigest()

def issue_api_key() -> dict:
    key = KEY_PREFIX + secrets.token_urlsafe(32)
    return {"shown_once": key, "stored": {"hash": hash_key(key), "last_four": key[-4:]}}

How to check

Search the database for any stored key value. Only hashes appear. A revoked key gets 401 on the next call.

For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers api design playbook: https://agentwranglers.se/playbook/api-design/api-security/api-keys.