Skip to main content
The social signer lets users authenticate with an OAuth provider (Google, Apple, Discord) through web3auth. The OAuth public flow runs in the browser; the provider secret and verifier callback are handled by your backend signer-proxy. A Stellar ed25519 key backs the resulting account - the user never manages a seed phrase.

When to use

Choose socialSigner when you want a familiar sign-in button (Google, Apple, Discord) without requiring your users to install a wallet or remember a seed phrase. The resulting key backs a classic G... account.
The web3auth client secret must never be included in a browser bundle. Configure a same-origin proxyUrl pointing at your backend signer-proxy, which is created with createSignerProxyRoute from @buckspay/nextjs. Only the public OAuth flow runs in the browser; the secret callback and verifier go through your server.

Factory

import { socialSigner } from "@buckspay/signers/social";

const signer = socialSigner({
  provider: "web3auth",
  clientId: "BNxxxx-your-web3auth-client-id",
  network:  "testnet",
  proxyUrl: "/api/buckspay/auth/social"
});
socialSigner(opts) accepts a SocialSignerOptions object:
OptionTypeRequiredDescription
provider"web3auth"YesOAuth provider backend (only "web3auth" in v1)
clientIdstringYesYour web3auth project client ID (public - safe in browser)
network"testnet" | "pubnet"YesStellar network to target
proxyUrlstringNoSame-origin route to the @buckspay/nextjs signer-proxy

Authentication

Call signer.authenticate?.(params) before the payment. It runs the provider’s OAuth flow and resolves an AuthDetails object:
const details = await signer.authenticate?.({ loginProvider: "google" });
// details: AuthDetails { publicKey: "G...", provider: "web3auth" }
After authenticate() returns, the signer’s getPublicKey() and signAuthEntry() are ready. Provider or network failures surface as BuckspayError with code AUTH_PROVIDER_ERROR.

Server-side proxy

Mount the signer-proxy in your backend (for example, a Next.js App Router route):
// app/api/buckspay/auth/social/route.ts
import { createSignerProxyRoute } from "@buckspay/nextjs";
export const POST = createSignerProxyRoute({ provider: "web3auth", network: "testnet" });
The proxy receives the OAuth callback and calls the facilitator’s POST /auth/social endpoint with the secret - only public key material is returned to the browser.

Example

// Recipe 12 - SOCIAL LOGIN (web3auth) -> gasless USDC. Browser app.
//
// The user signs in with Google/Apple/Discord via web3auth. The PUBLIC OAuth runs in the
// browser; the SECRET verifier callback is completed by YOUR backend's signer-proxy
// (`@buckspay/nextjs` createSignerProxyRoute -> facilitator POST /auth/social). web3auth
// hands back a Stellar ed25519 key - the smart-account signer. No web3auth secret and no
// private key ever reach this bundle.
import { createBuckspayClient, createRpcSimContext, type BuckspayConfig } from "@buckspay/core";
import { classicAccount } from "@buckspay/accounts/classic";
import { socialSigner } from "@buckspay/signers/social";
import { buckspayFacilitator } from "@buckspay/relayer/buckspay-facilitator";

const USDC_SAC_TESTNET = "CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA";
const MERCHANT = "GA6HCMBLTZS5VYYBCATRBR5VBZJEH5C2OON6XQGB3RNYDDAQ7JZ65YQH";

// The social ed25519 key backs the classic account (its G-address IS the account).
const signer = socialSigner({
  provider: "web3auth",
  clientId: "BNxxxx-your-web3auth-client-id",
  network: "testnet",
  // YOUR same-origin signer-proxy route; it forwards to the facilitator with the secret server-side.
  proxyUrl: "/api/buckspay/auth/social"
});

export const socialConfig: BuckspayConfig = {
  network: "testnet",
  account: classicAccount(),
  signer,
  // url points at YOUR backend relay route (apiKey server-side), never the raw facilitator key.
  relayer: buckspayFacilitator({ url: "/api/buckspay/relay", network: "testnet" }),
  gas: { mode: "sponsored" }
};

export const socialClient = createBuckspayClient(
  socialConfig,
  createRpcSimContext("https://soroban-testnet.stellar.org")
);

export async function payWithSocialLogin(): Promise<void> {
  // 1. Run the provider OAuth flow -> resolves the Stellar ed25519 key.
  const details = await signer.authenticate?.({ loginProvider: "google" });
  console.log("signed in as", details?.publicKey, "via", details?.provider);

  // 2. From here it is an ordinary gasless payment - accounts/relayer/engine are untouched.
  await socialClient.connect();
  const call = socialClient.transfer({ token: USDC_SAC_TESTNET, to: MERCHANT, amount: "1.50" });
  const receipt = await socialClient.pay([call]);
  console.log(receipt.transferTx);
}

Next

Email OTP

No OAuth required - authenticate with a code sent to the user’s inbox.

Facilitator and BFF

How the signer-proxy and API key work together server-side.