Skip to main content

Build a Connect with Rivo integration with OAuth apps

Create an OAuth app and implement a secure Connect with Rivo flow for your integration.

Written by Stuart Chaney

Build a Connect with Rivo integration with OAuth apps

This guide is for app developers building integrations with Rivo.

If you are a merchant connecting an existing app, use that app's setup flow instead.




What OAuth apps are for

OAuth apps let you add a Connect with Rivo flow to your app so merchants can authorize access without sharing API keys.

With OAuth, your app gets:

  • Merchant-approved access tokens

  • Scope-based permissions

  • Refresh tokens for long-lived connections

  • Standard authorization code flow with PKCE support




Create your OAuth app in Rivo

Open the OAuth Applications dashboard in your Rivo admin:

Then:

  1. Click New Application.

  2. Fill in:

    • Name: shown to merchants on the consent screen

    • Redirect URI: one or more callback URLs (space-separated)

    • Confidential: enable for server-side apps that can securely store a client secret

    • Scopes: space-separated scopes your app needs

  3. Save the app.

After creation, copy and store:

  • Client ID (uid)

  • Client Secret (store securely)

The app details page also shows Authorize → test links for each redirect URI.




OAuth endpoints

Use these endpoints:

  • Authorize: GET /api/oauth/v1/oauth/authorize

  • Token: POST /api/oauth/v1/oauth/token

  • Revoke: POST /api/oauth/v1/oauth/revoke

  • Introspect: POST /api/oauth/v1/oauth/introspect

Application management in the dashboard uses:

  • GET /developer/oauth/applications




Supported scopes

Rivo supports these configured scopes:

  • identity_basic_read: basic read access for identity/shop data

  • identity_basic_write: basic write access for identity/shop data

  • mcp_read: read access used for MCP tooling

  • developer_api: access for developer API usage

Request only the minimum scopes your integration needs.




Authorization code flow (recommended with PKCE)

  1. Redirect the merchant to the authorize endpoint with:

    • client_id

    • redirect_uri

    • response_type=code

    • scope

    • state

    • code_challenge and code_challenge_method=S256 (recommended)

  2. Merchant approves access.

  3. Rivo redirects to your redirect_uri with:

    • code

    • state

  4. Exchange the code at the token endpoint.

  5. Call Rivo APIs with Authorization: Bearer <access_token>.


Why state and PKCE matter

  • state protects against request forgery and lets you match responses to requests.

  • PKCE protects the authorization code exchange from interception.




Minimal Node.js example

import crypto from "node:crypto";import express from "express";import fetch from "node-fetch";const app = express();const RIVO_BASE = "https://your-rivo-host";const CLIENT_ID = process.env.RIVO_CLIENT_ID;const CLIENT_SECRET = process.env.RIVO_CLIENT_SECRET;const REDIRECT_URI = "https://your-app.com/oauth/rivo/callback";const stateStore = new Map();function base64url(buffer) {  return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");}app.get("/oauth/rivo/start", (req, res) => {  const state = crypto.randomBytes(16).toString("hex");  const codeVerifier = base64url(crypto.randomBytes(32));  const codeChallenge = base64url(crypto.createHash("sha256").update(codeVerifier).digest());  stateStore.set(state, { codeVerifier, createdAt: Date.now() });  const params = new URLSearchParams({    client_id: CLIENT_ID,    redirect_uri: REDIRECT_URI,    response_type: "code",    scope: "identity_basic_read",    state,    code_challenge: codeChallenge,    code_challenge_method: "S256"  });  res.redirect(`${RIVO_BASE}/api/oauth/v1/oauth/authorize?${params.toString()}`);});app.get("/oauth/rivo/callback", async (req, res) => {  const { code, state } = req.query;  const session = stateStore.get(state);  if (!code || !state || !session) {    return res.status(400).send("Invalid OAuth callback");  }  const tokenRes = await fetch(`${RIVO_BASE}/api/oauth/v1/oauth/token`, {    method: "POST",    headers: { "Content-Type": "application/x-www-form-urlencoded" },    body: new URLSearchParams({      grant_type: "authorization_code",      client_id: CLIENT_ID,      client_secret: CLIENT_SECRET,      redirect_uri: REDIRECT_URI,      code: String(code),      code_verifier: session.codeVerifier    })  });  const token = await tokenRes.json();  // token includes access_token, refresh_token (if issued), token_type, scope, expires_in  // Store token securely per merchant, then call Rivo APIs with Bearer access_token.  res.json(token);});



Token refresh and revocation

  • Store token response values securely per merchant account.

  • Use expires_in from the token response to track access token expiry.

  • Use the refresh token flow when your stored access token expires.

  • Revoke tokens with POST /api/oauth/v1/oauth/revoke when disconnecting a merchant.




OAuth vs API keys

Use OAuth apps when:

  • You are building a multi-merchant SaaS integration

  • You need a self-serve Connect button

  • You need merchant-level consent and revocation

Use API keys when:

  • You are building internal tooling for a single merchant

  • The merchant manages credentials directly

Related guides:

Did this answer your question?