How to Build API Key Authentication

API key auth gates an endpoint behind a secret key. The rules that make it secure: generate a strong random key, store only its hash, show the raw value once, and verify the X-API-Key header on each request. Here's how.

Security Engineerpythonapi-keysauthentication

How API key auth works

Each client gets a secret key. They send it on every request (an X-API-Key header is the convention), and your middleware checks it before the handler runs. The security is all in how you generate and store the key.

Generate a strong key, store only its hash

Treat keys like passwords - never store the raw value. Generate with a CSPRNG and persist the hash:

import secrets, hashlib

def new_key():
    raw = "sk_" + secrets.token_urlsafe(32)       # strong, unguessable
    key_hash = hashlib.sha256(raw.encode()).hexdigest()
    db.execute("INSERT INTO api_keys (key_hash, created_at) VALUES (?, ?)",
               (key_hash, time.time()))
    return raw          # return the RAW key ONCE - it's never recoverable after this

Show the raw key to the user exactly once on creation. After that you only ever have the hash, so a database leak doesn't expose usable keys.

Verify on every request

Hash the incoming key and look up the hash - constant work, no raw keys in the DB:

from functools import wraps
from flask import request, jsonify

def require_api_key(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        raw = request.headers.get("X-API-Key", "")
        key_hash = hashlib.sha256(raw.encode()).hexdigest()
        row = db.execute("SELECT id FROM api_keys WHERE key_hash = ? AND revoked = 0",
                         (key_hash,)).fetchone()
        if not row:
            return jsonify({"error": "invalid api key"}), 401
        return f(*args, **kwargs)
    return wrapper

@app.get("/api/data")
@require_api_key
def data(): ...

The rules that make it secure

Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.

Try it in a workspace →

What you'll practice

FAQ

How should I store API keys?

Store only a hash of the key, never the raw value - generate the key with a CSPRNG, hash it (SHA-256 is enough for a high-entropy random key), and show the raw key to the user only once at creation.

Where should the API key go in a request?

Conventionally an X-API-Key header (or Authorization: Bearer <key>). Verify it in middleware before the handler runs and return 401 if it's missing or invalid. Always over HTTPS.

Do I need bcrypt for API keys like for passwords?

No - bcrypt's slowness defends weak human passwords against brute force. A randomly generated 256-bit key has too much entropy to brute force, so a fast SHA-256 hash is appropriate and lets you look it up efficiently.

What is the difference between API key and basic authentication?

Basic auth sends a username and password (base64-encoded) on every request; an API key is a single opaque token sent in a header like X-API-Key. API keys are easier to issue, scope, and revoke per client without exposing user credentials.

Keep learning

Close a SQL Injection in a Search EndpointSecurity projectNeutralize a Stored XSS in CommentsSecurity projectRemove Hardcoded Credentials From Source CodeSecurity projectSecurity roadmapStep by step to hiredSecurity interview questionsSTAR answersAll Security projectsProjects hub

Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.

Open the workspace →