Skip to content
Clean Minimal API
Lean Mean Clean Apps

Five templates, one search box. Everything in the docs is in here, including the bits we hoped you'd skim.

Try one of these

Results say which template they came from, so you won't end up reading about Lambda when you wanted GraphQL. Again.

Secure the API

Out of the box the API runs wide open. Every movie, author and review endpoint asks for authorization, but with no authority configured the default policy says yes to everyone. That’s lovely on a laptop and less lovely in production, so here’s how to close the door.

  1. Tell the API who issues tokens and who they’re for. Either bake it in when you create the solution:

    Terminal window
    dotnet new cleanminimalapi --name Acme.Movies \
    --authority https://login.example.com --audience https://movies.example.com

    Or set it on a solution you already have, in appsettings.json or as environment variables:

    Terminal window
    Authentication__Authority=https://login.example.com
    Authentication__Audience=https://movies.example.com
  2. Get a token from the authority for that audience, and send it.

    Terminal window
    curl "http://localhost:5032/api/movies" -H "Authorization: Bearer eyJhbGciOi..."

    Without a token, or with one from the wrong issuer or for the wrong audience, the API answers 401 Unauthorized.

  • The movie, author and review endpoints need a valid token. GET /api/version, /health/live and /health/ready stay open, so load balancers and curious humans can still check the lights are on.
  • The OpenAPI document gains a Bearer security scheme, and Scalar shows an Auth box where you can paste a token and keep clicking Send.
  • Tokens are validated against the authority’s published keys, so there’s no secret to store and nothing to rotate on your side.

AuthenticationSettings reads the Authentication section. When the authority is set, the API registers the JWT bearer handler and the normal authorization services. When it isn’t, it registers a default policy that passes every request. Every endpoint group calls RequireAuthorization(), and the version endpoint opts out with AllowAnonymous(). The same attributes work either way, which is why turning authentication on doesn’t touch a single endpoint.

Scopes, roles and per-endpoint policies are a short step from here: add policies to AddAuthorization and ask for them with RequireAuthorization("policy"). Which claims to check depends entirely on your identity provider, so the template stops at the door and lets you decide who gets past it.