Skip to main content
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.
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

pip install mudraid-middleware
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.

4. Add the middleware

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:
# 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 seeWhat it meansFix
Every authed call returns WRONG_AUDIENCEYour YAML’s platform_id doesn’t match what MudraID issuedRe-export mudraid_scopes.yaml from the portal and redeploy
MIDDLEWARE_NOT_READY (500)The YAML couldn’t be loaded or parsedFix the file; the next request recovers without a restart
JWKS_UNAVAILABLE (500)The middleware couldn’t reach MudraID’s keysTransient network issue to MudraID; check connectivity
A route unexpectedly 404sIt has no rule in the YAML, or is marked skipAdd a rule for it
Full table: Interpret verification error codes.

Next steps

Define scopes

Design the permissions your API exposes.

Manage the scopes lifecycle

How changes roll out safely.

Error responses

The stable error_code contract.

Survive key rotation

Why rotation needs no action from you.