bullseye-arrowQuickstart

Integrate Revibase into a web app (Next.js, Remix, Vite).

This guide is for web apps (Next.js, Remix, Vite, etc).

You ship three things:

  • Frontend: call signIn, transferTokens, executeTransaction.

  • Static config: /.well-known/revibase.json on your domain.

  • Backend: POST /api/clientAuthorization with your PRIVATE_KEY.

1

Install

Terminal
pnpm add @revibase/lite
2

Generate client keys

Generate a client keypair. Keep the private key on the server only.

circle-info

This snippet uses WebCrypto. Node 20+ recommended.

Terminal
node -e '
(async () => {
  const toBase64 = str => Buffer.from(str).toString("base64");

  const keyPair = await crypto.subtle.generateKey(
    { name: "Ed25519" },
    true,
    ["sign", "verify"]
  );

  const [pub, priv] = await Promise.all([
    crypto.subtle.exportKey("jwk", keyPair.publicKey),
    crypto.subtle.exportKey("jwk", keyPair.privateKey)
  ]);

  const publicKeyJSON  = `{"alg":"EdDSA","crv":"Ed25519","kty":"OKP","x":"${pub.x}"}`;
  const privateKeyJSON = `{"alg":"EdDSA","crv":"Ed25519","d":"${priv.d}","kty":"OKP","x":"${priv.x}"}`;

  console.log({
    publicKey: toBase64(publicKeyJSON),
    privateKey: toBase64(privateKeyJSON)
  });
})();
'

You’ll get:

  • publicKey → goes into revibase.json as clientJwk.

  • privateKey → set as PRIVATE_KEY on your server.

3

Publish /.well-known/revibase.json

Serve this from the same domain as your app:

https://<your-domain>/.well-known/revibase.json

Required fields:

  • clientJwk: your public key (base64).

  • title: app name shown in the approval UI.

Optional:

  • description: short UX copy.

public/.well-known/revibase.json
{
  "clientJwk": "<paste-public-key>",
  "title": "My App",
  "description": "Connect with passkeys"
}
4

Backend callback (/api/clientAuthorization)

Expose:

  • POST /api/clientAuthorization

Set server env:

  • PRIVATE_KEY: the base64 private key you generated above

app/api/clientAuthorization/route.ts
import {
  processClientAuthCallback,
  type DeviceSignature,
  type StartMessageRequest,
  type StartTransactionRequest,
} from "@revibase/lite";

export async function POST(req: Request) {
  try {
    const { request, device, channelId } = (await req.json()) as {
      request: StartMessageRequest | StartTransactionRequest;
      device?: DeviceSignature;
      channelId?: string;
    };

    const result = await processClientAuthCallback({
      request,
      privateKey: process.env.PRIVATE_KEY!,
      signal: req.signal,
      device,
      channelId,
    });

    return Response.json(result);
  } catch (e) {
    const msg = e instanceof Error ? e.message : String(e);
    return Response.json({ error: msg }, { status: 500 });
  }
}
5

Frontend flows

Revibase runs in the browser. In Next.js, call it from a Client Component.

circle-info

Call the methods below from a user gesture (click/tap). Popups can be blocked otherwise.

Sign in

Sign in
import { RevibaseProvider, signIn } from "@revibase/lite";

const provider = new RevibaseProvider();
const { user } = await signIn(provider);

Pay (token transfer)

transferTokens works with or without signer.

Transfer
import { RevibaseProvider, signIn, transferTokens } from "@revibase/lite";

const provider = new RevibaseProvider();

// Option A: pay without an explicit connect step
const { txSig, user } = await transferTokens(provider, {
  amount: 100_000_000n,
  destination: "DESTINATION_WALLET_ADDRESS",
});

// Option B: connect first, then pay as that user
// const { user } = await signIn(provider);
// const { txSig } = await transferTokens(provider, { amount, destination, signer: user });

After you get txSig, confirm it with your Solana RPC (getTransaction, getSignatureStatuses, etc).

Custom transactions (executeTransaction)

Build instructions with your preferred Solana library.

Custom transaction
import { RevibaseProvider, signIn, executeTransaction } from "@revibase/lite";

const provider = new RevibaseProvider({
  rpcEndpoint: "https://api.mainnet-beta.solana.com",
});

const { user } = await signIn(provider);

const { txSig } = await executeTransaction(provider, {
  instructions: [], // your instructions
  signer: user,
});

Two-device approvals (channels)

Use channels when one device drives the UI and another device approves.

Go here for the full setup and API snippets:

Security notes

  • Never ship PRIVATE_KEY to the browser.

  • Use HTTPS in production.

Next

Last updated