Separate authentication from authorization
Authentication answers “who are you?”. Authorization answers “what are you allowed to do?”. Mixing them creates security bugs and confusing API behavior.
A robust REST API authenticates the caller first, then checks authorization on every resource and action.
API keys: simple but limited
API keys are easy to implement and good for server-to-server or internal use. They are coarse: they usually represent an application, not a user.
If you need user-level permissions, auditability, or revocation, API keys alone are insufficient.
OAuth: the standard for user data
OAuth allows delegated access without sharing passwords. It is the standard for public APIs and third-party integrations.
The setup is more complex, but it provides a security model that scales across apps and users.
JWTs: portable but sensitive
JSON Web Tokens are self-contained and work well for stateless APIs. They remove the need for server-side session storage.
However, they are hard to revoke once issued. Use short lifetimes and refresh tokens, and rotate signing keys.
Scopes and least privilege
Scopes limit what a token can do. They reduce risk if a token leaks.
Design scopes around actions or resource categories. Keep them small and stable so they are easy to reason about.
Auth error handling
Use 401 when authentication is missing or invalid. Use 403 when the caller is authenticated but not allowed.
Return safe messages that help developers fix issues without leaking sensitive details.
Secure transport is mandatory
Always use HTTPS. Tokens over HTTP are effectively plaintext.
For internal APIs, use private networks or mTLS, but still keep encryption as a baseline.
Rotation and audit
Keys and tokens should rotate. Build rotation into the system so you can revoke credentials without downtime.
Log auth events to detect abuse and to support compliance requirements.
