AuthServer
Todo Sample
Run the SqlOS AuthPage email OTP sample with simple FGA, protected-resource metadata, and public-client onboarding paths.
The Todo sample is the canonical "ship hosted AuthPage plus simple FGA fast" walkthrough.
It keeps the model intentionally small:
TodoSample__EnableEmailOtp=truetodo-localtodo-cli device-flow client and runnable .NET CLICIMD and optional DCRACS_COMMUNICATION_SERVICE_NAME=<acs-communication-service-name>
AZURE_RESOURCE_GROUP=<resource-group>
ACS_FROM_ADDRESS=no-reply@example.com
ACS_CONN=$(az communication list-key \
--name "$ACS_COMMUNICATION_SERVICE_NAME" \
--resource-group "$AZURE_RESOURCE_GROUP" \
--query primaryConnectionString \
-o tsv)
TodoSample__EnableEmailOtp=true \
SqlOS__EmailOtp__AzureCommunicationServicesConnectionString="$ACS_CONN" \
SqlOS__EmailOtp__FromAddress="$ACS_FROM_ADDRESS" \
dotnet run --project examples/SqlOS.Todo.AppHost/SqlOS.Todo.AppHost.csprojOpen http://localhost:5080/.
If you already ran an older version of the Todo sample, reset the Todo sample SQL database or persistent volume once before rerunning. Existing rows are not backfilled into the FGA graph.
The default path is a seeded browser client called todo-web.
Use the landing page to:
The Todo app only starts the OAuth request. SqlOS AuthPage owns credential collection, OTP delivery, OTP verification, user creation on signup, and the redirect back with an authorization code.
The sample also seeds email branding with SeedAuthEmails(...), so the default OTP emails use the Todo application name and colors without a custom template.
The Todo sample now models every todo as an FGA resource.
Hierarchy:
roottenant::{userId}todo::{todoId}Role and permission matrix:
tenant_ownerTENANT_CREATE_TODOTODO_READTODO_WRITEThe app grants tenant_owner on the user tenant node. Child todo resources inherit access from that node, so the sample can:
GetAuthorizationFilterAsync<TodoItem>(...)That keeps the controller code small while still populating the FGA dashboard with a real tree.
The sample API protects /api/todos with audience-aware token validation.
It also exposes:
GET /.well-known/oauth-protected-resourceAnd when a caller presents no token or the wrong audience, the API returns:
401 UnauthorizedWWW-Authenticate header with resource_metadataThat means the sample demonstrates both sides at once:
For localhost development, use the seeded client:
client_id: todo-localhttp://localhost:3100/oauth/callbackThis is the easiest local loop before you publish the sample on a stable HTTPS origin.
For the Emcy-hosted local Todo MCP flow, use the additional seeded client:
client_id: todo-mcp-localhttp://localhost:5150/api/v1/hosted-mcp/todo-local/oauth/callbackThis client exists so Emcy can broker the downstream Todo authorization flow while the Todo API itself keeps the same OAuth and audience behavior.
The sample also seeds a public CLI client:
client_id: todo-cliRun the AppHost, then in another terminal:
dotnet run --project examples/SqlOS.Todo.Cli -- login
dotnet run --project examples/SqlOS.Todo.Cli -- whoami
dotnet run --project examples/SqlOS.Todo.Cli -- add "Ship device OAuth"
dotnet run --project examples/SqlOS.Todo.Cli -- list
dotnet run --project examples/SqlOS.Todo.Cli -- toggle <todo-id>login prints and opens verification_uri_complete. Sign in through SqlOS AuthPage, approve the CLI request, then return to the terminal. Tokens are stored under ~/.sqlos/todo-cli/tokens.json for the demo.
More detail: CLI OAuth.
Once the sample is reachable on public HTTPS, you can use both public-client onboarding paths.
The sample publishes a metadata document at:
/clients/portable-client.jsonThat document is useful as:
client_id metadata documentDCR stays off by default. Enable it when you need compatibility clients:
TodoSample__EnableDcr=trueThen use:
POST /sqlos/auth/registerThis is the compatibility path for clients that still expect dynamic client registration.
Use the Todo sample when your question is:
"How do I ship hosted auth, simple FGA, and protected-resource metadata with very little app code?"
Use the broader Example stack when your question is:
"How do I explore all of SqlOS, including OIDC, SAML, org workflows, and richer multi-tenant FGA?"