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

# Quickstart: Platform Operator

> Protect your API so only trusted, in-scope agents reach your code.

This guide takes you from an unprotected API to one where every request is checked for a valid MudraID token and the right scope — before it reaches your handlers. The integration is two lines plus a config file.

**By the end** your routes will reject unauthenticated or under-scoped agents automatically, with no auth code in your handlers.

## Before you start

* A MudraID account, with your platform registered (step 1 below).
* A FastAPI or Starlette application.
* Python 3.10 or newer.

## 1. Register your platform

Sign in to the MudraID portal, create a platform, and verify you own its domain (a DNS TXT record). Then define the scopes your routes will require — the permissions you'll hand out to agents, like `items:read` and `items:write`.

You'll get a `platform_id`. Keep it; it ties tokens to your platform.

## 2. Get your scopes file

The portal generates a `mudraid_scopes.yaml` for your platform. It maps each route to one of three outcomes: a required scope, an open `public` route, or a hidden `skip` route.

```yaml theme={null}
platform_id: 4f8e9c1d-2b4f-5e6a-7b8c-9d0e1f2a3b4c
version: 1
routes:
  - method: GET
    path: /health
    public: true            # no token needed
  - method: GET
    path: /api/v1/items
    scope: items:read
  - method: POST
    path: /api/v1/items
    scope: items:write
```

Drop it in your project root, next to where your app starts.

## 3. Install the middleware

```bash theme={null}
pip install mudraid-middleware
```

<Note>
  During the v0.1 alpha the package isn't on PyPI yet. Install from source: `pip install -e sdks/mudraid-middleware-python` from the repo root.
</Note>

## 4. Add the middleware

```python theme={null}
from fastapi import FastAPI
from mudraid_middleware import MudraIDMiddleware

app = FastAPI()
app.add_middleware(MudraIDMiddleware)

@app.get("/api/v1/items")
def list_items():
    return {"items": [...]}   # runs only after the token and scope checks pass
```

That's the whole change. Your existing route handlers stay exactly as they are — no decorators, no auth parameters, no per-route checks. The middleware enforces `mudraid_scopes.yaml` in front of all of them.

## Verify it works

With the stack running, try the routes by hand:

```bash theme={null}
# Public route — no token needed
curl https://your-api.example.com/health
# → 200 {"status":"ok"}

# Scoped route with no token — rejected
curl https://your-api.example.com/api/v1/items
# → 401 {"error_code":"MISSING_TOKEN", ...}
```

A registered agent calling the same scoped route with a valid, in-scope token gets through to your handler. That's the loop working.

## What just happened

For every incoming request, the middleware now:

1. **Matches** the method and path against your YAML.
2. **Lets public routes through** untouched.
3. **Reads** the `Authorization: Bearer` token.
4. **Verifies** its signature, issuer, audience, and timing against MudraID's published keys — locally, no per-request callback.
5. **Checks** the route's required scope is present in the token.
6. **Forwards** to your handler, or returns a structured `{"error_code", "message"}` error.

Your code only ever runs for requests that are authenticated and in scope.

## Troubleshooting

| What you see                               | What it means                                               | Fix                                                          |
| ------------------------------------------ | ----------------------------------------------------------- | ------------------------------------------------------------ |
| Every authed call returns `WRONG_AUDIENCE` | Your YAML's `platform_id` doesn't match what MudraID issued | Re-export `mudraid_scopes.yaml` from the portal and redeploy |
| `MIDDLEWARE_NOT_READY` (500)               | The YAML couldn't be loaded or parsed                       | Fix the file; the next request recovers without a restart    |
| `JWKS_UNAVAILABLE` (500)                   | The middleware couldn't reach MudraID's keys                | Transient network issue to MudraID; check connectivity       |
| A route unexpectedly 404s                  | It has no rule in the YAML, or is marked `skip`             | Add a rule for it                                            |

Full table: [Interpret verification error codes](/guides/platform-operator/error-codes).

## Next steps

<CardGroup cols={2}>
  <Card title="Define scopes" href="/guides/platform-operator/define-scopes">
    Design the permissions your API exposes.
  </Card>

  <Card title="Manage the scopes lifecycle" href="/guides/platform-operator/scopes-lifecycle">
    How changes roll out safely.
  </Card>

  <Card title="Error responses" href="/sdks/middleware/error-responses">
    The stable error\_code contract.
  </Card>

  <Card title="Survive key rotation" href="/guides/platform-operator/key-rotation">
    Why rotation needs no action from you.
  </Card>
</CardGroup>
