Prebit Developer Docs

OAuth

Authorization-code + PKCE — the merchant-install flow every app goes through.

Prebit is the authorization server. Your app's backend is the OAuth client. The flow is standard authorization-code + PKCE (S256 only — plain is rejected), with a merchant's browser as the user-agent.

Merchant browser          Prebit (auth server)          Your server
     |  1. redirected to consent screen  |                    |
     |----------------------------------->                    |
     |  2. approves install              |                    |
     |----------------------------------->                    |
     |  3. redirect to your redirect_uri?code=...&state=...    |
     |---------------------------------------------------------->
     |                                    |  4. POST /oauth/token
     |                                    <----------------------
     |                                    |  5. access_token + refresh_token
     |                                    ----------------------->

1. Build the authorization URL

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

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

const authorizeUrl = buildAuthorizationUrl({
  baseUrl: "https://admin.prebit.in",
  clientId: "...",
  redirectUri: "https://your-app.example.com/oauth/callback",
  scopes: ["read_products", "write_products"],
  codeChallenge,
  state,
});
// Store codeVerifier server-side (session/signed cookie/short-lived row
// keyed by `state`) — you need it again in step 3.
ParamRequiredNotes
client_idyesFrom your PartnerApp registration
redirect_uriyesMust be an exact match to a registered redirect URI
scopeyesSpace-separated. Capped to what your app's PartnerApp.requestedScopes declares
code_challengeyesPKCE challenge (S256)
code_challenge_methodyesMust be S256
staterecommendedEchoed back verbatim on redirect; use for CSRF protection

2. Merchant approves

The merchant (with ADMIN+ store access) approves on Prebit's own consent screen. You don't implement this step.

3. Receive the authorization code

Prebit redirects to your redirect_uri:

GET https://your-app.example.com/oauth/callback?code=<opaque code>&state=<your state>

The code is single-use and short-lived (5-minute TTL). Verify state matches before proceeding.

4. Exchange the code for tokens

import { exchangeAuthorizationCode } from "@prebit/sdk";

const tokens = await exchangeAuthorizationCode({
  baseUrl: "https://admin.prebit.in",
  code,
  codeVerifier,
  redirectUri: "https://your-app.example.com/oauth/callback",
  clientId: "...",
  clientSecret: "...",
});

Response:

{
  "access_token": "...",
  "refresh_token": "...",
  "token_type": "bearer",
  "expires_in": 900,
  "scope": "read_products write_products",
  "mode": "offline"
}

scope is the granted set, which may be a subset of what you requested — always trust this field.

Errors: 400 with error: "invalid_request" (missing fields), 400 with error: "invalid_grant" (bad/expired/reused code, or PKCE mismatch), 401 with error: "invalid_client" (bad client id/secret).

5. Refresh an expired access token

import { refreshAccessToken } from "@prebit/sdk";

const tokens = await refreshAccessToken({
  baseUrl: "https://admin.prebit.in",
  refreshToken,
  clientId: "...",
  clientSecret: "...",
});

Same response shape as step 4. Refresh tokens rotate — store the new one from every response.

Revoking a token

import { revokeToken } from "@prebit/sdk";

await revokeToken({ baseUrl: "https://admin.prebit.in", token, clientId: "...", clientSecret: "..." });

Always resolves {"ok":true} for a well-formed request, even if the token was already revoked or unknown (RFC 7009 semantics) — this is your opt-in cleanup, distinct from the merchant clicking "Uninstall," which revokes tokens automatically without you calling anything.

Redirect URI rules

Exact, pre-registered HTTPS URL — no wildcard or partial-path matching.

What happens on uninstall

When a merchant uninstalls your app, Prebit revokes all tokens immediately, stops future webhook/job deliveries, deletes Extension Storage, and cancels any active billing:"prebit" subscription. Build your app so a 403 "Installation is not active" response is handled as "this merchant uninstalled," not retried forever.

A full working example

prebit-examples/oauth-example is this entire flow, end to end, in one runnable file — including the local callback server.

On this page