Skip to main content

Overview

Bluvo’s OAuth2 integration lets your users connect their exchange accounts through a secure popup window. No API keys are exposed to your frontend, users authenticate directly with the exchange, and your app receives a wallet ID that represents the connection. From that point forward, the wallet ID is all you need to fetch balances, request withdrawal quotes, and execute transactions. Bluvo handles the entire OAuth lifecycle behind the scenes: authorization URL generation, token exchange, token refresh, AES-256-CBC encryption, and tenant-isolated storage. This page walks through the OAuth2 popup flow using @bluvo/react and Next.js server actions, the fastest path to a working integration.
If you pass a walletId that already exists, startWithdrawalFlow() automatically detects the existing wallet and skips OAuth, no separate resume call needed.

Integration Levels

Bluvo supports multiple integration depths. Pick the level that matches your team’s needs: This page focuses on the React State Machine approach with @bluvo/react. The same concepts (states, transitions, error handling) apply to all levels.

How OAuth2 Works

When a user connects an exchange account, this is what happens under the hood:
  1. Your app calls startWithdrawalFlow({ exchange, walletId }) with the user’s selected exchange and a wallet ID (new or previously stored)
  2. Bluvo requests an OAuth2 authorization URL from the exchange and opens a popup window
  3. The user authenticates directly with the exchange inside the popup
  4. The exchange redirects back to Bluvo’s callback with an authorization code
  5. Bluvo exchanges the code for access/refresh tokens server-side, then encrypts and stores them
  6. A wallet record is created and the wallet ID is returned to your app via WebSocket
  7. The popup closes automatically and the flow transitions to wallet:loading

What Bluvo Handles vs. What You Handle

Bluvo manages:
  • OAuth URL generation and popup lifecycle
  • Token exchange, refresh, and revocation
  • AES-256-CBC encryption of all credentials
  • WebSocket notifications for real-time state updates
  • Wallet ID creation and tenant-isolated storage
You are responsible for:
  • Calling startWithdrawalFlow() when the user selects an exchange
  • Rendering UI based on the current state
  • Persisting wallet IDs via the onWalletConnectedFn callback (so returning users skip OAuth automatically)
  • Handling popup-closed and error states gracefully

State Machine

The useBluvoFlow hook exposes the current state of the OAuth flow as boolean properties. Your UI simply reacts to these states.

OAuth State Flow

State Reference

Hook Booleans

Each state maps to a boolean on the flow object returned by useBluvoFlow:

React Implementation

Prerequisites

Install the React SDK:
Set up environment variables:

Server Actions

Create server actions that proxy Bluvo SDK calls.

Initialize the Hook

Wire up useBluvoFlow in a client component. No provider or context wrapper is needed, the hook manages its own state.
useBluvoFlow captures its configuration at mount time. Changing props after mount has no effect, remount the component to reinitialize.

Render OAuth States

Use the hook’s boolean properties to conditionally render each phase of the flow:
Each walletId must be unique per user and per exchange. See Wallet Id for the recommended pattern.

Error Handling

The OAuth flow has three distinct error scenarios, each requiring different UI treatment: Recoverable OAuth error (flow.isOAuthError && !flow.isOAuthFatal), a transient failure like a network timeout or temporary exchange issue. The user can retry by calling startWithdrawalFlow() again with the same exchange. Fatal OAuth error (flow.isOAuthFatal), the exchange permanently rejected the connection (e.g., account restrictions, unsupported region). Display flow.error?.message and offer flow.cancel() to reset the flow. User closed popup (flow.isOAuthWindowBeenClosedByTheUser), the user manually closed the authentication window. This is not an error, offer a retry button or let them pick a different exchange.
After wallet:ready, errors shift to wallet-specific states. Use flow.isWalletError for general wallet errors, flow.hasWalletNotFoundError when a wallet ID is no longer valid, and flow.hasInvalidCredentialsError when stored tokens have been revoked by the exchange.

What Comes After OAuth

Once flow.isWalletReady is true, the OAuth flow is complete. From here, the typical withdrawal flow continues:
  1. User selects an asset, amount, and destination address
  2. Your app calls flow.requestQuote(...) to get a real-time quote with fees
  3. User confirms, and flow.executeWithdrawal(quoteId) submits the transaction
  4. If the exchange requires 2FA, the hook surfaces flow.requires2FA or flow.requires2FAMultiStep
  5. Transaction completes at flow.isWithdrawalComplete
The state machine handles all of these transitions automatically. For the full withdrawal implementation, see the code samples.

Next Steps

Get API Keys

Create your organization and project in the Bluvo Portal

Code Samples

Full working examples for Next.js, React, and more

Encryption & Security

How Bluvo encrypts and isolates exchange credentials

Supported Exchanges

See which exchanges support OAuth2 connections