HeoLab
ToolsBlogAboutContact
HeoLab

Free developer tools with AI enhancement. Built for developers who ship.

Tools

  • JSON Formatter
  • JWT Decoder
  • Base64 Encoder
  • Timestamp Converter
  • Regex Tester
  • All Tools →

Resources

  • Blog
  • What is JSON?
  • JWT Deep Dive
  • Base64 Explained

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 HeoLab. All rights reserved.

Tools work in your browser. Zero data retention.

HomeBlogAPI Key Security: Design, Storage, and Rotation Best Practices
Table of Contents▾
  • What Makes a Good API Key
  • Entropy Requirements
  • Use a Recognizable Prefix
  • Never Store API Keys in Plain Text
  • Environment Variables: The Right Way
  • Never hardcode keys
  • Local development
  • .env.local (never commit this file)
  • Production secrets
  • Handling Leaked Keys
  • Set up GitHub secret scanning
  • Key Scoping and Rate Limiting
  • Generate Secure API Keys
security#api-keys#security#authentication

API Key Security: Design, Storage, and Rotation Best Practices

How to design secure API keys, store them safely in your applications, handle rotation without downtime, and detect leaked keys before they cause damage.

Trong Ngo
February 28, 2026
4 min read

API keys are everywhere — OpenAI, Stripe, GitHub, Google Maps, AWS. They're simple to use but easy to misuse. A leaked API key can result in thousands in unauthorized charges, data breaches, or account takeovers. This guide covers the full lifecycle: generation, storage, usage, and rotation.

What Makes a Good API Key

A well-designed API key has three properties:

  1. Sufficient entropy — hard to guess or brute-force
  2. Identifiable format — easy to spot in logs and code
  3. Verifiable structure — optionally embeds a checksum for quick validation

Entropy Requirements

An API key should have at least 128 bits of entropy, ideally 256 bits:

const crypto = require('crypto');

// 32 random bytes = 256 bits of entropy
const rawKey = crypto.randomBytes(32);

// Base62 encoding (URL-safe, no confusing chars)
const BASE62 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
// Or simpler: hex encoding (48 chars, still 192 bits)
const hexKey = rawKey.toString('hex'); // e.g., 'a3f2b1...'

Use a Recognizable Prefix

Prefixes like sk_live_, pk_test_, or heo_ make keys identifiable in logs and prevent accidental cross-environment usage:

function generateApiKey(prefix = 'heo') {
  const secret = crypto.randomBytes(32).toString('hex');
  return `${prefix}_${secret}`;
}

// e.g., 'heo_a3f2b1c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1'

GitHub uses ghp_ (personal access tokens), ghs_ (server tokens), and gha_ (Actions tokens). Stripe uses sk_live_ and sk_test_. This approach also enables GitHub's secret scanning to automatically detect leaked keys.

Never Store API Keys in Plain Text

Like passwords, API keys should be hashed before storage. This way, even if your database is breached, attackers get hashes, not working keys:

const crypto = require('crypto');

// Hash the key for storage
function hashApiKey(key) {
  return crypto.createHash('sha256').update(key).digest('hex');
}

// On creation: store the hash, return the key once to the user
async function createApiKey(userId) {
  const key = generateApiKey();
  const keyHash = hashApiKey(key);

  await db.apiKeys.insert({
    user_id: userId,
    key_hash: keyHash,
    key_preview: key.slice(0, 8) + '...' + key.slice(-4), // for UI display
    created_at: new Date(),
  });

  return key; // Show this ONCE — never stored
}

// On verification: hash the incoming key and compare
async function verifyApiKey(key) {
  const keyHash = hashApiKey(key);
  return db.apiKeys.findOne({ key_hash: keyHash, revoked: false });
}

SHA-256 is fine here (unlike passwords) because API keys already have high entropy — rainbow tables aren't viable against 256-bit random values.

Environment Variables: The Right Way

Never hardcode keys

// ❌ Never do this
const openai = new OpenAI({ apiKey: 'sk-abc123...' });

// ✅ Always use environment variables
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

Local development

# .env.local (never commit this file)
OPENAI_API_KEY=sk-...
STRIPE_SECRET_KEY=sk_test_...

Add .env.local to .gitignore. Commit a .env.example with placeholder values.

Production secrets

Use your platform's secret management — never plain environment variables in a docker-compose.yml or CI config file:

  • Vercel: Dashboard → Settings → Environment Variables
  • AWS: AWS Secrets Manager or Parameter Store
  • GitHub Actions: Repository → Settings → Secrets and variables

Handling Leaked Keys

If you suspect a key is leaked:

  1. Revoke immediately — don't wait to investigate
  2. Check usage logs — identify what was accessed
  3. Issue a new key — rotate before restoring service
  4. Audit your codebase — use git log -S 'sk_' to find historical commits containing keys

Set up GitHub secret scanning

If you use prefixed API keys (like heo_), you can register a pattern with GitHub's Secret Scanning Partner Program. GitHub will automatically alert you when a key with your pattern appears in a public repository.

Key Scoping and Rate Limiting

Don't make keys omnipotent. Scope them to minimum required permissions:

-- API keys table with permission scopes
CREATE TABLE api_keys (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES users(id),
  key_hash TEXT UNIQUE NOT NULL,
  key_preview TEXT NOT NULL,
  scopes TEXT[] DEFAULT '{}', -- e.g., '{read:data,write:data}'
  rate_limit INT DEFAULT 1000, -- requests per hour
  expires_at TIMESTAMPTZ,
  revoked_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

Generate Secure API Keys

Use HeoLab's API Key Generator to create cryptographically secure API keys with custom prefixes, lengths, and character sets — perfect for testing your key generation logic or generating development keys instantly.

Try These Tools

API Key Generator

Generate cryptographically secure API keys in hex, Base64url, and prefixed formats. 100% client-side.

Related Articles

Understanding CORS: Why Browsers Block Your Requests and How to Fix It

4 min read

HMAC Authentication: Signing API Requests the Right Way

4 min read

Unit Testing Best Practices in JavaScript

3 min read

Back to Blog

Table of Contents

  • What Makes a Good API Key
  • Entropy Requirements
  • Use a Recognizable Prefix
  • Never Store API Keys in Plain Text
  • Environment Variables: The Right Way
  • Never hardcode keys
  • Local development
  • .env.local (never commit this file)
  • Production secrets
  • Handling Leaked Keys
  • Set up GitHub secret scanning
  • Key Scoping and Rate Limiting
  • Generate Secure API Keys

Related Articles

Understanding CORS: Why Browsers Block Your Requests and How to Fix It

4 min read

HMAC Authentication: Signing API Requests the Right Way

4 min read

Unit Testing Best Practices in JavaScript

3 min read