Chapter 11 of 11
Choosing an API Authentication Method
A decision table across complexity, revocation, rotation, delegation, browser exposure and maturity, plus the four questions that usually settle it first.
Most of this API authentication decision is made by two facts you already have. Who is calling, and what they are calling on behalf of. The table below is for the cases where that is not enough.
Four questions that usually settle it
Is there a user delegating access? If yes, you are in OAuth territory, and the only real question is which grant. If no, OAuth's redirect flows are answering a question you do not have.
Can the client keep a secret? Anything running in a browser or shipped to a phone cannot, which rules out schemes that depend on a client secret staying private and makes PKCE mandatory.
How fast must you be able to revoke? Immediately means an opaque token or a key you can withdraw centrally. Within minutes means short-lived tokens are sufficient.
Does the request need integrity beyond the channel? Almost never, and where it does, a signature scheme is the answer and not a token.
The decision table
| Method | Complexity | Revocation | Rotation | Delegation | Browser exposure | Transport | Maturity | Typical use |
|---|---|---|---|---|---|---|---|---|
| API key | Very low | Immediate, per key | Manual, needs overlap | None | High if stored in the page | TLS required | Universal | Machine to machine, public API access |
| HTTP Basic | Very low | Change the password | Manual | None | High | TLS required | Universal | Token endpoints, internal calls |
| HTTP Digest | Medium | Change the password | Manual | None | Not applicable | Survives plain HTTP | Legacy | Devices, older systems |
| Bearer, opaque | Low | Immediate | Automatic on expiry | Through the issuer | Medium | TLS required | Universal | Any token-based API |
| JWT | Medium | Hard, needs a denylist | Automatic on expiry | Through the issuer | Medium | TLS required | Universal | Stateless validation at scale |
| OAuth 2.0 client credentials | Medium | Central, at the server | Automatic on expiry | None | Low, no browser | TLS required | Universal | Service to service with central control |
| OAuth 2.0 code with PKCE | High | Central, at the server | Automatic, refresh rotation | Full | Low, nothing in the page | TLS required | Universal | Third-party and first-party user access |
| OpenID Connect | High | Central, at the server | Automatic | Full, plus identity | Low | TLS required | Universal | Sign-in and user identity |
| OAuth 1.0 | High | Revoke the token | Manual | Full | Not applicable | Works without TLS | Legacy | Established integrations |
| AWS Signature V4 | High | Rotate the access key | Derived keys, short-lived | None | Not applicable | Works without TLS | Universal in its niche | AWS service calls |
| Hawk | Medium | Rotate the key | Manual | None | Not applicable | Works without TLS | Niche | Internal systems needing signatures |
| NTLM | High | Change the password | Manual | None | Not applicable | Domain-bound | Legacy | Windows intranets |
| Mutual TLS | High | Revoke the certificate | Certificate lifecycle | None | Not applicable | Is the transport | Universal | High-assurance, known parties |
| Session cookie | Low | Delete the session | Automatic on expiry | None | Low with HttpOnly | TLS required | Universal | Browser to your own API |
Two columns deserve a note. Browser exposure asks how much damage a cross-site scripting flaw does, so a cookie marked HttpOnly scores well because script cannot read it, and a token in storage scores badly. Maturity distinguishes methods you can expect any client library to support from ones that need custom work.
By situation
| Situation | Use | Why |
|---|---|---|
| A partner integration you both control | API key, scoped and rotatable | Lowest friction, and the scoping does the work |
| A public API with many machine callers | API key, with OAuth client credentials as an option | Keys get people started, and OAuth serves the ones who want short-lived credentials |
| A third-party app acting for your users | OAuth 2.0 authorization code with PKCE | The case OAuth was built for, per RFC 7636 and RFC 9700 |
| Your own single-page application | Authorization code with PKCE, or a cookie session | Both avoid a long-lived token in browser storage |
| Your own mobile application | Authorization code with PKCE | A mobile app is a public client and cannot hold a secret |
| Service to service inside one estate | Client credentials, or mutual TLS in a mesh | Central revocation, or transport-level identity |
| Payments or health data between known parties | Mutual TLS plus a token | Transport identity plus application authorization |
| Something old that already speaks a scheme | That scheme | This is an integration task, not a design decision |
Supporting two methods
Plenty of APIs accept both a key and a token, and there is nothing wrong with that as long as two things hold.
Every path enforces the same authorization. A second way in is a second place to get the object-level check wrong, and an attacker will find whichever path is weaker.
The specification says which endpoints accept which. A caller cannot infer it, and documenting security schemes is how you say it once.
Migrating from one method to another
A migration that begins with a cut-off date and no overlap becomes somebody's outage. The sequence that works has four steps.
Accept both. Add the new scheme alongside the old one, with no deadline yet.
Instrument. Record which callers use which, so you know who is affected before you announce anything.
Announce with a date, and give people a way to test. A staging environment that only accepts the new scheme lets an integrator verify their change without switching production.
Withdraw, in stages. New callers first, then the ones you have heard from, then the rest, watching the traffic on the old scheme go to zero.
In Routebase
Two of the decisions above show up directly in how Routebase is used.
Supporting several methods is ordinary, not awkward. An environment defines the default, a suite overrides it where a different identity is needed, and a case overrides that again. A project talking to a legacy service with Digest and a modern service with OAuth handles both in one place, because both are in the same catalogue.
Migrating is easier when both schemes can run side by side in the same suite. Configure the new scheme on a second environment, point the same suite at it, and compare the runs. Because environment-specific values live in the environment instead of in the tests, that comparison costs nothing but a dropdown.
If you have decided which method you need, the setup path is in setting up authentication in Routebase, and the configuration surface is documented in Project Auth.
Frequently asked questions
Which authentication method is best for a public API?
For machine callers, an API key with scopes and rotation covers most public APIs and is the lowest-friction option for the people integrating with you. Add OAuth 2.0 client credentials when you want short-lived tokens and central revocation, and add the authorization code flow with PKCE when third parties will act on behalf of your users. Most successful public APIs offer keys for the simple case and OAuth for the delegated one.
Is OAuth 2.0 overkill for a simple API?
It is when nobody is delegating anything, because OAuth exists to let one party act for another without sharing a password. A service calling your API on its own behalf gains short-lived credentials and central revocation from the client credentials grant, and it gains nothing from the redirect flows. Introducing OAuth for a case with no resource owner adds moving parts and answers a question you did not have.
Can an API support more than one authentication method?
Yes, and many do, with an API key for straightforward machine access and OAuth for delegated access. Document each scheme in your specification and say per endpoint which ones are accepted, since a caller cannot infer that. The cost is that every path needs the same authorization checks behind it, because a second way in is a second way to get it wrong.
How do you migrate an API from one authentication method to another?
Accept both for a period, instrument which callers use which, and only then withdraw the old one. Announce the deadline before you set it in code, and give integrators a way to test the new scheme without switching, such as a staging environment that only accepts the new method. A migration that starts with a cut-off date and no overlap becomes an outage for somebody.
Last reviewed by The Routebase Team.