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