MCP server auth implementation guide: using the latest spec
Provides key implementation points for MCP server authentication compliance with the 2025-06-18 specification.
A few days ago (June 18, 2025), the MCP (Model Context Protocol) team released the latest version of the MCP Spec (2025-06-18). This update includes a key change to the auth spec. MCP Servers will no longer issue access tokens as an Authorization Server. Instead, they will consume access tokens and provide resources as a Resource Server.
As one of the maintainers of MCP Auth (a plug-and-play MCP Server auth library), I have implemented support for the latest MCP auth spec in this project. Based on my practical experience, I will show you how to implement authentication features for your MCP Server that comply with the latest specification.
This article will help you:
- Understand how MCP auth works under the new MCP auth spec
- Clarify what MCP Servers need to implement as Resource Servers according to the MCP auth spec requirements
- Provide guidance for implementing auth support that meets the latest MCP auth spec requirements for your MCP Server
- Identify overlooked points and security issues when implementing the MCP auth spec
Please note this article:
- Assumes readers have basic knowledge of JWT (JSON Web Token). The article will not cover JWT structure, signature verification, and other basic concepts in detail. For specific details, refer to Auth Wiki - JWT
- Does not deeply introduce various RFCs that the MCP auth spec depends on. It only provides implementations that comply with these RFC requirements
- Does not cover MCP Client and Authorization implementation and interaction details. These are usually implemented by LLM clients and authorization server providers that support MCP based on MCP specifications. MCP Server developers do not need to and cannot interfere with related implementations. For specific details, refer to OAuth Client and Authorization Server
- All access tokens mentioned in the article are assumed to be JWT, which is the most widely used format in the market. Other forms of tokens need to be used according to the documentation provided by the corresponding authorization server provider.
How does MCP auth work?
According to the latest MCP auth spec, the MCP auth flow is shown in the following diagram:
-
The MCP Client requests resources from the MCP Server at
https://github-tools.com
. Since the user has not logged in yet, the HTTP authorization header of this request does not contain an access token representing the user. -
The MCP Server cannot get an access token from the authorization header of the MCP Client's request. It returns an HTTP 401 error to the MCP Client. This error response includes a WWW-Authenticate header, which contains the URL of the MCP Server's resource metadata (the value of the
resource_metadata
field). -
The MCP Client extracts the value of
resource_metadata
from the returned WWW-Authenticate header (for example:https://github-tools.com/.well-known/oauth-protected-resource
). Then the MCP Client requests the resource metadata provided by the MCP Server as a Resource Server from this address. This metadata includes content such asauthorization_servers
andscopes_supported
, helping the MCP Client understand how to obtain the access token needed to access the MCP Server, such as from which authorization server to get a token with certain permissions.
4-8. The MCP Client requests authorization server metadata information based on the authorization server metadata URL obtained from the resource metadata. Then the MCP Client conducts an OAuth 2.1 authorization flow with the authorization server and obtains an access token after completing authorization.
-
The MCP Client carries the access token obtained from the authorization server and makes another resource request to the MCP Server.
-
The MCP Server returns the requested resource after verifying that the token is valid. After that, communication between the MCP Client and MCP Server will continue with the valid token.
Next, we will explain how to implement the MCP server's auth mechanism step by step based on the MCP auth workflow.
Handle unauthorized requests: return 401 error and WWW-Authenticate Header
As shown in the above flow, when the MCP Client sends a request without an access token to the MCP Server, the MCP Server will return an HTTP 401 Unauthorized error with a WWW-Authenticate
header containing the URL to get the MCP Server's resource metadata.
According to the MCP auth spec error handling requirements, besides MCP Client requests not carrying access tokens, when the MCP Server receives an invalid access token, it should also return a 401 error with a WWW-Authenticate
header.
After knowing when to return a 401 error, how should we build the returned WWW-Authenticate
header?
According to RFC9728 Section 5.1, the WWW-Authenticate
header needs to include a resource_metadata
parameter to indicate the URL of the protected resource metadata.
Its basic format is as follows:
Here, Bearer
is the authentication scheme, indicating that a bearer token is needed to access OAuth 2.0-protected resources (see: MDN documentation). The value of the resource_metadata
parameter that follows is the complete URL of the resource metadata endpoint provided by your MCP Server.
The actual code implementation is similar to:
When the MCP Client receives such a 401 error, the MCP Client will access the MCP Server's resource metadata through the value of resource_metadata
in the WWW-Authenticate
header. Then, based on the information provided by the resource metadata, it will initiate an authorization request to the specified authorization server to obtain an access token that can be used to access the MCP Server.
Now we know when to return a 401 error and that we need to return a resource_metadata
URL. But we still don't know how to build this resource metadata URL and what the metadata contains. This is what we will introduce next.
Implement resource metadata discovery mechanism
According to the MCP auth flow, after the MCP Client receives a 401 error, it immediately requests resource metadata from the MCP Server. So the MCP Server as a Resource Server should implement a resource metadata discovery mechanism.
Determine the URL path of the metadata endpoint
In the OAuth system, we use URLs to identify Resource addresses. This address is called a "resource indicator". According to RFC9728 regulations, resource metadata should be hosted under a specific /.well-known
path.
If your MCP Server (like https://github-tools.com
) only provides one service, the metadata endpoint should be set to:
If you provide multiple different MCP services on one host, each service should have an independent metadata endpoint. For example, the enterprise platform https://api.acme-corp.com
provides the following services:
https://api.acme-corp.com/github
- GitHub integration servicehttps://api.acme-corp.com/slack
- Slack integration servicehttps://api.acme-corp.com/database
- Database query service
The corresponding metadata endpoints should be:
https://api.acme-corp.com/.well-known/oauth-protected-resource/github
https://api.acme-corp.com/.well-known/oauth-protected-resource/slack
https://api.acme-corp.com/.well-known/oauth-protected-resource/database
The advantage of this design is that each service can have different permission scopes and authorization server configurations. For example:
- GitHub service uses GitHub OAuth server, needs
github:read
,github:write
permissions - Slack service uses Slack OAuth server, needs
slack:channels:read
,slack:messages:write
permissions - Database service uses enterprise internal authorization server, needs
db:query
permission
From the above situations, we can summarize that metadata endpoint URLs follow this pattern:
We can get the metadata endpoint URL of this resource from the resource identifier in this way:
Build resource metadata response
After determining the endpoint URL path, we need to make this endpoint return JSON format metadata that complies with RFC9728 regulations.
In actual implementation, we mainly need to focus on four core fields.
First is the resource
field, which is the resource identifier and should be consistent with the resource address that the MCP Client wants to access.
Then is the authorization_servers
field, which is an array specifying which authorization servers the MCP Client should apply for access tokens from. According to OAuth 2.0 Protected Resource Metadata (RFC 9728), this field is optional. But in the MCP auth spec, this field is required because the MCP Client needs to clearly know which authorization server to initiate authorization requests to. Without this information, the MCP Client cannot complete the subsequent OAuth flow.
Next is the scopes_supported
field, which lists all permission scopes supported by this Resource Server.
Finally is the bearer_methods_supported
field, which tells the MCP Client what methods this server supports for receiving access tokens. Usually we set it to ["header"]
, indicating that after the MCP Client gets an access token from the Authorization Server, it should send the token to the MCP Server through the HTTP Authorization header.
Let's look at a specific example. Suppose we want to configure resource metadata for the https://github-tools.com
MCP Server:
This configuration tells the MCP Client several important pieces of information: it wants to access the https://github-tools.com
resource, needs to apply for an access token from the https://auth.github-tools.com
authorization server, can apply for permissions like github:read
, github:write
, repo:admin
, and should pass the obtained token through the HTTP Authorization header.
For most application scenarios, configuring these four basic fields is enough for the MCP Client to work normally. If you need more complex configurations, you can refer to the complete field list in RFC9728 to understand all available options.
Validate access tokens
After the MCP Client gets an access token from the authorization server, the Client will carry this access token to access the MCP Server.
In practice, MCP servers need to pay attention to the following points when validating access tokens:
- When performing basic token validation, validate the token based on the MCP Server's configuration, not by getting authorization server information from the token's carried information.
- Validate whether the token's audience is the MCP Server itself, ensuring that the token was indeed obtained for accessing the MCP Server's resources.
- Handle scope validation correctly
Use MCP Server configuration to validate access tokens
When the MCP Server receives an access token, because this token itself contains authorization server information (issuer
), some developers will directly get the information needed to validate the token based on the issuer
carried by the token. This is especially true when the MCP Server resource metadata provides multiple authorization server configurations, such as when the MCP server's resource metadata returns:
In this situation, developers will first extract the issuer
from the unverified token to match the data provided by the authorization server used for verification. Attackers might construct a malicious authorization server and issue a fake access token for the MCP Server. If developers directly extract the issuer
pointing to this malicious authorization server from this fake access token and rely on this malicious authorization server to validate this access token, then this validation will pass.
Therefore, the correct validation method should be:
- For situations with only one authorization server configured: directly validate this token based on the backend-configured authorization server
- For situations with multiple authorization servers configured: first extract the
issuer
from the unverified token and find the corresponding authorization server from the MCP Server's configuration items for verification. If no corresponding authorization server is found, reject this token
Of course, when validating tokens, remember to strictly validate the token's issuer.
Taking the jose JWT validation library as an example:
Validate token audience
The Token Audience Binding and Validation section of the MCP auth spec states that when a client requests an access token from an authorization server, it must specify what resource this access token request will be used to access. The MCP Server must also check whether this token's audience is itself when validating the token.
This mechanism is based on the Resource Indicators for OAuth 2.0 (RFC 8707) standard. Simply put, its workflow is as follows:
-
Client request phase: When the MCP Client requests an access token from the authorization server, it will specify the
resource
parameter in the request, telling which specific resource server the token will be used to access (for examplehttps://github-tools.com
) -
Token issuance phase: After receiving the request, the Authorization server will bind the specified resource address to the access token. For JWT format tokens, this resource address will be written into the JWT payload as the value of the
audience
(abbreviated asaud
) field -
Token validation phase: When the MCP Server receives this access token, it must verify whether the
audience
field in the JWT exactly matches its own resource identifier
Taking our https://github-tools.com
MCP Server as an example:
This audience validation is a key security mechanism to prevent token abuse. Without this validation, attackers might use access tokens issued for other services to try to access your MCP Server. If your server doesn't validate audience, it might incorrectly accept tokens that shouldn't be accepted.
Scope validation
Some MCP Servers manage access permissions for internal resources because different users may have different permission scopes.
So after the access token passes validation, we need to further check whether this access token has certain permissions. We can do this by verifying whether the scope
claim in the token includes the permissions required to access the current resource:
Note that according to the MCP auth spec, when this token does not have the scope required by the accessed resource, a 403 Forbidden error should be returned.
Conclusion
Through this article's introduction, you should be able to implement authentication features that comply with the latest specifications for your MCP Server. Remember a few key points: validate tokens securely, configure metadata correctly, and strictly verify audience.
If you are building an MCP Server, try the MCP Auth library. It has already implemented all the functionality discussed in this article and can help you quickly integrate auth support.
Feel free to discuss any questions on GitHub. Let's work together to advance the MCP ecosystem.