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

  1. In Rivo admin, go to Settings.

  2. Open OAuth Applications.

  3. Click New Application.

  4. Fill in:

    • Name: shown to merchants on the consent screen

    • Redirect URI: one or more callback URLs (one URI per line)

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

  5. Save the app.

After creation, copy and store:

  • Client ID

  • Client Secret (store securely)

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



​
​

OAuth endpoints

Production OAuth base URL: https://developer-api.rivo.io
​

Use these endpoints:

  • Authorize: GET https://developer-api.rivo.io/api/oauth/v1/oauth/authorize

  • Token: POST https://developer-api.rivo.io/api/oauth/v1/oauth/token

  • Revoke: POST https://developer-api.rivo.io/api/oauth/v1/oauth/revoke

  • Introspect: POST https://developer-api.rivo.io/api/oauth/v1/oauth/introspect

For OAuth discovery (RFC 8414), use:

  • GET https://developer-api.rivo.io/.well-known/oauth-authorization-server

OAuth apps created in this flow use the developer_api scope.



​
​

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

This example is for a confidential app (server-side) and includes client_secret in the token exchange.

import crypto from "node:crypto";import express from "express";import fetch from "node-fetch";const app = express();const RIVO_BASE = process.env.RIVO_BASE || "https://developer-api.rivo.io";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: "developer_api",    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?