Skip to content

API Keys vs OAuth

1. Decision

Choose API Keys for simple machine-to-machine integration, developer API identification, and project-level rate limiting where no human user authentication is involved; choose OAuth 2.0 / OIDC for delegated user-scoped authorization, third-party app integration, user identity verification, and fine-grained access control.


2. 30-Second Answer

API Keys are long-lived, static secret strings assigned to a developer project or application. They identify the calling application (Project Identification) to the API gateway, enabling basic rate limiting, usage billing, and project-level tracking. However, API Keys do NOT authenticate individual human users, lack fine-grained scoped permissions, and carry high security risks if leaked (no native expiration). OAuth 2.0 is a delegated authorization framework that issues short-lived, scoped Access Tokens tied to specific users and scopes. It authenticates who the user is and defines what specific actions the app is allowed to perform, offering robust security via token expiration, refresh tokens, and instant user access revocation.


3. Decision Matrix

Option Best For Avoid When Latency Scalability Consistency Operational Complexity
API Keys Server-to-server developer APIs (Stripe, OpenAI, SendGrid API keys), public developer usage tracking, project rate-limiting End-user authentication, delegating user permissions, mobile apps with user logins Ultra-Low (Fast string/hash lookup in Redis or Gateway memory) High (Stateless lookup at API Gateway) Project-level static access Very Low
OAuth 2.0 / OIDC End-user authentication, Single Sign-On (SSO), mobile/web apps accessing user data, third-party integrations Simple server-to-server developer APIs where managing token refresh flows adds useless friction Low (Stateless JWT signature validation or introspect) High (Scalable identity provider architecture) Scoped user-delegated authorization Medium to High

4. Selection Rules

Requirement Best Choice Rationale / Example
Public Developer API Integration (OpenAI / Stripe) API Key Developer generates static API Key sk_live_123 in dashboard to call server APIs
Mobile App Accessing Private User Profile Data OAuth 2.0 / OIDC User logs in via OAuth2 flow; app receives scoped short-lived Access Token
Identify Calling Application for Rate Limiting & Billing API Key Track monthly API usage billing and enforce 1,000 req/min quota per developer project
Delegated Access ("Allow App X to read my Google Calendar") OAuth 2.0 User approves specific OAuth scopes (calendar.readonly) for a third-party application
Secure Hash Storage for API Keys SHA-256 Hashing Store only the SHA-256 hash of API Keys in database (sk_live_... shown once)

5. Tradeoffs

  1. Simplicity & Developer Ergonomics vs Security Granularity
  2. Gain (API Key): Extremely simple; developer includes Authorization: Bearer sk_key in cURL commands.
  3. Lose (API Key): No user context; if leaked, attacker gains full project-level API access until key is manually rolled.
  4. Project Identification vs Delegated User Authorization
  5. Gain (API Key): Identifies the application/organization making the call.
  6. Lose (API Key): Cannot differentiate between different end-users using the application.
  7. Short-Lived Token Lifespan vs Static Credential Maintenance
  8. Gain (OAuth): Access tokens expire in 15-60 minutes; stolen tokens become useless quickly.
  9. Lose (OAuth): Client applications must implement Refresh Token exchange loops.
  10. Fine-Grained Scopes vs All-or-Nothing Access
  11. Gain (OAuth): Scopes restrict client to exact permissions (read:invoices vs write:invoices).
  12. Lose (OAuth): Complex scope evaluation logic at API Gateway / Microservice layer.
  13. Revocation Control
  14. Gain (OAuth): User revokes third-party app access in account settings, invalidating all associated tokens instantly.
  15. Lose (API Key): Revoking an API Key breaks all server integrations using that key.

