> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/punkpeye/fastmcp/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Secure your MCP server with OAuth 2.1, API keys, and custom authentication

FastMCP provides flexible authentication options to secure your MCP server, from simple API keys to full OAuth 2.1 flows with pre-configured providers.

## OAuth with Pre-configured Providers

The simplest way to add OAuth is using the `auth` option with a pre-configured provider:

```typescript theme={null}
import { FastMCP, getAuthSession, GoogleProvider, requireAuth } from "fastmcp";

const server = new FastMCP({
  auth: new GoogleProvider({
    baseUrl: "https://your-server.com",
    clientId: process.env.GOOGLE_CLIENT_ID!,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
  }),
  name: "My Server",
  version: "1.0.0",
});

server.addTool({
  canAccess: requireAuth,
  description: "Get user profile",
  execute: async (_args, { session }) => {
    const { accessToken } = getAuthSession(session);
    const response = await fetch(
      "https://www.googleapis.com/oauth2/v2/userinfo",
      {
        headers: { Authorization: `Bearer ${accessToken}` },
      },
    );
    return JSON.stringify(await response.json());
  },
  name: "get-profile",
});
```

### Available Providers

<CodeGroup>
  ```typescript Google theme={null}
  import { GoogleProvider } from "fastmcp";

  const server = new FastMCP({
    auth: new GoogleProvider({
      baseUrl: "https://your-server.com",
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      scopes: ["openid", "profile", "email"],
    }),
    name: "My Server",
    version: "1.0.0",
  });
  ```

  ```typescript GitHub theme={null}
  import { GitHubProvider } from "fastmcp";

  const server = new FastMCP({
    auth: new GitHubProvider({
      baseUrl: "https://your-server.com",
      clientId: process.env.GITHUB_CLIENT_ID!,
      clientSecret: process.env.GITHUB_CLIENT_SECRET!,
      scopes: ["read:user", "user:email"],
    }),
    name: "My Server",
    version: "1.0.0",
  });
  ```

  ```typescript Azure theme={null}
  import { AzureProvider } from "fastmcp";

  const server = new FastMCP({
    auth: new AzureProvider({
      baseUrl: "https://your-server.com",
      clientId: process.env.AZURE_CLIENT_ID!,
      clientSecret: process.env.AZURE_CLIENT_SECRET!,
      tenantId: "common",
    }),
    name: "My Server",
    version: "1.0.0",
  });
  ```

  ```typescript Custom Provider theme={null}
  import { OAuthProvider } from "fastmcp";

  const server = new FastMCP({
    auth: new OAuthProvider({
      authorizationEndpoint: process.env.OAUTH_AUTH_ENDPOINT!,
      baseUrl: "https://your-server.com",
      clientId: process.env.OAUTH_CLIENT_ID!,
      clientSecret: process.env.OAUTH_CLIENT_SECRET!,
      scopes: ["openid", "profile"],
      tokenEndpoint: process.env.OAUTH_TOKEN_ENDPOINT!,
    }),
    name: "My Server",
    version: "1.0.0",
  });
  ```
</CodeGroup>

## Tool Authorization

Control which tools are available to authenticated users using the `canAccess` property with built-in helper functions:

### Require Authentication

```typescript theme={null}
import { requireAuth } from "fastmcp";

server.addTool({
  canAccess: requireAuth, // Only authenticated users
  name: "user-tool",
  execute: async () => "Authenticated!",
});
```

### Require Specific Scopes

```typescript theme={null}
import { requireScopes } from "fastmcp";

server.addTool({
  canAccess: requireScopes("read:user", "write:data"),
  name: "scoped-tool",
  execute: async () => "Access granted!",
});
```

### Require Specific Role

```typescript theme={null}
import { requireRole } from "fastmcp";

server.addTool({
  canAccess: requireRole("admin"),
  name: "admin-tool",
  execute: async () => "Welcome, admin!",
});
```

### Combine Requirements

<CodeGroup>
  ```typescript AND Logic theme={null}
  import { requireAll, requireAuth, requireRole } from "fastmcp";

  server.addTool({
    canAccess: requireAll(requireAuth, requireRole("admin")),
    name: "admin-only",
    execute: async () => "Full access!",
  });
  ```

  ```typescript OR Logic theme={null}
  import { requireAny, requireRole } from "fastmcp";

  server.addTool({
    canAccess: requireAny(requireRole("admin"), requireRole("moderator")),
    name: "staff-tool",
    execute: async () => "Staff access!",
  });
  ```

  ```typescript Custom Logic theme={null}
  server.addTool({
    name: "custom-auth-tool",
    canAccess: (auth) =>
      auth?.role === "admin" && auth?.department === "engineering",
    execute: async () => "Access granted!",
  });
  ```
</CodeGroup>

## Access Session Data

Use `getAuthSession` for type-safe access to the OAuth session in your tool execute functions:

