API Error: 401 {"type":"error","error":{"type":"authentication_error","message":"OAuth authentication is currently not supported."}}
Read the message, not the status code. This is a well-formed error body from a server that received your request, parsed your credential, recognised what kind of credential it was, and declined that kind. It is not a broken login, not a revoked token, not a network fault, and not a quota problem — all of which would produce different wording or no body at all.
The practical consequence is blunt: your sign-in is working, and running
/login again will hand the same endpoint the same kind of credential and get
the same 401 back.
The status code and the message disagree about what is wrong
Per the API error reference, 401 with error.type: authentication_error
generally means an API key is malformed, revoked, or expired. That is the
reading almost everyone applies here, and it sends them to the console to
regenerate something.
This particular message says something else. “OAuth authentication is currently not supported” is a statement about the authentication scheme, not about the validity of your credential. The server is saying: whatever you sent was intelligible, and this endpoint does not accept that form of it. A malformed token does not produce a message naming OAuth; a server that could not understand your credential would not be able to tell you which scheme it was.
So the failure is a mismatch between two things that are each individually fine: a subscription sign-in that works, and an endpoint that wants an API key.
Where the mismatch comes from
Claude Code can be pointed at more than one place. ANTHROPIC_BASE_URL sends
its traffic to a gateway instead of directly to Anthropic — the docs note that
error text changes to name the gateway host when this is set, which is a useful
tell that you are not talking to who you think you are. Cloud deployments are
the other family: Amazon Bedrock, Google Cloud and Microsoft Foundry are
documented as API-key/cloud-credential paths, distinct from a claude.ai
subscription sign-in.
Any of those targets can be perfectly healthy and still have no idea what to do with a subscription token. The same applies to a third-party relay, a self-hosted proxy, a team’s internal gateway, or a script that reuses Claude Code’s credential against a raw API endpoint it was never issued for.
A note on the word “currently”: it is in the vendor’s message for a reason, and it means this page should not be read as a permanent law. Treat the message as describing the endpoint you are talking to today. Claude Code’s behaviour and error strings are version-gated in the official docs often enough that a scheme’s support status is a moving target — check what your target endpoint documents rather than assuming the shape of this error is eternal.
The fix runs in the opposite direction from the usual one
This is the part worth carrying away. The most common auth misconfiguration in
Claude Code is a stray ANTHROPIC_API_KEY in the environment shadowing a
subscription — the docs call that out explicitly as the reason subscribers see
Console-billing symptoms, and the standard remedy is to unset it.
Here the remedy is the reverse: you need an API key, and the OAuth credential is what is in the way. Unsetting the key would make this error worse, not better, because it removes the only credential the endpoint would have accepted. Advice copied from the invalid-key page will actively hurt you here, and that page’s advice is correct for its own error. The variable is the same; the direction is not.
/status is what settles which situation you are in. It shows the active
settings sources and which credential is active, so it tells you both what you
are sending and — via the settings source — where that came from.
Telling the causes apart
/status shows a subscription sign-in, and ANTHROPIC_BASE_URL is set.
You are sending a subscription token to a gateway. Confirm by checking what that
host expects; a relay that terminates and re-signs requests almost always wants
an API key of its own.
You are on Bedrock, Google Cloud, or Microsoft Foundry. These paths take
their own credentials. A /login sign-in is not one of them, and no amount of
re-authenticating with claude.ai will produce one.
It works in your interactive session and fails in a script, a hook, or an SDK
app. The two contexts resolved different credentials. Compare what /status
reports interactively against what the script’s environment actually contains —
the script may be inheriting an OAuth credential from your profile while
targeting an endpoint configured for keys.
It started the day someone added a corporate gateway or an enterprise policy. Managed settings are applied from a system directory, so the change may not be visible anywhere in your own files. Check with your administrator which credential the gateway expects before you touch anything locally.
Nothing changed on your side and every endpoint fails. Then the endpoint’s own policy changed, and this is not yours to fix — verify against the vendor’s documentation for the endpoint before spending an afternoon on your config.
Is retrying useful?
No. This is a policy decision, and policy decisions are identical on every attempt.
There is no capacity involved, no retry-after header to honor, and no backoff
that converts an unsupported scheme into a supported one. The response arrived
promptly and completely — the presence of a parsed JSON body is itself proof
that the round trip worked. A retry re-runs a completed negotiation with
unchanged inputs.
If a wrapper is retrying this for you, turn it off for this error class. All it buys is a longer wait before you read the message, and the message is the entire diagnosis.
Fix by scenario
- Gateway or relay in the path — obtain and configure the credential that
gateway issues, or remove
ANTHROPIC_BASE_URLand go direct if your subscription is meant to be the credential. - Cloud provider deployment — configure that provider’s credentials. The subscription sign-in is not portable into Bedrock, Google Cloud or Microsoft Foundry.
- Script or CI inheriting the wrong credential — set the credential explicitly for that context instead of relying on what your shell happens to export. Never write the key into the repository or echo it into a build log; CI logs outlive the key.
- Endpoint genuinely does not support the scheme — switch the credential type rather than the credential. Regenerating anything is wasted motion.
Whatever you do here, do not paste a key into a chat window, a web form, or a third-party site to “test” whether it is accepted. The only safe test is a real request from your own machine.
How to confirm it’s fixed
/status naming the credential type the endpoint expects is step one, and a
successful request against that same endpoint is step two. Do not accept a
success obtained by quietly falling back to a different target — if you removed
ANTHROPIC_BASE_URL to make the error go away, confirm that is the
configuration you intended to run, not a workaround you will rediscover in a
month.
Then repeat from a newly launched process. A session started before your change still holds the old environment and will keep producing the old result, which reads as “the fix did not work” when it simply has not been loaded.
Related errors
If your login itself is failing rather than your requests, you are on the
exchange side of this cluster, not the credential side:
a login that returns a 500
got a real answer from the auth server, while
a login that times out at a fixed deadline
never got one in time. A bare
AxiosError: Request failed with status code 401
with no JSON body is a different beast again — no body means no error type to
read, and the diagnosis shifts to which client sent it. The
AI coding error triage tool separates these by
whether a request was refused, unanswered, or never made.