By AndyPublished
JWT vs API Key: Differences and When to Use Each
Use an API key when a known customer’s server calls your API and you mainly need to know which account to bill and rate-limit. Use JWTs when you need to know which user is acting, what they may do, and when many services must check that cheaply. Many production APIs use both: a key to obtain a token, and the token for the actual calls.
JSON Web Token vs API Key: The Core Difference
The difference is where the meaning lives. An API key such as sk_live_3Zp2cvI1qc2n6duUKf4E is a reference. On its own it says nothing; the server has to find the matching record to learn which account it belongs to, what it may do, and whether it is still enabled. A JWT is a value. Its payload states the subject, issuer, audience, expiry and scopes, and the signature proves those statements came from a key the server trusts. The header, payload and signature guide explains how that works.
| Aspect | API key | JWT |
|---|---|---|
| What it is | A random secret string, meaningless on its own | A signed JSON document of claims (RFC 7519) |
| Identifies | Usually an application, project or customer account | Usually a user or a service, plus scopes and audience |
| Lifetime | Months or years; valid until someone revokes it | Minutes to hours, enforced by the exp claim |
| Validation | Database or cache lookup on every request | Signature check with a key already in memory |
| Revocation | Immediate: delete or disable the record | Hard before exp without a deny-list or introspection |
| Carries data | No; everything is looked up server-side | Yes; claims travel with the token and can be read by the holder |
| Standard | None; each vendor picks a format and header | RFC 7519, with JWS (RFC 7515) for signing |
| Issued by | A developer dashboard or admin API | A login endpoint or an OAuth authorisation server |
| Damage if leaked | High: works until noticed and revoked | Limited to the remaining lifetime of the token |
Neither is encrypted in transit by itself. Both must only be sent over HTTPS, and both are bearer credentials: whoever holds one can use it. See JWT vs bearer token for what that means and how proof-of-possession changes it.
JWT or API Key: Which Should You Use?
Use an API key when
- ·The caller is a backend server owned by a customer or partner, not a browser or mobile app.
- ·You need to identify an account for billing, quotas and rate limits, and there is no end user in the request.
- ·You want the lowest possible integration effort: one header, no token endpoint, no expiry handling.
- ·Immediate revocation matters more than avoiding a lookup per request (and the lookup can be cached for a few seconds).
Use a JWT when
- ·Requests act on behalf of a logged-in user, and each API needs the user ID, roles or scopes.
- ·Several services verify the same credential and you do not want each to query a central database.
- ·The credential lives somewhere it can leak, such as a browser or a mobile device, so a short lifetime limits the damage.
- ·You already use an identity provider or OAuth server that issues JWT access tokens.
Using a JWT as an API Key
Some platforms hand out long-lived JWTs and call them API keys. This gives the key a readable structure (tenant ID, role, issue date) and lets gateways check it without a database. It also combines the downsides of both approaches:
- ·No real expiry: a key-style JWT often has an
expyears away, or none at all, so the main safety property of a JWT is gone. - ·No cheap revocation: if the gateway never checks a database, the only way to kill one leaked key is to rotate the signing key, which invalidates every other key signed with it.
- ·Readable payload: anyone who finds the key can decode it and learn the tenant and role names.
If you issue JWT-shaped keys, keep a jti in each and check it against a revocation list, even if that list is cached. The options are covered in JWT logout and revocation. You can inspect such a key with the jwtdecode.app decoder, which decodes in the browser, to see exactly what it discloses.
Using an API Key and a JWT Together
The most robust pattern uses each for what it is good at. The client holds a long-lived API key but only presents it to one endpoint, which returns a short-lived JWT. Every other call uses the JWT. The key is exposed on the wire far less often, the JWT limits the damage of any leak to minutes, and your APIs validate tokens statelessly. This is essentially the OAuth client credentials grant, and if you already run an OAuth server you should use that grant rather than inventing your own.
A minimal exchange endpoint in Node.js with the jose library. Keys are stored as SHA-256 hashes, so a database leak does not reveal usable keys:
import { createHash } from 'node:crypto';
import { SignJWT } from 'jose';
const secret = new TextEncoder().encode(process.env.JWT_SECRET); // 32+ random bytes
// keysByHash: Map of sha256(key) -> { clientId, scopes }, loaded from your database
function lookupApiKey(presented) {
const hash = createHash('sha256').update(presented).digest('hex');
return keysByHash.get(hash) ?? null;
}
export async function exchangeApiKeyForToken(apiKey) {
const client = lookupApiKey(apiKey);
if (!client) return null; // respond 401
return new SignJWT({ scope: client.scopes.join(' ') })
.setProtectedHeader({ alg: 'HS256' })
.setSubject(client.clientId)
.setIssuer('https://api.example.com')
.setAudience('https://api.example.com')
.setIssuedAt()
.setExpirationTime('15m')
.sign(secret);
}Downstream services then verify with jwtVerify(token, secret, { issuer, audience, algorithms: ['HS256'] }). If services other than the issuer need to verify, switch to an asymmetric algorithm so they only hold a public key; HS256 vs RS256 covers that choice.
Handling API Keys Safely
API keys have no standard, so the safety properties depend on how you build them. Generating and storing them correctly in Python:
import hashlib, hmac, secrets
def new_api_key():
key = "sk_live_" + secrets.token_urlsafe(32) # show to the user once
digest = hashlib.sha256(key.encode()).hexdigest() # store only this
return key, digest
def check_api_key(presented, stored_digest):
digest = hashlib.sha256(presented.encode()).hexdigest()
return hmac.compare_digest(digest, stored_digest)- ·High entropy: at least 128 bits from a CSPRNG. Because the key is random, a fast hash such as SHA-256 is enough for storage; slow password hashes are not needed.
- ·Recognisable prefix: a prefix such as
sk_live_lets secret scanners and your own log filters spot leaked keys. - ·Send in a header, never in the query string, where it ends up in access logs, browser history and proxies.
- ·Scope and rotate: let customers create several keys with narrow permissions, and support two active keys at once so rotation has no downtime.
- ·Record last use: unused keys should be flagged and disabled.
Is an API Key or a JWT More Secure?
Neither is secure or insecure by nature; they fail in different ways.
- ·API keys fail by leaking and living forever. Keys get committed to repositories, pasted into CI logs and shared in chat. Because they rarely expire, a key leaked a year ago may still work today. The mitigations are operational: secret scanning, per-environment keys, rotation, and alerting on unusual use.
- ·JWTs fail through validation mistakes. A leaked JWT expires quickly, but a verifier that accepts
alg: none, skips the audience check, or trusts the algorithm in the header can be tricked into accepting forged tokens. The mitigations are in code: a maintained library, a pinned algorithm list, and checks oniss,audandexp. See JWT attacks and vulnerabilities. - ·Both are bearer credentials. Whoever holds one can use it, so both need HTTPS, both must stay out of URLs and logs, and neither proves the sender is the rightful owner unless you add proof of possession.
In practice, the better question is how much damage a single leaked credential can do. A 15-minute JWT with one narrow scope limits that far more than a permanent key with full account access. A key limited to one IP range and read-only permissions can be safer than a day-long JWT with admin rights. Lifetime and scope matter more than format.
JWT vs OAuth2 vs API Key
These three are often listed as alternatives, but OAuth 2.0 is a framework for issuing tokens, and the tokens it issues are frequently JWTs. The honest comparison is between approaches:
| Approach | Best for | Main weakness |
|---|---|---|
| API key | Server-to-server calls by a known customer; metering and rate limits | Long-lived, no user context, easy to leak into code and logs |
| JWT | Stateless auth for users and services across many APIs | Hard to revoke early; payload readable by anyone who holds it |
| OAuth 2.0 | Delegated access, third-party apps, SSO, standard machine flows | More moving parts; needs an authorisation server |
A typical public API ends up with all three: API keys for simple server integrations, OAuth for third-party apps acting for users, and JWT access tokens as the format those OAuth flows produce. The relationship between the last two is explained in JWT vs OAuth.
Summary
- ·An API key is an opaque, long-lived secret identifying an application; a JWT is a short-lived, signed statement about a user or service.
- ·API keys revoke instantly but need a lookup per request; JWTs validate locally but are hard to revoke before they expire.
- ·Choose API keys for server-to-server calls by known customers, JWTs for user context and multi-service validation.
- ·Avoid long-lived JWTs used as API keys unless you also check a revocation list.
- ·Combining them, a key exchanged for a 15-minute JWT, gives you instant revocation of the key and cheap validation of every call.