docs
Add dots.id to any app.
@wrldbld/dots is a drop-in SDK — one package, one key — for Sign in with dots, cross-app credits, per-user data, and server-side token verification. dots.id is the OAuth 2.1 + PKCE issuer; your app is a client.
quickstart
From zero to signed-in
- 1
Get an API key
Your API key is a dots OAuth client id. Create one in the developer portal at /dev/clients → New client. For a browser/SPA app choose public (PKCE — no secret) and add your redirect URI, e.g.
http://localhost:3000/dots/callback. - 2
Install the SDK
One package, alpha-tagged. Pin an exact version while the API evolves.
npm i @wrldbld/dots@alpha # or: bun add @wrldbld/dots@alpha - 3
Set the env
The key is your public OAuth client id — safe in client code (public clients use PKCE, no secret).
# .env.local NEXT_PUBLIC_DOTS_API_KEY="client_..." # your dots app's public OAuth client id (safe in the browser) # NEXT_PUBLIC_DOTS_ISSUER="https://dots.localhost" # point at a dev issuer while testing; omit in prod - 4
Create the client
A single framework-agnostic factory. Works in Next, Vite, Svelte, anywhere.
// lib/dots.ts import { createDots } from "@wrldbld/dots"; export const dots = createDots({ apiKey: process.env.NEXT_PUBLIC_DOTS_API_KEY!, // issuer defaults to https://www.dots.id; redirectUri defaults to `${origin}/dots/callback` }); - 5
Sign in with dots
Redirects to dots.id for branded consent, then back to your callback.
// a sign-in button — kicks off OAuth 2.1 + PKCE, branded consent at dots.id import { dots } from "@/lib/dots"; export function SignIn() { return <button onClick={() => dots.signIn({ returnTo: "/app" })}>Sign in with dots</button>; } - 6
Handle the callback
Add a
/dots/callbackroute that completes the PKCE exchange.// app/dots/callback/page.tsx "use client"; import { useEffect } from "react"; import { dots } from "@/lib/dots"; export default function Callback() { useEffect(() => { dots.handleCallback().then(() => (location.href = "/app")); }, []); return <p>Signing you in…</p>; } - 7
Read the user
Identity comes straight from the access-token claims — no extra round-trip.
const user = await dots.getUser(); // { sub, username, walletAddress, dotsIdStatus, email } const token = await dots.getAccessToken(); // send as Bearer to your backend await dots.signOut(); - 8
Verify tokens on your server
Trust the user on your own backend by verifying the token via
@wrldbld/dots/server— zero-dependency (Web Crypto + fetch), runs in Node, Bun, Deno, and edge. Stateless: for revocation-sensitive checks useintrospectDotsToken().// app/api/whatever/route.ts — protect YOUR backend with the dots token import { verifyDotsToken, getBearerToken, hasScope } from "@wrldbld/dots/server"; export async function GET(request: Request) { const token = getBearerToken(request); try { const claims = await verifyDotsToken(token); // RS256, verified against dots JWKS if (!hasScope(claims, "data:read")) return new Response("forbidden", { status: 403 }); return Response.json({ sub: claims.sub, wallet: claims.walletAddress }); } catch { return new Response("unauthorized", { status: 401 }); } }
sdk
Client surface
dots.signIn() / handleCallback() / signOut()OAuth 2.1 + PKCE against the dots OAuth server.dots.getUser() / getAccessToken()Identity from token claims — no extra round-trip.dots.identity.status() / confirm() / activity()Drive onboarding off the live creation progress.dots.credits.balance() / debit() / topUp()One pute balance, cross-app, idempotent debits.dots.emails.add() / list()Verified emails attached to the dots.dots.attestations.list() / submitProof()Verified claims (zkTLS or otherwise). Preview.dots.data.get() / set() / list()Per-user storage namespaced to your app (data:read/write).dots.cosign.*Vouch a dot/agent into your authority (EIP-712 + 2FA). Preview.server
Server surface — @wrldbld/dots/server
Verify dots tokens on your own backend. Zero dependencies; works in any runtime.
verifyDotsToken(token, opts?)RS256 verify against JWKS; checks sig/exp/issuer/audience. Throws DotsTokenError.verifyDotsTokenSafe(token)Same, returns null instead of throwing.getBearerToken(req)Pull the Bearer token from a Request/Headers/string.hasScope(claims, scope)Scope check on verified claims.introspectDotsToken(token, creds)RFC 7662 introspection — catches server-side revocation.getDotsUserInfo(token) / getOpenIdConfiguration()OIDC userinfo + discovery document.scopes
OAuth scopes
openidRequired OIDC identity scope.profileUsername and basic dots.id profile.emailVerified email claims.walletConnected wallet address.data:read / data:writeRead/write the user's per-app data layer.pute:read / pute:spend / pute:topupRead balance / debit / start a top-up.offline_accessIssue refresh tokens for long-lived sessions.reference
More
- · Install walkthrough — the marketing-flavored version of this page.
- · Package source & README — full API reference, types, and changelog.
- · Developer dashboard — create/manage OAuth clients (API keys).
- · OIDC discovery — issuer metadata, endpoints, JWKS.