Skip to main content
Turn Prelude Auth into your own OAuth 2.0 authorization server so any of your applications can sign users in against your existing Prelude Auth users — a “Sign in with us” button for your product suite. You host the login and consent screens once; every client app then runs a standard authorization-code + PKCE flow against them, with no extra identity provider to run. This is the same authorization-server machinery that powers MCP Login, pointed at your own applications instead of MCP clients.
This is not Enterprise SSO (OIDC) or social login. Those make Prelude the OAuth client of an external identity provider (Okta, Google…). Here Prelude is the authorization server, and your app is the client.

How it works

There are two sides to build, and this guide covers both:
  • The authorization frontend — the login and consent screens Prelude redirects to. Prelude drives the OAuth protocol; your UI authenticates the user and collects consent, then hands the browser back with an authorization code. This is exactly what the Prelude Dashboard does for MCP clients today.
  • The client app — the application asking users to sign in. It uses the new PrldOAuth2Client in the Web SDK to start the flow and exchange the code for a session.
A login looks like this:
1

Authorize

The client app calls PrldOAuth2Client.initiate() and redirects the browser to /v1/session/oauth/authorize with PKCE. Prelude persists the request and 302s to your login UI with an ?oauth_req=<oar_…> parameter.
2

Login

Your sign-in route reads oauth_req, authenticates the user with any method your app supports (OTP, password, passkey, social, SAML), then calls continueOAuth2(oauthReq). Prelude returns the consent URL to navigate to.
3

Consent

Your consent route fetches the pending request with getOAuth2Pending(oauthReq) to display the client name and requested scopes, then submits the user’s decision with decideOAuth2(oauthReq, approve). Prelude returns the client redirect_uri — with a one-time code and state on approval, or error=access_denied on denial.
4

Token

The browser lands back on the client app’s redirect_uri. The client calls handleCallback(), which verifies state, exchanges the code at /v1/session/oauth/token with its PKCE code_verifier, and persists the tokens so a PrldSessionClient on the same domain picks up the session.
The issued session is a child of the user’s browser session. Its scopes are the intersection of the requested scopes and the parent session’s scopes (or the parent’s full set when the client requests the prld:oauth:inherit scope). A session minted through the OAuth flow cannot itself start another OAuth flow — the chain is capped at one level.

Prerequisites

Before you start, make sure you have:
  • A Prelude account with access to Prelude Auth
  • An Application ID (appID) — see Applications
  • Your Management API key for backend calls
  • A verified custom domain, or your default ${APP_ID}.session.prelude.dev host — the authorization-server endpoints are anchored to this auth domain
  • A login UI built with the Web SDK that can host the sign-in and consent screens

Configure Prelude as your authorization server

Enable the OAuth server on your app and point it at your login UI with a single PUT. default_provider_url is the origin Prelude sends the browser to: it 302s to <default_provider_url>/sign-in from /authorize, and to <default_provider_url>/oauth/consent after login.
For first-party SSO you typically know your client apps ahead of time, so register each one explicitly instead of enabling Dynamic Client Registration. This returns the client_id (an oac_… identifier) the client app needs:
The client_name you set here is what the consent screen shows the user. See the OAuth Server Config API reference for the full configuration schema — including DCR and CIMD if you want clients to self-register, as covered in the MCP Login guide.

Build the authorization frontend

Prelude handles the OAuth protocol but hands the browser to your login UI to authenticate the user and collect consent. Build two routes at the origin you set as default_provider_url. Both use a standard Web SDK session client:
1

Sign-in route (/sign-in)

Prelude redirects here with an ?oauth_req=<oar_…> parameter. Authenticate the user with any method your app supports, then resume the flow with continueOAuth2. Prelude returns the consent URL to navigate to.
If the user already has a live session when they land here, you can skip straight to continueOAuth2.
2

Consent route (/oauth/consent)

Prelude redirects here with the same ?oauth_req=. This route requires a signed-in session — if there is none, send the user to /sign-in?oauth_req=<oar_…> first, preserving the parameter. Fetch the pending request to render consent, then submit the decision.
The continue, pending, and decision calls run against the user’s live session and are bound to it with DPoP. The Web SDK manages the session and the DPoP proof for you — you do not construct these requests by hand.

Build the client app

The application signing users in acts as a public OAuth client. The Web SDK ships PrldOAuth2Client for exactly this: initiate() builds the authorize URL (generating and storing the PKCE code_verifier and CSRF state), and handleCallback() validates the returned state, exchanges the code, and persists the session.
1

Start the flow

Call initiate() and send the browser to the returned authorizationURL. The PKCE verifier and state are persisted for you; initiate() does not navigate, so you do it.
initiate() also accepts per-call { scopes, state } if you want to override the constructor defaults or supply your own state.
2

Handle the callback

At your redirectURI, pass the query parameters to handleCallback(). It throws PrldErrors.OAuth2 on a provider error, a state mismatch, or a failed exchange.
handleCallback() returns the raw token result ({ accessToken, tokenType, expiresIn, refreshToken?, scope? }) if you want to inspect it, but you rarely need to — it persists the session for you, so continue with a PrldSessionClient as you would after any other login.

What’s next?

Web SDK

Build the sign-in and consent screens your login UI hosts.

MCP Login

The same authorization server, for MCP clients — including DCR and CIMD self-registration.

OAuth Server API

The raw authorize, token, continue, pending, and decision endpoints.

Groups & scopes

Control which scopes a session — and its OAuth children — can carry.