Sign in with PeridotID

Let users sign into your app with their PeridotID (Google or passkey)

Add "Sign in with PeridotID" to any web app in three steps. Your users authenticate against PeridotID production — no local setup, no secrets to manage.

1. Register your app

Call POST /v1/apps with your PeridotID session (cookie) to get a public client_id. List every URL PeridotID may return users to — codes are only issued to these:

import { Peridot } from '@peridotvault/pid-sdk-js';

const peridot = Peridot({ baseUrl: 'https://api.pid.peridotvault.com' });
// Register with just a name — allowed origins are managed after, in the dashboard
// at pid.peridotvault.com/workspace (or PATCH /v1/apps).
const res = await peridot.post('/v1/apps', { name: 'My Game' });
// res.data.clientId → "pidapp_..." — pass it as client_id in step 2

Then add your websites under Allowed origins (bare https://… origins, no paths). Pass the exact return URL in code — its origin must be listed:

Your redirect URI origins are automatically allowed for browser API calls (within ~60s of registering, no redeploy needed). Local development needs nothing at all: http://localhost, http://127.0.0.1 and http://[::1] (any port, any path) are always allowed — arbitrary production hosts are never accepted without registration (an open redirect would let anyone steal users' login codes).

2. Open the login popup

npm install @peridotvault/pid-sdk-js
import { Peridot, openLoginTab } from '@peridotvault/pid-sdk-js';

const peridot = Peridot({
  baseUrl: 'https://api.pid.peridotvault.com',
  solanaRpcUrl: 'https://api.devnet.solana.com',
  popupBaseUrl: 'https://app.pid.peridotvault.com',
});

async function signIn() {
  const { pidCode } = await openLoginTab({
    popupBaseUrl: 'https://app.pid.peridotvault.com',
    params: {
      origin: window.location.origin,
      popup: 'login',
      client_id: 'pidapp_...',
    },
  });
  if (pidCode) {
    const identity = await peridot.auth.exchange(pidCode, 'pidapp_...');
    // { pid, profile: { displayName, avatarUrl }, credentials: [{ provider, email }] }
  }
}

Auth opens the PeridotID login in a new tab (a full-page flow: Google, plus the PID picker if the visitor has no PeridotID yet). When it completes the tab mints a one-time pid_code for your client_id and posts it to your page, then closes — you never handle a password and nothing runs in your DOM. Passkeys run on the PeridotID origin (browsers bind WebAuthn to our domain); Google uses the redirect round-trip. If the tab is blocked, fall back to navigating to the hosted login directly (same query params). No API calls happen before login, so there is nothing CORS-related to configure.

First sign-in creates a PID. If the visitor has no PeridotID yet, the tab shows the emission-free Create your PID step (the handle is permanent and user-chosen). Login only resolves once a PID exists. popupBaseUrl is reused as the auth host; approval popups (a small window on the PeridotID origin) are used only for confirmations like transfers and payments.

In React, wrap the same two calls in your own button + hook — there is no provider component to install.

3. Handle the login

After login the tab returns a one-time pid_code (posted to your opener; a full-page redirect_uri fallback is also supported). Exchange it as above — directly, or via your backend, which then mints your app's own session.

Already signed in? The tab issues the code immediately (a one-tap consent screen appears for cross-origin SSO). Denying returns with ?error=access_denied.

Prefer to mint your own session? Exchange server-side instead of calling peridot.auth.exchange in the browser:

// your backend: verify the code against PeridotID, then create your session
const r = await fetch('https://api.pid.peridotvault.com/v1/auth/exchange', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ code, clientId: 'pidapp_...' }),
});
const identity = await r.json(); // single-use code, 5-minute expiry

Notes

  • Passkey login always runs on a PeridotID-hosted page (browsers bind WebAuthn to our domain) and returns with pid_code like Google does.
  • Codes are single-use, expire in ~5 minutes, and are bound to your client_id.
  • No framework? The snippet in step 2 is already framework-free: openLoginTab (alias openLoginPopup), loginWithPasskey({ clientId, returnTo }), exchange(code, clientId).

Next: money

Once users can sign in, you can fund their balance, hold escrow on your app's account, and charge your own fee:

  • Fiat & payments — top-up, balance, sends, escrow.
  • Apps & workspace — manage your app, set per-app fees, read the escrow balance with a machine token.

On this page