OAuth 2.1 for remote MCP servers — Complete guide
Curso MCP Engineering · M3
This guide explains, from scratch and taking nothing for granted, how a remote MCP server controls who can use it. It's a guide to keep beside you: first the "how it works" —which is what makes everything else fall into place— and then the vocabulary so you don't get lost. No need to write code yet.
In one sentence
When an MCP server lives on the internet and decides to authenticate (ask for credentials), MCP requires a single framework: OAuth 2.1. The server never trusts: it asks for credentials, checks them, and only then opens the door. The rhythm is always the same: 401 → discovery → token → validate.
First of all: authenticating is OPTIONAL
This is key and many people get it wrong. A remote server can be public (no login), just as there are web pages anyone opens without an account. Authentication is not mandatory.
What is mandatory is the how: if a remote server decides to authenticate, it has to do it with OAuth 2.1. You can't invent your own password scheme. So:
- Local server over stdio → doesn't need OAuth (whoever reached your machine is already inside).
- Public remote server → may skip authentication.
- Remote server that authenticates → must use OAuth 2.1.
What is OAuth, in simple words?
OAuth is the standard "log in and grant permission" system. You've already used it without realizing: every time you enter an app with "Continue with Google," that's OAuth. Instead of giving your password to each app, a trusted authorization server hands you a temporary credential that the app can verify. OAuth 2.1 is the modernized, more secure version of that standard, and it's the one MCP adopts.
The flow, explained as a conversation
Think of OAuth 2.1 as entering a building with a reception desk. You don't knock on the office door: first you pass through reception, show who you are, they give you a temporary credential, and only with that credential do they let you through. These are the five steps, in order:
- The client knocks on the door. Your MCP client sends the first request to the remote server, still without credentials. It doesn't yet know what it will be asked for.
- The server responds
401 Unauthorized. It's a "not yet." But it's not a door slammed shut: alongside the 401 comes aWWW-Authenticateheader that points to the metadata of the protected resource. The server tells you "you need permission, and here's the address to find out how to get it." - The client does discovery. Following that clue, the client queries the endpoint
/.well-known/oauth-protected-resource. That "well-known" file tells it who the authorization server is — the one to ask for the token. These discovery endpoints stay always open, without authentication, so a new client can get started (bootstrap) without knowing anything in advance. - The client obtains a token (a JWT). With that information, the client goes to the authorization server, proves its identity, and receives an access token in the form of a JWT.
- The client retries, now with the credential. It repeats the original request, but this time it adds the header
Authorization: Bearer <token>. The server validates the JWT and, if everything checks out, responds. You're in.
Who does what
| Step | What happens | Who |
|---|---|---|
| 1 | First request, without credentials | Client → Server |
| 2 | 401 Unauthorized + WWW-Authenticate pointing to the metadata | Server → Client |
| 3 | Discovery at /.well-known/oauth-protected-resource (open endpoint) | Client → Server |
| 4 | Issues the access token (JWT) | Authorization server → Client |
| 5 | Retry with Authorization: Bearer <token> | Client → Server |
| 6 | Validates the JWT: issuer, audience, scope | Server |
What a JWT is (the "token")
JWT stands for JSON Web Token. It's a token that carries signed information inside: who issued it, who it's for, when it expires, and what permissions it includes. Think of it as an event wristband: there's no need to phone the organization to confirm you're valid —the wristband carries the data and a seal that can't be forged. That seal is the signature: the server checks that the token is legitimate without keeping a copy of every credential ever issued.
What the server validates in the JWT
When the server receives the Bearer <token>, it doesn't accept it blindly. It checks three things:
| Field | Question it answers | If it doesn't check out… |
|---|---|---|
Issuer (iss) | Was it issued by the authorization server I trust? | Rejected |
Audience (aud) | Was the token issued for this server? | Rejected |
| Scope | Does it include the permission for the requested action? | Rejected |
This verification is the heart of security first: a token valid for another service must not work in yours. A remote server never trusts a token without validating it.
Why does discovery stay open?
It may look like a hole, but it's on purpose. The /.well-known/... endpoint only hands out metadata about where to ask for the token (who the authorization server is). It does not hand out protected data or tokens. Knowing which door to knock on doesn't let you in: for that you still need a valid JWT. That's why it stays open: so a new client can get started without knowing anything in advance.
Key moments in the video
- 5:25 — The first OAuth 2.1 flow. The full journey: request without credentials,
401, and retry with token. Take away the rhythm 401 → discovery → token → validate. - 11:15 — The
well-knowndiscovery. How the client discovers on its own which authorization server to ask for the token, without credentials. - 27:40 — Validating the JWT. The key security moment: the server checks issuer, audience, and scope before letting you through. If you take one image away from the video, make it this one.
Glossary
- OAuth 2.1: authorization framework that MCP requires when a remote server authenticates.
- 401 Unauthorized: response that says "you need credentials"; it carries the clue to get them.
WWW-Authenticate: the 401 header that points to the metadata of the protected resource.- Discovery /
well-known: open endpoints that tell you whom to ask for the token. - Authorization server: the one that issues the credentials (the token).
- JWT (JSON Web Token): signed token with issuer, audience, expiration, and scope inside.
Authorization: Bearer <token>: the header with which the client presents the token.- Issuer / Audience / Scope: who issued it / who it's for / what it allows — what gets validated.
To remember
- Authenticating is optional; but if a remote MCP server authenticates, it must use OAuth 2.1. A local server over stdio doesn't need it.
- The rhythm is always: 401 → discovery → token → validate.
- The
401isn't a door slammed shut: inWWW-Authenticateit carries the clue to get permission. - The
/.well-known/...endpoints stay open on purpose: they're the client's bootstrap. - The server never accepts a
Bearerblindly: it validates issuer, audience, and scope. - Golden rule: a remote server doesn't trust; it verifies.
Turning Point Academy · MCP Engineering Course · Module 3 · OAuth 2.1 for remote servers