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

# Authorization

> Control access to MCP tools and resources using CEL-based authorization rules.

Agentgateway supports fine-grained authorization policies for both MCP and HTTP traffic. Authorization rules use [Common Expression Language (CEL)](https://cel.dev/) — a compact, safe expression language designed for policy evaluation.

## MCP authorization

The `mcpAuthorization` policy on an MCP route defines which users can access which tools and resources. Rules are evaluated against the authenticated JWT subject and claims.

Tools and resources that a user is not permitted to access are automatically filtered out of the `tools/list` and `resources/list` responses. If a user attempts to call a denied tool directly, the call is also rejected.

### Configuration

Here is the full authorization example config from `examples/authorization/config.yaml`:

```yaml config.yaml theme={null}
# yaml-language-server: $schema=https://agentgateway.dev/schema/config
binds:
- port: 3000
  listeners:
  - routes:
    - policies:
        cors:
          allowOrigins:
          - "*"
          allowHeaders:
          - "*"
          exposeHeaders:
          - "Mcp-Session-Id"
        backendAuth:
          passthrough: {}
        jwtAuth:
          issuer: agentgateway.dev
          audiences: [test.agentgateway.dev]
          jwks:
            # Relative to the folder the binary runs from, not the config file
            file: ./manifests/jwt/pub-key
        mcpAuthorization:
          rules:
          # Allow anyone to call 'echo'
          - 'mcp.tool.name == "echo"'
          # Only the test-user can call 'add'
          - 'jwt.sub == "test-user" && mcp.tool.name == "add"'
          # Any authenticated user with the claim `nested.key == value` can access 'printEnv'
          - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"'
      backends:
      - mcp:
          targets:
          - name: mcp2
            mcp:
              host: http://localhost:3001/mcp
```

`jwtAuth` handles authentication (token validation), while `mcpAuthorization` handles authorization (what a validated user may do). Both are required for JWT-claim-based rules.

### CEL rule syntax

Each rule in `mcpAuthorization.rules` is a CEL expression that evaluates to a boolean. A request is **permitted** if any rule evaluates to `true`.

<AccordionGroup>
  <Accordion title="Allow a tool to all authenticated users">
    ```yaml theme={null}
    rules:
    - 'mcp.tool.name == "echo"'
    ```

    Any authenticated user may call the `echo` tool. No JWT claim check is required.
  </Accordion>

  <Accordion title="Restrict a tool to a specific user">
    ```yaml theme={null}
    rules:
    - 'jwt.sub == "test-user" && mcp.tool.name == "add"'
    ```

    Only the user whose JWT `sub` claim is `test-user` can call `add`. All other users see this tool filtered from their tool list.
  </Accordion>

  <Accordion title="Allow access based on a JWT claim value">
    ```yaml theme={null}
    rules:
    - 'mcp.tool.name == "printEnv" && jwt.nested.key == "value"'
    ```

    Any authenticated user whose token contains the nested claim `nested.key == "value"` may call `printEnv`. Nested JWT claims are accessed with dot notation: `jwt.<field>.<subfield>`.
  </Accordion>

  <Accordion title="Allow a list of tools">
    ```yaml theme={null}
    rules:
    - 'mcp.tool.name == "echo"'
    - 'mcp.tool.name == "add"'
    - 'mcp.tool.name == "time"'
    ```

    Add one rule per tool to allow access to a specific set of tools for all users.
  </Accordion>
</AccordionGroup>

### Available CEL fields

| Field                 | Type   | Description                                 |
| --------------------- | ------ | ------------------------------------------- |
| `mcp.tool.name`       | string | Name of the MCP tool being called           |
| `jwt.sub`             | string | Subject claim from the JWT                  |
| `jwt.<claim>`         | any    | Any top-level JWT claim                     |
| `jwt.<claim>.<field>` | any    | Nested JWT claim accessed with dot notation |

### Rule evaluation

Rules are evaluated in order. A request is permitted as soon as any rule evaluates to `true`. If no rule matches, the request is denied.

<Note>
  When `mcpAuthorization` is configured, tools are filtered proactively. Clients see only the tools they are permitted to access in `tools/list` responses — they cannot discover tools they do not have access to.
</Note>

## Testing authorization rules

<Steps>
  <Step title="Start the gateway">
    ```bash theme={null}
    cargo run -- -f examples/authorization/config.yaml
    ```
  </Step>

  <Step title="Connect with a restricted token">
    Use the example token `manifests/jwt/pub-key/example2.key`. This token has `sub: test-user` and no extra claims.

    Paste the token into MCP Inspector under **Authentication > Bearer Token** and run **List Tools**.

    You should see only `echo` and `add` — the two tools accessible to `test-user` without additional claims.
  </Step>

  <Step title="Connect with a token that has custom claims">
    Use `manifests/jwt/pub-key/example1.key`. This token has `sub: test-user` and the following claims:

    ```json theme={null}
    {
      "field1": "value1",
      "nested": {
        "key": "value"
      },
      "list": ["apple", "banana"]
    }
    ```

    Run **List Tools** again. You should now also see `printEnv`, because the third rule (`jwt.nested.key == "value"`) now matches.

    <Tip>
      MCP Inspector caches the tools list. Re-run **List Tools** explicitly after switching tokens to see the updated results.
    </Tip>
  </Step>
</Steps>

## HTTP authorization

For plain HTTP routes, use the `authorization` policy instead of `mcpAuthorization`. The syntax is the same — a list of CEL rules — but the available fields reflect HTTP request context.

```yaml theme={null}
policies:
  authorization:
    rules:
    - 'jwt.sub == "admin"'
```

<Note>
  HTTP authorization rules apply to all traffic on the route, not just MCP protocol calls. Use `mcpAuthorization` specifically when the backend is an MCP server.
</Note>

## Combining authentication and authorization

Authentication (`jwtAuth` or `mcpAuthentication`) must be configured alongside authorization to make JWT claims available in rules. The typical pattern is:

```yaml theme={null}
policies:
  # 1. Validate the token and extract claims
  jwtAuth:
    issuer: agentgateway.dev
    audiences: [test.agentgateway.dev]
    jwks:
      file: ./manifests/jwt/pub-key
  # 2. Enforce access rules using those claims
  mcpAuthorization:
    rules:
    - 'mcp.tool.name == "echo"'
    - 'jwt.sub == "test-user" && mcp.tool.name == "add"'
```

See the [Authentication guide](/guides/authentication) for details on configuring JWT validation.
