- OAuth 2.1 + PKCE — for third-party and community applications acting on behalf of a Michelangelo user. Your app registers itself (no manual signup), sends the user through a consent screen, and receives a token scoped to that user.
- Bearer JWT (first-party) — for the official Michelangelo app and first-party clients, which present the user’s existing session token.
OAuth 2.1 for Community Apps
Michelangelo’s identity provider is a standard OAuth 2.1 authorization server with PKCE enforced and Dynamic Client Registration enabled — your app registers itself programmatically, with no manual credential request.Every endpoint you need lives under
api.michelangelo.land — auth, OAuth, and data APIs. The infrastructure behind it is an implementation detail: your integration only ever talks to one domain.Endpoints
The discovery document is the authoritative source — your client should resolve endpoints from it rather than hard-coding them.
1. Register your client
client_id. Public clients authenticate at the token endpoint with token_endpoint_auth_method: "none" plus PKCE — there is no client secret.
Native clients with loopback redirects (RFC 8252 — MCP clients like Kimi Code or Claude Code listening on
http://127.0.0.1:<ephemeral-port>) work transparently: the platform bridges ephemeral loopback ports through api.michelangelo.land, so you don’t need to register fixed ports. Just register your loopback URI via DCR and use whatever port you listen on — the flow completes normally.2. Build the authorization URL (PKCE S256)
Generate a high-entropy randomcode_verifier (43–128 chars), then compute:
S256 method is mandatory; plain challenges are rejected.
3. User consent
The user authenticates and approves (or denies) your app’s request on Michelangelo’s consent screen, hosted athttps://api.michelangelo.land/oauth/consent. On approval, the browser is redirected back to your redirect_uri with an authorization code.
4. Exchange the code for a token
access_token (a JWT signed with ES256) and a refresh_token. OAuth tokens carry a client_id claim identifying your application — the API uses it for per-client quota and auditing.
5. Call the API and verify
whoami returns 200, your OAuth flow works end to end.
Signing In on the Consent Screen
When an OAuth flow sends you to Michelangelo’s consent screen, sign in with any method linked to your Michelangelo account:- Google or GitHub — one click, the same providers as the app;
- Email code — a 6-digit code sent to your account email. This works for every account, including Sign in with Apple users, who typically have no password;
- Email + password — if you set one up.
Tokens for Personal Use and Scripts
If you want to call the API yourself (scripts, curl, your own service), you don’t copy a token from a settings page — you run the same OAuth flow above with a client you register via DCR (step 1). Register once with your ownredirect_uri (a http://localhost:PORT/callback URI works for local scripts), complete the flow in your browser, and use the resulting access_token and refresh_token. The token identifies both you (user_id) and your client (client_id) — and it works with the MCP server too.
First-Party Bearer Tokens
The official Michelangelo app authenticates users directly and calls the API with the resulting session JWT (Authorization: Bearer <session_jwt>). These tokens are validated the same way (JWKS) but carry no client_id. This mode is reserved for the official app — for anything else, including personal scripts, use the OAuth flow above.
Errors
Authentication failures return a consistent shape:Beta Notes
The OAuth authorization server is in public beta (Supabase OAuth 2.1). The flow above is verified end to end — DCR, PKCE, consent, token exchange — but check the community channels for GA status and any changes before a production launch.
Next Steps
Async Jobs
Learn the job lifecycle before your first generation.
Examples
Complete curl workflows with a real token.

