Skip to main content
OAuth lets your users connect their own accounts to your app. Corsair handles state signing, token exchange, and encrypted storage — you wire up the connect flow. Corsair supports two connect modes: This page covers manual mode in production. The flow uses client.connect.createLink() — one API for minting connect URLs. Corsair handles CSRF protection via HMAC-signed state, token encryption, and automatic refresh before API calls.
1

Configure your app

Add OAuth plugins, database, kek, and manual connect config. Mount the management handler so createLink is available over HTTP.
corsair.ts
app/api/corsair/[[...path]]/route.ts
Store your OAuth app credentials once:
OAuth is supported by plugins like Gmail, Google Calendar, Notion, Spotify, Dropbox, and others.
2
When a user clicks “Connect”, call createLink on your authenticated backend. Read tenantId from your session — never from the request body alone in production.
This step must be authenticated. If left open, anyone could mint connect links for arbitrary tenants. Always resolve tenantId from your session before calling createLink.
app/actions/connect.ts
connect-button.tsx
createLink returns { connectUrl, expiresAt }. Redirect the user’s browser to connectUrl. The signed state is already embedded in that URL.
3

The connect page

connectUrl points at your manual.baseUrl with ?state=…. This page verifies the state and redirects the user to the provider’s OAuth screen.
app/connect/page.tsx
4

The callback route

After the user approves, the provider redirects to manual.redirectUri with ?code= and ?state=. Exchange the code for tokens and store them encrypted for the tenant.
Corsair re-verifies the HMAC-signed state inside oauthCallback. The tenantId and plugin are extracted from state — do not trust query parameters for tenant identity.
app/api/oauth/callback/route.ts

Environment variables


Security checklist

createLink is behind authentication — tenantId comes from your session, not user input
manual.baseUrl and manual.redirectUri use your HTTPS domain in production
The connect page calls resolve(state) — Corsair verifies the HMAC before returning the OAuth URL
The callback calls oauthCallback({ code, state }) — Corsair re-verifies state and exchanges the code
All user-controlled values are HTML-escaped before rendering error pages
OAuth redirect URI registered with the provider matches manual.redirectUri exactly

Hub mode

If you prefer Corsair to host the connect UI, use hub: { ... } instead of manual. You only mint a link and mount a delivery endpoint — no connect page or callback route needed. Hub stores none of your credentials; tokens still land in your database. See Hub overview for the model, Manual or Hub for a side-by-side, and Connect / OAuth for the API.

What’s next

Connect / OAuth

Unified createLink API — hub and manual modes.

OAuth 2.0 Concepts

How Corsair encrypts and stores tokens, and handles automatic refresh.

Multi-Tenancy

Scoping every API call and database query per user with withTenant().

Gmail Plugin

Set up Gmail OAuth — a common starting point.