A year ago, Anthropic released the Model Context Protocol (MCP): a new protocol for AI processes such as LLMs and AI agents to reliably connect with external resources and data. Before MCP was open-sourced, developers would load an API’s OpenAPI specification into the AI workflow. However, these specifications didn’t convey the purpose or usage context behind the API. MCP addresses this gap by pre-packaging prompt templates, tools, and data of external resources like Salesforce.
Because AI agents and LLMs aren’t humans, the authorization flows for MCP are distinct from a traditional API. APIs usually rely on signed credentials of a human user (e.g. via email and password). AI agents and LLMs must attain such authorization autonomously, without a human. Hardcoding login credentials into the AI agent is dangerous, so we need a context-aware approach for AI agents and MCP.
Today, we’ll explore best practices for handling authorization within MCP and go over OAuth 2.1, Proof Key for Code Exchange, Dynamic Client Registration, and authorization frameworks. But first, how does MCP actually work?
What is Model Context Protocol (MCP)
The Model Context Protocol (MCP), created by Anthropic, outlines how applications should provide context to Large Language Models (LLMs). MCP is often considered the “USB-C port for AI applications,” but it’s more like a cakemix box that describes what’s included inside, instructions on how to use it, and the potential complex things to create with it.
MCP differs from API protocols (e.g. OpenAPI) by providing AI agents with more than just descriptive data. OpenAPI specifications are detailed, but leave AI agents to figure out how to use them effectively on their own. On the other hand, a human might utilize the API’s documentation along with online tutorials to guide them. With MCP, AI agents can access all of this in one framework to operate with much more context.
How does MCP work?
MCP establishes a client-server model where an AI application serves as a host for several MCP clients. To connect to an external resource, a.k.a. an MCP server, the host will create an MCP client to manage that relationship.
MCP servers provide three key components:
- Tools that the AI can call to perform specific functions, similar to API endpoints
- Resources, files, and data that the AI can access from connected applications
- Prompts, which are predefined instructions to guide the AI in specific scenarios
Whereas traditional APIs simply outline strict guidelines on what services they provide, developers can use MCP to create more context-aware AI systems that can understand the tools at its disposal.
How does MCP handle authorization?
Although some MCP servers do not require authorization (usually public resources, like WHOIS), most MCP servers need some form of client authorization. In some cases, to control usage and prevent excessive requests (e.g. CC0 images database). In others, to safeguard distribution of otherwise confidential data (e.g. Salesforce).
There are several approaches to managing authorization. The simplest is using API keys, preferably stored and securely managed in a dedicated key management solution like Infisical. With their simplicity, API keys have their drawbacks: they usually grant service-wide access instead of granular, user or task-specific control. Additionally, not every service supports API key authentication.
Most applications instead utilize a user-delegated authorization flow like OAuth 2.0. But such flows become trickier when it comes to AI agents, who are not humans. AI agents can’t just log in or manage credentials themselves, and hardcoding credentials directly into an AI agent’s codebase is dangerous.
To handle this, developers can use Dynamic Client Registration (DCR) to pre-authorize AI agents based on specific attributes. But first, let’s start with the basics: OAuth 2.1, MCP’s adopted authorization standard.
What is OAuth 2.1?
OAuth 2.1 is a proposed IEEE specification based on the OAuth 2.0 framework in order to address security gaps. A core principle of OAuth 2.1 is delegated authorization, allowing third-party services to securely manage authorization for the MCP clients and server.
Compared to OAuth 2.0, the new specification introduces three changes: mandated PKCE, Metadata Discovery, and DCR.
Let’s dive deeper into each one.
Proof Key for Code Exchange (PKCE)
PKCE, initially introduced as an an optional extension for OAuth 2.0, provides an extra layer of security during the exchange of the authorization code for an access token.
Let’s review the OAuth 2.0 process:
- The user provides their valid credentials.
- The authorization server issues an authorization code to the client server.
- The client exchanges that code for an access token.
- The client server can access protected resources with the access token.
However, this also exposes a security risk: if an attacker manages to intercept the authorization code, the malicious actor can now exchange it for an access token and gain unauthorized access!
PKCE adds extra steps to mitigate this:
- Before the user even submits credentials, the client server generates a random string called a verifier and derives a code challenge from it.
- When the client requests an authorization code, the challenge is also attached.
- When the authorization code grant is submitted for an access token, the verifier is also attached.
- If the verifier matches the original code challenge, the server issues the access token.
Because the client only sends the verifier when requested the access token the authorization server can be sure that it’s communicating with the original client instead of a malicious actor.
Metadata Discovery
Because humans are not manually setting up connections between MCP clients and servers, there needs to be a reliable way for an MCP client to know which authorization server to use. This can be achieved by having authorization servers expose metadata about themselves for the MCP clients to read.
This is especially important for Dynamic Client Registration, where MCP clients can register with authorization servers without human intervention.
Dynamic Client Registration
Another OAuth 2.0 extension that has been incorporated into OAuth 2.1 is Dynamic Client Registration (DCR). It enables MCP clients to automatically pre-register with new authorization servers without any user involvement. DCR enables AI agents, which cannot predict which resources they might need, to adapt and request authorization servers that the user wasn’t originally are of when the AI agent was initially created.
Beyond OAuth 2.1, how is authorization practically implemented?
OAuth 2.1 handles the challenge of obtaining a valid access token for an MCP client, but authorization goes beyond just tokens. Once a client’s identity has been established, systems still need to determine the identity’s permissions.
This is what access frameworks are for. In modern systems, most approaches can be categorized in one of three ways:
- Role-Based Access Control (RBAC) groups permissions into roles (e.g. admin, editor, or viewer) which are then assigned to an identity.
- Relationship-Based Access Control (ReBAC) determines access by the relationships between entities (e.g. user owns dataset, employee reports to manager).
- Attribute-Based Access Control (ABAC) bases permissions on attributes of the user or resource (e.g. the user’s identity or device, resource type, or request context).
Developers can mix frameworks (often called “AnyBAC”) and implement policy-as-code engines like Oso or Open Policy Agent (OPA) to handle enforcement.
In the context of MCP, OAuth 2.1 securely authorizes clients. Once authorized, access control frameworks define what resources the MCP client can access, under what conditions, and how the actions are logged and audited. OAuth essentially decides who can enter, while these frameworks govern what they’re allowed to do once inside.
What is Oso?
Oso is a policy-as-code framework that lets developers implement fine-grained authorization directly into their applications. Rather than dispersing access checks throughout the codebase, Oso consolidates them into centralized policies written in its declarative language, Polar. These policies can handle everything from role-based permissions (RBAC) to more complex models like ABAC and ReBAC.
In practice, Oso works as a smart gatekeeper. When an MCP client offers a token, Oso checks whether that token’s identity can perform a specific action of a specific resource. For instance, a Polar policy can specify that only the document’s owner can edit it, or that only certain roles and devices can access sensitive data.
If you are curious about Oso’s work, and how we’re automating least privilege for AI agents, learn more by clicking here.
Top comments (0)