Authentication answers the question "Who are you?". A client proves its identity to the server, for example with credentials or a token. Authorization answers the question "What are you allowed to do?". It decides whether the proven identity may access a particular resource or perform an action. The two are separate: you can be correctly authenticated and still have no permission.
HTTP defines a general framework for this (RFC 7235). The typical flow: the server responds to a request without credentials with 401 Unauthorized and a WWW-Authenticate header naming the expected scheme. The client then repeats the request with the credentials in the Authorization header.
Key status codes per MDN:
401 Unauthorized: not (validly) authenticated; the client may retry.403 Forbidden: validly authenticated, but not authorized; retrying is pointless.407withProxy-AuthenticateandProxy-Authorization: the same principle for proxies.
Common mechanisms at a glance:
- API keys: a static key per client, often in a header. Simple, but usually only coarse identification.
- HTTP Basic: username and password are sent in the
Authorizationheader. The data is only encoded (Base64), not encrypted, so it must only be used over HTTPS/TLS. - Bearer token / JWT: a bearer token is sent using the
Bearerscheme (RFC 6750). JWT (RFC 7519) is a widely used, self-contained token format. - OAuth 2.0 (RFC 6749): industry standard for delegated authorization. An application obtains an access token from the user via defined flows (e.g. Authorization Code with PKCE, Client Credentials) without ever knowing the user's password. OAuth 2.0 governs access rights, not primarily the end user's identity verification.
- Sessions / cookies: after a login, the server stores a session and the browser automatically sends the session ID via cookie; typical for classic web applications.
The header line always sits in the request and follows the pattern Authorization: , i.e. something like Authorization: Basic ... or Authorization: Bearer .... Browsers use UTF-8 encoding for Basic credentials. Note: the Authorization header is stripped on cross-origin redirects.
A practical note: the most consequential API gaps lie less in authentication than in authorization. Being authenticated doesn't automatically mean you're allowed to do everything. Missing or broken permission checks per object and per action allow users to read or change other people's data. Check permissions server-side on every access, therefore.
GET /api/orders/42 HTTP/1.1
Host: api.example.com
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
GET /api/orders/42 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJhbGciOiJIUzI1Ni...
HTTP/1.1 403 ForbiddenFlow: first 401 (not authenticated), then a request with a bearer token; 403 shows missing authorization despite a valid identity.
Best practices for API authentication
Authentication endpoints are, per OWASP API Security Top 10 (API2:2023 Broken Authentication), an easy target because they're reachable by anyone. Whoever compromises them takes over other people's accounts. The following practices summarize the documented recommendations from OWASP and oauth.net.
Transport and token handling
- Transmit credentials and passwords exclusively over TLS/HTTPS, never over unencrypted channels.
- Never send tokens and passwords in the URL. OWASP explicitly rates sending sensitive auth details in the URL as vulnerable; accordingly, they don't belong in logs either.
- Use short-lived access tokens and renew them via refresh tokens. Per oauth.net, the refresh token exists for exactly this purpose: it lets the authorization server use short token lifetimes without re-involving the user on every expiry.
- Secure refresh tokens for public clients. A stolen refresh token from a public client allows undetected abuse; binding it to the client instance via DPoP counters this. Sender-constrained tokens require proof of possession of a private key and so are not usable on their own.
Server-side token validation
- Always check tokens for authenticity. OWASP explicitly names missing verification as a vulnerability.
- Reject unsigned or weakly signed JWTs, especially
{"alg":"none"}. - Check the expiration date of every JWT; reject expired tokens.
- Per oauth.net, ID tokens must not be used for requests to the resource server, and the client must not interpret the content of the access token. This implies a server-side check against the expected audience.
Protection against automated attacks
- Rate limiting, account lockout and CAPTCHA against brute force and credential stuffing. Note: OWASP shows how attackers use GraphQL query batching to bypass a per-request limit; the limit must therefore also cover batch operations.
- Treat "forgot / reset password" endpoints like login endpoints (same brute-force and rate-limit protection).
- Deploy multi-factor authentication where possible; disallow weak passwords.
- Tie sensitive operations such as changing email or password to a fresh confirmation of the current password, otherwise account takeover via a stolen token is possible.
Architecture and principles
- Don't invent authentication, token generation and password storage yourself; use established standards instead (OAuth 2.0/2.1, OIDC, RFCs). OWASP also stresses: OAuth and API keys are not authentication in themselves.
- Principle of least privilege: per oauth.net, a refresh token must not grant access beyond the scope of the original grant.
- Avoid weak or predictable tokens and weak keys; rotate keys regularly. In microservice environments, no service should be reachable without authentication.
- Know all possible auth flows (web, mobile, deep links, one-click) and check them centrally and consistently.
POST /token grant_type=refresh_token&refresh_token=...&client_id=...
GET /api/orders
Authorization: Bearer <access_token>=> { "access_token": "...", "expires_in": 900, "token_type": "Bearer" }Renew a short-lived access token via a refresh token, send the token in the Authorization header (not in the URL)
Authentication methods: which one to use, and when?
The choice depends on who is proving identity to whom (human or machine, browser or service) and whether the server should hold state. Ground rule for all methods: transmit credentials and tokens only over TLS (OWASP, MDN).
API keys identify an application or service, not an individual user. They suit server-to-server calls, rate limiting and per-client billing.
- Good for: machine identification, public/semi-public APIs, quota control.
- Not good for: real user authentication, fine-grained authorization; a key counts as a bearer secret and is fully abusable if leaked.
- Note: store server-side, rotate regularly, never keep in the frontend or repo.
HTTP Basic sends username and password base64-encoded in the Authorization header (RFC 7617, framework RFC 7235). Simple, but the secret travels with every request.
- Good for: internal tools, machine calls, quick tests, always only over HTTPS/TLS.
- Not good for: public end-user logins; base64 is not encryption, completely insecure without TLS (MDN).
Session cookies are the classic model for server-side browser apps: after login the server holds the session, the browser automatically sends the cookie.
- Good for: server-rendered web apps, simple immediate invalidation (logout) via server state.
- Not good for: stateless APIs across many services, cross-domain or native-app scenarios without a browser.
- Note: set cookies with
HttpOnly,Secure,SameSiteand provide CSRF protection.
Bearer token / JWT enable stateless, well-scaling authentication; the token is sent in the Authorization: Bearer header (RFC 6750, JWT RFC 7519).
- Good for: APIs, SPAs and service-to-service communication without a shared session store.
- Not good for: when immediate, central revocation is critical; a stolen bearer token is valid until it expires. Countermeasures: short lifetime, refresh token, revocation/introspection (RFC 7009, RFC 7662).
OAuth 2.0 / OIDC is the industry standard for delegated access: an app receives limited access on the user's behalf without ever knowing their password (oauth.net, RFC 6749). OpenID Connect adds the identity and login layer (ID token) on top of OAuth.
- Good for: third-party access, single sign-on, user login via identity provider, separate scopes per app.
- Not good for: overkill for simple internal service calls; the wrong flow is a risk.
- Note: for web/SPA and native apps use the authorization code flow with
PKCE; implicit and password grant are considered deprecated (oauth.net, RFC 9700).
mTLS (Mutual TLS) authenticates both sides via X.509 certificates at the transport layer (RFC 8705).
- Good for: mutual service-to-service authentication, zero-trust networks, high-security OAuth variants (token binding to a client certificate).
- Not good for: typical end-user browser logins; distributing and rotating certificates is operationally heavy.
Rule of thumb: machine-to-machine: API key or mTLS resp. client credentials flow. Browser app with server: session cookies. Stateless API/SPA: bearer/JWT. Third-party user login or delegated access: OAuth 2.0 / OIDC.
// Bearer token in the HTTP header (RFC 6750) GET /api/orders HTTP/1.1 Host: api.example.com Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... // HTTP Basic (only over TLS!) - RFC 7235 Authorization: Basic dXNlcjpwYXNzd29yZA==
Typical Authorization header by method; use Basic only over HTTPS.
| Method | Good for | Less suited for |
|---|---|---|
| API keys | service-to-service, app identification, rate limiting | real user authentication, fine-grained rights |
| HTTP Basic | internal tools, quick tests (only over TLS) | public end-user logins |
| Session cookies | server-side browser apps, immediate logout | stateless APIs across many services, native apps |
| Bearer token / JWT | stateless APIs, SPAs, service-to-service | when immediate revocation is required (token is valid until expiry) |
| OAuth 2.0 / OIDC | third-party delegated access, user login (SSO) | simple internal calls (overhead) |
| mTLS | mutual service authentication, zero trust | browser end users (certificate management) |
Sources
- Authorization header - HTTP MDN Web Docs
- HTTP authentication MDN Web Docs
- OAuth 2.0 oauth.net (IETF OAuth Working Group)
- Authentication Cheat Sheet OWASP Cheat Sheet Series
- API2:2023 Broken Authentication OWASP API Security Top 10
- OAuth 2.0 Access Tokens oauth.net
- OAuth 2.0 Refresh Tokens oauth.net
- OAuth 2.0 Grant Types oauth.net