Prebit Developer Docs
Tutorials

Tutorial: OAuth From Scratch

Build the install flow yourself, step by step, with no framework in the way.

This walks through exactly what prebit-examples/oauth-example does, one step at a time, so you understand every line before you copy it.

1. Register a PartnerApp

In the Developer Portal, create an org (if you haven't), then an app. You'll get a client_id and client_secret — treat the secret like a password.

2. Register a redirect URI

While developing, this is a tunnel URL (prebit dev prints one if you have cloudflared installed) plus /callback. It must match exactly what you send in step 3 — no partial-path matching.

3. Generate a PKCE pair and build the authorize URL

import { generatePkcePair, buildAuthorizationUrl } from "@prebit/sdk";

const { codeVerifier, codeChallenge } = generatePkcePair();
const state = crypto.randomUUID();

const authorizeUrl = buildAuthorizationUrl({
  baseUrl: "https://admin.prebit.in",
  clientId: process.env.PREBIT_CLIENT_ID!,
  redirectUri: "http://localhost:8787/callback",
  scopes: ["read_products", "read_orders"],
  codeChallenge,
  state,
});

codeVerifier and state both need to survive until step 5 — in a real app, store them server-side (session, signed cookie, or a short-lived DB row keyed by state). In this from-scratch version, they just live in a variable because the whole script is one process.

4. Send the merchant there and start a callback server

console.log(`Open this URL: ${authorizeUrl}`);

You need something listening on redirectUri to catch the redirect. A plain http.createServer works fine — see the full example for the complete version.

5. Verify state, then exchange the code

// req.url is something like /callback?code=...&state=...
const url = new URL(req.url!, "http://localhost:8787");
const code = url.searchParams.get("code")!;
const returnedState = url.searchParams.get("state");

if (returnedState !== state) throw new Error("State mismatch — possible CSRF");

const tokens = await exchangeAuthorizationCode({
  baseUrl: "https://admin.prebit.in",
  code,
  codeVerifier,
  redirectUri: "http://localhost:8787/callback",
  clientId: process.env.PREBIT_CLIENT_ID!,
  clientSecret: process.env.PREBIT_CLIENT_SECRET!,
});

6. Prove it worked

const client = new PrebitPartnerClient({ baseUrl: "https://admin.prebit.in", accessToken: tokens.access_token });
const { store } = await client.getStore();
console.log(`Installed on ${store.name}`);

If this prints a real store name, you have a working OAuth flow. From here: persist tokens in your own database keyed by whatever identifies this installation to you, and set up a webhook receiver (see Webhooks and prebit-examples/webhook-listener) if you subscribed to any topics.

Common mistakes

  • Sending the wrong redirect_uri on exchange. It must be byte- identical to what you sent on the authorize step and what's registered on your PartnerApp — all three.
  • Losing codeVerifier between steps 3 and 5. If your process restarts (or you're running two server instances behind a load balancer) between generating the PKCE pair and receiving the callback, the exchange fails. Store it somewhere that survives — not just a module-level variable, in anything beyond a single-process demo.
  • Not checking state. Skipping this makes your callback vulnerable to CSRF — an attacker tricking a merchant into completing someone else's install flow.

On this page