```typescript theme={null}
import { getAuthSession, GoogleSession } from "fastmcp";

server.addTool({
  canAccess: requireAuth,
  name: "get-profile",
  execute: async (_args, { session }) => {
    // Type-safe destructuring (throws if not authenticated)
    const { accessToken } = getAuthSession(session);

    // Or with provider-specific typing:
    // const { accessToken } = getAuthSession<GoogleSession>(session);

    const response = await fetch("https://api.example.com/user", {
      headers: { Authorization: `Bearer ${accessToken}` },
    });
    return JSON.stringify(await response.json());
  },
});
```

<Note>
  You can also access `session.accessToken` directly, but you must handle the case where `session` is undefined. The `getAuthSession` helper throws a clear error if the session is not authenticated, making it safer when used with `canAccess: requireAuth`.
</Note>

## Custom Authentication

For non-OAuth scenarios like API keys or custom tokens, use the `authenticate` option:

```typescript theme={null}
const server = new FastMCP({
  name: "My Server",
  version: "1.0.0",
  authenticate: (request) => {
    const apiKey = request.headers["x-api-key"];

    if (apiKey !== "123") {
      throw new Response(null, {
        status: 401,
        statusText: "Unauthorized",
      });
    }

    return { id: 1, role: "user" };
  },
});

server.addTool({
  name: "sayHello",
  execute: async (args, { session }) => {
    return `Hello, ${session.id}!`;
  },
});
```

## OAuth Discovery Endpoints

FastMCP supports OAuth discovery endpoints for direct integration with OAuth providers, supporting both **MCP Specification 2025-03-26** and **MCP Specification 2025-06-18**:

```typescript theme={null}
import { FastMCP, DiscoveryDocumentCache } from "fastmcp";
import { buildGetJwks } from "get-jwks";
import fastJwt from "fast-jwt";

const discoveryCache = new DiscoveryDocumentCache({
  ttl: 3600000, // Cache for 1 hour
});

const server = new FastMCP({
  name: "My Server",
  version: "1.0.0",
  oauth: {
    enabled: true,
    authorizationServer: {
      issuer: "https://auth.example.com",
      authorizationEndpoint: "https://auth.example.com/oauth/authorize",
      tokenEndpoint: "https://auth.example.com/oauth/token",
      jwksUri: "https://auth.example.com/.well-known/jwks.json",
      responseTypesSupported: ["code"],
    },
    protectedResource: {
      resource: "mcp://my-server",
      authorizationServers: ["https://auth.example.com"],
    },
  },
  authenticate: async (request) => {
    const authHeader = request.headers.authorization;

    if (!authHeader?.startsWith("Bearer ")) {
      throw new Response(null, {
        status: 401,
        statusText: "Missing or invalid authorization header",
      });
    }

    const token = authHeader.slice(7);

    try {
      const config = (await discoveryCache.get(
        "https://auth.example.com/.well-known/openid-configuration"
      )) as {
        jwks_uri: string;
        issuer: string;
      };

      const getJwks = buildGetJwks({
        jwksUrl: config.jwks_uri,
        cache: true,
        rateLimit: true,
      });

      const verify = fastJwt.createVerifier({
        key: async (token) => {
          const { header } = fastJwt.decode(token, { complete: true });
          const jwk = await getJwks.getJwk({
            kid: header.kid,
            alg: header.alg,
          });
          return jwk;
        },
        algorithms: ["RS256", "ES256"],
        issuer: config.issuer,
        audience: "mcp://my-server",
      });

      const payload = await verify(token);

      return {
        userId: payload.sub,
        scope: payload.scope,
        email: payload.email,
      };
    } catch (error) {
      throw new Response(null, {
        status: 401,
        statusText: "Invalid OAuth token",
      });
    }
  },
});
```

This configuration automatically exposes OAuth discovery endpoints:

* `/.well-known/oauth-authorization-server` - Authorization server metadata (RFC 8414)
* `/.well-known/oauth-protected-resource` - Protected resource metadata (RFC 9728)
* `/.well-known/oauth-protected-resource<endpoint>` - Protected resource metadata at sub-path

## Helper Functions Reference

| Function                   | Description                     | Example                                                                 |
| -------------------------- | ------------------------------- | ----------------------------------------------------------------------- |
| `requireAuth`              | Requires any authenticated user | `canAccess: requireAuth`                                                |
| `requireScopes(...scopes)` | Requires specific OAuth scopes  | `canAccess: requireScopes("read:user")`                                 |
| `requireRole(...roles)`    | Requires specific role          | `canAccess: requireRole("admin")`                                       |
| `requireAll(...checks)`    | Combines checks with AND logic  | `canAccess: requireAll(requireAuth, requireRole("admin"))`              |
| `requireAny(...checks)`    | Combines checks with OR logic   | `canAccess: requireAny(requireRole("admin"), requireRole("moderator"))` |
| `getAuthSession(session)`  | Type-safe session extraction    | `const { accessToken } = getAuthSession(session)`                       |

## Next Steps

<CardGroup cols={2}>
  <Card title="OAuth Proxy" icon="shield-halved" href="/features/oauth-proxy">
    Learn about the built-in OAuth Proxy with DCR, PKCE, and token swap
  </Card>

  <Card title="Custom Routes" icon="route" href="/features/custom-routes">
    Add authenticated custom HTTP routes to your server
  </Card>
</CardGroup>
