install
Add Sign in with dots to any app.
dots.id is an OAuth identity provider for the dots ecosystem. Use it as your only sign-in method, or add it beside an existing auth stack as a connected identity. Supabase backs the OAuth server, while Privy, Vercel, and Better Auth-compatible email flows provide the proofs that make a dots.id portable.
quick start
- 1. Create an OAuth app in the dots dashboard.
- 2. Add your redirect URI and allowed scopes.
- 3. Wire authorize, callback, token exchange, and userinfo.
- 4. Store the returned dots subject as the linked dots.id.
model
How dots auth is layered
Supabase is the main dots auth server and system of record. The other providers are upstream proofs or compatibility layers that feed the dots profile before OAuth shares it with ecosystem apps.
Supabase
The dots auth server database. It owns profiles, OAuth clients, consent, issued tokens, username state, and synced identity claims.
Privy
The primary user session and wallet/social login layer used by dots.id before a profile can authorize ecosystem apps.
Vercel
A developer/platform proof. Users connect Vercel during dots.id creation so apps can trust developer identity context.
Better Auth + Resend
The email compatibility and notification layer. dots uses verified backup/email channels for app notifications, recovery, and syncing email identity into apps that use Better Auth.
Issuance flow
A user connects an e-wallet, signs in with Vercel, verifies an email through the Resend-backed flow, and subscribes to vibe through Stripe. Supabase stores the completed dots profile and the OAuth server uses that profile to issue scoped tokens to apps.
verification
What a dots.id verifies
e-wallet
Privy sign-in plus an embedded wallet or connected wallet.
Vercel sign-in
A verified Vercel account as the developer/platform proof.
A verified contact email for account info, notifications, and recovery.
Subscribe to vibe
A Stripe subscription that includes #color and unlocks pute.me.
vibe
What the subscription unlocks
The fourth verification step is a vibe subscription. Once active, dots can hand the user into pute.me, where the dots OAuth identity is linked to a Universal Compute Wallet. That wallet connection is what apps use for compute balance, spend caps, and wallet-backed access.
provider
Provider settings
issuer
https://dots.id
response type
code + PKCE
/api/oauth/authorizeStart the OAuth code flow and ask for user consent.
/api/oauth/tokenExchange a code or refresh token for dots tokens.
/api/oauth/userinfoRead the scoped dots.id profile for the signed-in user.
/api/oauth/revokeRevoke an app's token when access should end.
/api/oauth/introspectValidate token state from trusted server code.
env
Add project variables
Register your app at the developer dashboard, then add the generated values to your project. Public or native clients should use PKCE and avoid a client secret.
DOTS_CLIENT_ID="dots_client_..."
DOTS_CLIENT_SECRET="dots_secret_..."
DOTS_REDIRECT_URI="https://yourapp.com/api/auth/dots/callback"
DOTS_ISSUER="https://dots.id"flow
Wire the OAuth flow
1. Start sign-in
const params = new URLSearchParams({
client_id: process.env.DOTS_CLIENT_ID!,
redirect_uri: process.env.DOTS_REDIRECT_URI!,
response_type: "code",
scope: "openid profile email wallet",
state,
code_challenge: challenge,
code_challenge_method: "S256",
});
redirect(`${process.env.DOTS_ISSUER}/api/oauth/authorize?${params}`);2. Exchange the callback code
const tokenRes = await fetch(`${process.env.DOTS_ISSUER}/api/oauth/token`, {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
authorization: `Basic ${Buffer.from(
`${process.env.DOTS_CLIENT_ID}:${process.env.DOTS_CLIENT_SECRET}`
).toString("base64")}`,
},
body: new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: process.env.DOTS_REDIRECT_URI!,
code_verifier: verifier,
}),
});3. Read scoped dots.id claims
const profileRes = await fetch(`${process.env.DOTS_ISSUER}/api/oauth/userinfo`, {
headers: {
authorization: `Bearer ${accessToken}`,
},
});
const dotsProfile = await profileRes.json();modes
Use dots as primary or connected auth
Only provider
Use the dots subject as your app user ID. Every account signs in through dots.id and inherits the same identity, wallet, email, and ecosystem permissions.
Optional provider
Keep your existing auth provider and attach dots.id as a linked account. Use this when dots powers sync, reputation, groups, or ecosystem features without replacing your login.
better auth
Stay compatible with Better Auth
dots should be installable anywhere Better Auth can accept a custom OAuth provider. In that setup, Better Auth owns the local app session while dots.id remains the external identity, sync, notification, and ecosystem authorization layer.
What syncs
The app stores the dots subject, username, verified email claims, wallet, and any requested social claims. Resend-powered email is used for dots notifications, recovery, and syncing email state into apps that already model users through Better Auth.
// Better Auth custom OAuth provider shape
{
id: "dots",
name: "dots.id",
issuer: "https://dots.id",
authorizationEndpoint: "https://dots.id/api/oauth/authorize",
tokenEndpoint: "https://dots.id/api/oauth/token",
userInfoEndpoint: "https://dots.id/api/oauth/userinfo",
scopes: ["openid", "profile", "email", "wallet"],
}scopes
Choose what your app can sync
openidRequired OIDC identity scope.
profileUsername and basic dots.id profile information.
emailVerified email claims.
walletConnected wallet address.
social:twitterConnected Twitter/X username.
social:instagramConnected Instagram username.
social:googleConnected Google account info.
data:readRead app data from the user's dots data layer.
data:writeWrite app data into the user's dots data layer.
offline_accessIssue refresh tokens for long-lived sessions.
sdk
Self-building SDK shape
The install flow can become a generated SDK: choose framework, auth mode, callback path, and scopes, then emit the exact files and environment variables for that project.
{
"provider": "dots",
"appUrl": "https://yourapp.com",
"redirectPath": "/api/auth/dots/callback",
"scopes": ["openid", "profile", "email", "wallet"],
"mode": "better-auth-compatible"
}npx dots install --framework next --mode optional