6. Interview Counter Questions

  1. Why should you NEVER use API Keys for end-user authentication in mobile or Single-Page Web Applications?
  2. How should API Keys be generated, formatted, and stored securely in a database (Stripe-style)?
  3. How does Stripe structure API Keys (pk_test_, sk_live_) and why are prefixes useful?
  4. How do you implement Rate Limiting for API Keys using Redis?
  5. What is the difference between a Client Secret in OAuth 2.0 and an API Key?
  6. How do you handle API Key rotation without breaking production traffic (Dual-Key Support)?
  7. How does an API Gateway validate API Keys at the edge (Cache vs DB)?
  8. What security risks exist if an API Key is checked into a public GitHub repository?
  9. When would you use BOTH an API Key AND an OAuth Token in the same API request?
  10. How do you prevent Timing Attacks during API Key verification string comparisons?

7. Gold Standard Answers

  1. API Keys embedded in mobile apps or SPA JS bundles can be easily extracted via reverse-engineering or dev tools. Since API Keys lack user context and short-lived expirations, attackers gain permanent access.
  2. Generate cryptographically secure random bytes (e.g. 32 bytes CSPRNG), format with prefix (sk_live_...), display to user once, and store ONLY its SHA-256 hash in the database.
  3. Prefixes (pk_ = publishable, sk_ = secret, test_/live_ = environment) allow automated GitHub secret scanners to detect committed keys instantly and prevent wrong environment usage.
  4. Store API Key hash in Redis. Incoming request extracts key \(\rightarrow\) hashes key \(\rightarrow\) executes Redis sliding window counter Lua script mapped to rate:apikey:<hash>.
  5. API Key identifies a project to an API gateway. Client Secret is a machine credential used strictly during OAuth2 token exchanges to prove client app identity to the Authorization Server.
  6. Support Dual-Key Rolling: Allow projects to maintain an active_key and a secondary_key concurrently. Developers deploy the new key, verify traffic, and then revoke the old key.
  7. Gateway caches hashed API Keys in local memory (Caffeine) or Redis cluster with short TTLs (1-5 mins), verifying key validity and quotas in sub-millisecond time without querying the primary database.
  8. Automated bot scrapers clone public repos instantly. If a secret key is committed, bots execute unauthorized operations, spam compute resources, or exfiltrate data within seconds.
  9. Combined pattern: API Key identifies the developer organization for billing/rate-limiting, while OAuth Access Token authorizes the specific logged-in user and their scopes.
  10. Standard string comparison (if (keyA == keyB)) leaks execution time based on matching character counts. Use Constant-Time String Comparison functions (e.g., crypto.timingSafeEqual) to prevent timing side-channel attacks.

8. Common Mistakes

  • Storing raw, un-hashed API Keys in plain text in database tables.
  • Embedding secret API Keys (sk_live_...) inside client-side JavaScript or mobile app binaries.
  • Using API Keys as a substitute for user authentication and user session management.
  • Hardcoding API Keys in source code instead of retrieving them from environment variables or Secrets Managers.
  • Using standard == string equality operators to verify API Keys, exposing the system to Timing Side-Channel attacks.

9. Keywords

API Key, OAuth 2.0, Secret Key, Publishable Key, CSPRNG, SHA-256 Hashing, Secret Scanning, Constant-Time Comparison, Timing Attack, Dual-Key Rolling, Scopes, Project Identification, User Authorization.


10. Cheat Sheet

  • Core Difference: API Key = Identifies calling Application/Project (Billing, Rate Limits); OAuth 2.0 = Authorizes delegated User Actions & Scopes.
  • Storage Rule: Never store plain-text API Keys! Store SHA-256 Hashes of API Keys in the DB. Show full key to developer ONLY ONCE upon creation.
  • Key Prefixing: Prefix keys (sk_live_, pk_test_) to enable automated GitHub secret scanning and environment validation.
  • Browser/Mobile Safety: NEVER embed secret API Keys (sk_live_) in frontend JS or mobile apps. Use public keys (pk_) or OAuth2 PKCE.
  • Rotation: Support Dual-Key rolling (active_key + secondary_key) for zero-downtime key rotation.
  • String Comparison: Always use Constant-Time Comparison (crypto.timingSafeEqual) to prevent timing side-channel attacks.

11. Related Decisions