Blog
401 vs 403 for API Developers
401 means the credential is missing or expired. 403 means the credential is valid and not allowed. Mixing them sends developers into the wrong fix, and they leave before they file anything.
2026-07-23 · 6 min read · AethelLayer
The next step is different
A 401 should tell them to refresh a token or pass the header. A 403 should tell them which permission or tenant is missing. One 'access denied' string makes both look like a bad password.
Use two stable codes. Scripts and agents branch on the code. Humans search it.
Say which credential you looked at
Name the header or the query parameter. Do not echo the secret. 'Authorization bearer was missing' is enough. 'The token for org_123 cannot call billing:write' is the 403 version.
If you have more than one auth scheme, say which one this route expects. Evaluators paste an OAuth access token into an API-key header all week.
SDKs must not collapse the two
Throw distinct errors. A single ApiError with only the HTTP status forces every sample into the same catch. The code property is the contract.
On 401, the SDK may refresh once if it owns the refresh token. On 403, it must not retry. Retrying a permission error looks like abuse.
Cluster by code and route
A spike of 403 on one new route is a scope you forgot to document. A spike of 401 on login is an expired sample token. The status code alone mixes them if you only chart '4xx'.
Keep the developer's sentence with the probe. 'I was using the key from the dashboard example' is the doc bug.
Keep reading
Capture the failure before they leave
Capture the failure before they leave. Book early access or talk to sales, then install @aethellayer/sdk when you are onboarded.