|
| 1 | +# Authentication and Authorization |
| 2 | + |
| 3 | +FastAPI-MCP supports authentication and authorization using your existing FastAPI dependencies. |
| 4 | + |
| 5 | +It also supports the full OAuth 2 flow, compliant with [MCP Spec 2025-03-26](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization). |
| 6 | + |
| 7 | +It's worth noting that most MCP clients currently do not support the latest MCP spec, so for our examples we might use a bridge client such as `npx mcp-remote`. We recommend you use it as well, and we'll show our examples using it. |
| 8 | + |
| 9 | +## Basic Token Passthrough |
| 10 | + |
| 11 | +If you just want to be able to pass a valid authorization header, without supporting a full authentication flow, you don't need to do anything special. |
| 12 | + |
| 13 | +You just need to make sure your MCP client is sending it: |
| 14 | + |
| 15 | +```json |
| 16 | +{ |
| 17 | + "mcpServers": { |
| 18 | + "remote-example": { |
| 19 | + "command": "npx", |
| 20 | + "args": [ |
| 21 | + "mcp-remote", |
| 22 | + "http://localhost:8000/mcp", |
| 23 | + "--header", |
| 24 | + "Authorization:${AUTH_HEADER}" |
| 25 | + ] |
| 26 | + }, |
| 27 | + "env": { |
| 28 | + "AUTH_HEADER": "Bearer <your-token>" |
| 29 | + } |
| 30 | + } |
| 31 | +} |
| 32 | +``` |
| 33 | + |
| 34 | +This is enough to pass the authorization header to your FastAPI endpoints. |
| 35 | + |
| 36 | +Optionally, if you want your MCP server to reject requests without an authorization header, you can add a dependency: |
| 37 | + |
| 38 | +```python |
| 39 | +from fastapi import Depends |
| 40 | +from fastapi_mcp import FastApiMCP, AuthConfig |
| 41 | + |
| 42 | +mcp = FastApiMCP( |
| 43 | + app, |
| 44 | + name="Protected MCP", |
| 45 | + auth_config=AuthConfig( |
| 46 | + dependencies=[Depends(verify_auth)], |
| 47 | + ), |
| 48 | +) |
| 49 | +mcp.mount() |
| 50 | +``` |
| 51 | + |
| 52 | +## OAuth Flow |
| 53 | + |
| 54 | +FastAPI-MCP supports the full OAuth 2 flow, compliant with [MCP Spec 2025-03-26](https://modelcontextprotocol.io/specification/2025-03-26/basic/authorization). |
| 55 | + |
| 56 | +It would look something like this: |
| 57 | + |
| 58 | +```python |
| 59 | +from fastapi import Depends |
| 60 | +from fastapi_mcp import FastApiMCP, AuthConfig |
| 61 | + |
| 62 | +mcp = FastApiMCP( |
| 63 | + app, |
| 64 | + name="MCP With OAuth", |
| 65 | + auth_config=AuthConfig( |
| 66 | + issuer=f"https://auth.example.com/", |
| 67 | + authorize_url=f"https://auth.example.com/authorize", |
| 68 | + oauth_metadata_url=f"https://auth.example.com/.well-known/oauth-authorization-server", |
| 69 | + audience="my-audience", |
| 70 | + client_id="my-client-id", |
| 71 | + client_secret="my-client-secret", |
| 72 | + dependencies=[Depends(verify_auth)], |
| 73 | + setup_proxies=True, |
| 74 | + ), |
| 75 | +) |
| 76 | + |
| 77 | +mcp.mount() |
| 78 | +``` |
| 79 | + |
| 80 | +And you can call it like: |
| 81 | + |
| 82 | +```json |
| 83 | +{ |
| 84 | + "mcpServers": { |
| 85 | + "fastapi-mcp": { |
| 86 | + "command": "npx", |
| 87 | + "args": [ |
| 88 | + "mcp-remote", |
| 89 | + "http://localhost:8000/mcp", |
| 90 | + "8080" // Optional port number. Necessary if you want your OAuth to work and you don't have dynamic client registration. |
| 91 | + ] |
| 92 | + } |
| 93 | + } |
| 94 | +} |
| 95 | +``` |
| 96 | + |
| 97 | +You can use it with any OAuth provider that supports the OAuth 2 spec. See explanation on [AuthConfig](#authconfig-explained) for more details. |
| 98 | + |
| 99 | +## Custom OAuth Metadata |
| 100 | + |
| 101 | +If you already have a properly configured OAuth server that works with MCP clients, or if you want full control over the metadata, you can provide your own OAuth metadata directly: |
| 102 | + |
| 103 | +```python |
| 104 | +from fastapi import Depends |
| 105 | +from fastapi_mcp import FastApiMCP, AuthConfig |
| 106 | + |
| 107 | +mcp = FastApiMCP( |
| 108 | + app, |
| 109 | + name="MCP With Custom OAuth", |
| 110 | + auth_config=AuthConfig( |
| 111 | + # Provide your own complete OAuth metadata |
| 112 | + custom_oauth_metadata={ |
| 113 | + "issuer": "https://auth.example.com", |
| 114 | + "authorization_endpoint": "https://auth.example.com/authorize", |
| 115 | + "token_endpoint": "https://auth.example.com/token", |
| 116 | + "registration_endpoint": "https://auth.example.com/register", |
| 117 | + "scopes_supported": ["openid", "profile", "email"], |
| 118 | + "response_types_supported": ["code"], |
| 119 | + "grant_types_supported": ["authorization_code"], |
| 120 | + "token_endpoint_auth_methods_supported": ["none"], |
| 121 | + "code_challenge_methods_supported": ["S256"] |
| 122 | + }, |
| 123 | + |
| 124 | + # Your auth checking dependency |
| 125 | + dependencies=[Depends(verify_auth)], |
| 126 | + ), |
| 127 | +) |
| 128 | + |
| 129 | +mcp.mount() |
| 130 | +``` |
| 131 | + |
| 132 | +This approach gives you complete control over the OAuth metadata and is useful when: |
| 133 | +- You have a fully MCP-compliant OAuth server already configured |
| 134 | +- You need to customize the OAuth flow beyond what the proxy approach offers |
| 135 | +- You're using a custom or specialized OAuth implementation |
| 136 | + |
| 137 | +For this to work, you have to make sure mcp-remote is running [on a fixed port](#add-a-fixed-port-to-mcp-remote), for example `8080`, and then configure the callback URL to `http://127.0.0.1:8080/oauth/callback` in your OAuth provider. |
| 138 | + |
| 139 | +## Working Example with Auth0 |
| 140 | + |
| 141 | +For a complete working example of OAuth integration with Auth0, check out the [auth_example_auth0.py](/examples/08_auth_example_auth0.py) in the examples folder. This example demonstrates the simple case of using Auth0 as an OAuth provider, with a working example of the OAuth flow. |
| 142 | + |
| 143 | +For it to work, you need an .env file in the root of the project with the following variables: |
| 144 | + |
| 145 | +``` |
| 146 | +AUTH0_DOMAIN=your-tenant.auth0.com |
| 147 | +AUTH0_AUDIENCE=https://your-tenant.auth0.com/api/v2/ |
| 148 | +AUTH0_CLIENT_ID=your-client-id |
| 149 | +AUTH0_CLIENT_SECRET=your-client-secret |
| 150 | +``` |
| 151 | + |
| 152 | +You also need to make sure to configure callback URLs properly in your Auth0 dashboard. |
| 153 | + |
| 154 | +## AuthConfig Explained |
| 155 | + |
| 156 | +### `setup_proxies=True` |
| 157 | + |
| 158 | +Most OAuth providers need some adaptation to work with MCP clients. This is where `setup_proxies=True` comes in - it creates proxy endpoints that make your OAuth provider compatible with MCP clients: |
| 159 | + |
| 160 | +```python |
| 161 | +mcp = FastApiMCP( |
| 162 | + app, |
| 163 | + auth_config=AuthConfig( |
| 164 | + # Your OAuth provider information |
| 165 | + issuer="https://auth.example.com", |
| 166 | + authorize_url="https://auth.example.com/authorize", |
| 167 | + oauth_metadata_url="https://auth.example.com/.well-known/oauth-authorization-server", |
| 168 | + |
| 169 | + # Credentials registered with your OAuth provider |
| 170 | + client_id="your-client-id", |
| 171 | + client_secret="your-client-secret", |
| 172 | + |
| 173 | + # Recommended, since some clients don't specify them |
| 174 | + audience="your-api-audience", |
| 175 | + default_scope="openid profile email", |
| 176 | + |
| 177 | + # Your auth checking dependency |
| 178 | + dependencies=[Depends(verify_auth)], |
| 179 | + |
| 180 | + # Create compatibility proxies - usually needed! |
| 181 | + setup_proxies=True, |
| 182 | + ), |
| 183 | +) |
| 184 | +``` |
| 185 | + |
| 186 | +You also need to make sure to configure callback URLs properly in your OAuth provider. With mcp-remote for example, you have to [use a fixed port](#add-a-fixed-port-to-mcp-remote). |
| 187 | + |
| 188 | +### Why Use Proxies? |
| 189 | + |
| 190 | +Proxies solve several problems: |
| 191 | + |
| 192 | +1. **Missing registration endpoints**: |
| 193 | + The MCP spec expects OAuth providers to support [dynamic client registration (RFC 7591)](https://datatracker.ietf.org/doc/html/rfc7591), but many don't. |
| 194 | + Furthermore, dynamic client registration is probably overkill for most use cases. |
| 195 | + The `setup_fake_dynamic_registration` option (True by default) creates a compatible endpoint that just returns a static client ID and secret. |
| 196 | + |
| 197 | +2. **Scope handling**: |
| 198 | + Some MCP clients don't properly request scopes, so our proxy adds the necessary scopes for you. |
| 199 | + |
| 200 | +3. **Audience requirements**: |
| 201 | + Some OAuth providers require an audience parameter that MCP clients don't always provide. The proxy adds this automatically. |
| 202 | + |
| 203 | +### Add a fixed port to mcp-remote |
| 204 | + |
| 205 | +```json |
| 206 | +{ |
| 207 | + "mcpServers": { |
| 208 | + "example": { |
| 209 | + "command": "npx", |
| 210 | + "args": [ |
| 211 | + "mcp-remote", |
| 212 | + "http://localhost:8000/mcp", |
| 213 | + "8080" |
| 214 | + ] |
| 215 | + } |
| 216 | + } |
| 217 | +} |
| 218 | +``` |
| 219 | + |
| 220 | +Normally, mcp-remote will start on a random port, making it impossible to configure the OAuth provider's callback URL properly. |
| 221 | + |
| 222 | + |
| 223 | +You have to make sure mcp-remote is running on a fixed port, for example `8080`, and then configure the callback URL to `http://127.0.0.1:8080/oauth/callback` in your OAuth provider. |
0 commit comments