OAuth for MCP Servers: How Sign-In Works for AI Assistants
What actually happens between adding a remote MCP server and your assistant being able to use it: the discovery, the browser sign-in, the consent screen, the token, and what you should check on the way.
8 min read
When an AI assistant connects to a remote MCP server, MCP OAuth works like this: the assistant calls the server without a token and is refused with a 401 that says where to learn more; it reads the server’s metadata to find the sign-in service; it identifies itself to that service; it opens your browser; you sign in and approve a list of permissions; and the assistant receives an access token that works only for that server. You never see the token and nothing is pasted anywhere. Each step is fixed by the MCP authorization specification (opens in a new tab) (revision 2026-07-28 at the time of writing), and knowing them tells you what to look for on the screen you are asked to approve.
This piece is for the people who press Approve: users and team leads. If you build servers, the developer side is in how to add authentication to an MCP server. If MCP itself is new to you, start with what MCP is.
Which servers sign you in this way
Authorization is optional in MCP, and the specification splits servers by how they are reached. A server reached over HTTP, which is every remote server, should follow the OAuth flow described here. A local server that your assistant starts on your own machine and talks to over standard input and output (stdio) should not; it takes its credentials from the environment instead, usually a key in a config file. So the browser sign-in is a remote-server experience. If you are pasting a key into a JSON file, you are almost certainly configuring a local server.
The sign-in, step by step
- The assistant calls the server with no token. The server answers
401 Unauthorizedwith aWWW-Authenticateheader naming aresource_metadataaddress. If the header is missing, the client tries well-known addresses on the server instead. - The assistant reads that protected resource metadata (a small JSON document defined by RFC 9728 (opens in a new tab)). It lists at least one authorization server: the service that will sign you in. It may be the same company as the MCP server, or a separate identity provider.
- The assistant reads the authorization server’s own metadata, trying the OAuth and OpenID Connect discovery addresses (opens in a new tab) in a fixed order. That document lists the sign-in and token endpoints and whether PKCE is supported. If it does not advertise PKCE, the client must refuse to go on.
- The assistant identifies itself. The current specification prefers a Client ID Metadata Document (opens in a new tab): the client’s id is an HTTPS address pointing at a JSON description of the app. Pre-registration is used where the two sides already know each other, and dynamic client registration remains as a deprecated fallback for older servers.
- The assistant generates a PKCE secret, records which authorization server it expects to hear back from, and opens your browser at the sign-in page. The request carries a
resourceparameter naming the MCP server, so the token will be minted for that server and no other. - You sign in, the way you normally sign in to that service, and see a consent screen. This is the one step that depends on you.
- The browser is sent back to the assistant with a short-lived code. The assistant checks that the answer came from the authorization server it expected, then swaps the code, plus its PKCE secret, for an access token.
- From then on, every request to the MCP server carries
Authorization: Bearerand the token. Tokens never go in a URL.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource",
scope="files:read"PKCE is what makes a stolen code useless: only the process that started the sign-in holds the secret needed to redeem it. The resource parameter is what keeps a token for one server from being replayed at another, because the server must check that a token was issued for it and reject anything else.
What to check on the consent screen
Everything before and after the consent screen is automatic. The screen is where a mistake, or an attack, gets your approval. Read it before you press the button.
- Did you start this? An approval page that appears when you did not just add or reconnect a server is a reason to cancel, not to approve.
- Who is asking. The app name may be whatever the app called itself. A good screen says when the name is unverified. With a Client ID Metadata Document the app is at least tied to a web domain, so look at the domain as well as the name.
- Where you will be sent back to. The specification requires authorization servers using metadata documents to show the redirect hostname clearly, and to warn more when it is only
localhost. For a desktop or terminal assistant,localhostis normal. For a web assistant, it should be that vendor’s domain. - What it may do. Scopes should be few and in plain words. Untick anything the assistant does not need yet.
- Which account or workspace. If you have several, make sure the one named is the one you meant to connect.
Scopes: what you are agreeing to
Scopes are the permissions a token carries. The specification asks servers to suggest the scopes a request needs in the WWW-Authenticate header, and asks clients to request only those, falling back to the server’s published list if none is given. When the assistant later tries something its token does not cover, the server can answer 403 with insufficient_scope, and the client can ask you to approve a wider set. This is called step-up authorization, and it is the reason you do not need to grant everything at the first sign-in.
The practical rule for a team lead: approve the narrowest set that does today’s job, and let the assistant ask for more when it needs it. A second approval screen a week later costs you ten seconds. A broad token that leaks costs a great deal more. The longer argument is in MCP security best practices.
Tokens, refresh and where they live
The access token lives with the assistant, not with you. The specification requires (opens in a new tab) clients and servers to store tokens securely, and says authorization servers should issue short-lived access tokens so that a leaked one does less harm. To avoid asking you to sign in every hour, many services also issue a refresh token, which the client uses to get a new access token quietly. Refresh tokens are optional: a client must not assume it will get one, and for public clients such as desktop and terminal assistants the authorization server must rotate them on each use.
In Claude Code, for example, the documentation (opens in a new tab) says authentication tokens are stored securely and refreshed automatically, and /mcp has a “Clear authentication” option. From a shell, claude mcp login <name> and claude mcp logout <name> run and clear the sign-in for one server.
OAuth or a pasted API key?
Many servers offer both. They end in the same place, a bearer token in a header, but get there differently.
- Where the secret lives. OAuth: in the client’s secure storage, never seen by you. Pasted key: in a config file, a shell history, a chat, or all three.
- What it can do. OAuth: the scopes you approved on the consent screen, bound to one server. Pasted key: whatever the key was created with, often everything.
- How it ends. OAuth: revoked by name on the server, or cleared on the client; short-lived tokens also expire on their own. Pasted key: until someone remembers to delete it.
- Who it identifies. Both can identify a person. A key shared across a team identifies nobody, which is why a shared key is worse than either.
Keep pasted keys for what genuinely cannot open a browser, such as a scheduled job or a CI runner. Give each its own name and store it where your other secrets live.
Taking access back
There are two sides. Clearing the sign-in on your client removes the token from that machine. Revoking on the server stops the token everywhere, which is the side that matters when a laptop is lost. Before you rely on a server, find where it lists connected assistants and check that revoking one leaves your own sign-in alone.
What this looks like on fenbs
fenbs is an MCP server and runs its own authorization server. A client with no token gets a 401 carrying resource_metadata; it registers, opens your browser, and swaps the code for a token with PKCE (S256 only). The approval page shows the app’s name marked “Unverified — this is the name the app gave itself”, where you will be sent back to, and which board it will work in.
- Three scopes: read the board (always on), add and change tasks, and comment. A token is also capped by your own role on the board, and the narrower of the two wins.
- Short-lived access. The access token lasts an hour and the assistant renews it with a refresh token, so it never holds a long-lived key. The connection itself is ended by revoking it under Settings, “Connect an AI assistant”, which stops the refresh too and leaves your own sign-in untouched.
- Everything the assistant does is recorded in History as “Claude via” the person it acts for.
- For a script that cannot open a browser, a token issued by hand in the same Settings panel, with a name and ticked scopes, shown once.
Related
Connect step by step in the connection guide or Claude Code’s page. What a token and its scopes mean on a board: assistant tokens and scopes. What can go wrong when an assistant connects: MCP security risks.