Passpage
Developer Guide

Integrating Passpage

Everything needed to add Passpage to your app: registering, requesting scopes, and exchanging an authorization code for user data.

Passpage lets your app request a user's onboarding data (name, email, phone, address) with their explicit, field-level consent, instead of collecting it yourself.

Passpage sits after your existing sign-in flow. It is not an authentication provider. If you need login, keep using whatever you already use (email/password, Google, etc.). Passpage only handles the "now that they're signed in, get their profile details" step.

Prerequisites

Step 1: Register your app

  1. Sign in to Passpage at app.passpage.outercirclelab.com
  2. Go to Developer → API Keys & Apps → Register New App
  3. Fill in your app name, category, and redirect URI(s), the exact URL(s) Passpage is allowed to send users back to
  4. On submit, you'll receive a client_id (public, safe for frontend code) and a client_secret (shown once, copy it immediately into your backend environment variables)

Redirect URI matching is exact. https://myapp.com/callback and https://myapp.com/callback/ are different values, and a mismatch fails at authorization time. Get this exactly right during registration.

Step 2: Decide what data you need

Requests are split into required_scopes (fields you cannot function without, the user can't deselect these) and optional_scopes (nice to have, the user chooses). Only mark a field required if your app genuinely cannot work without it.

ScopeReturns
profile:namefull_name
profile:emailemail
profile:phonephone (may be null)
profile:addressaddress object: line1, line2, city, state, postal_code, country

Step 3: Trigger the authorization popup

From your frontend, open a popup to:

https://app.passpage.outercirclelab.com/authorize
  ?client_id=YOUR_CLIENT_ID
  &redirect_uri=YOUR_REGISTERED_REDIRECT_URI
  &required_scopes=profile:name,profile:email
  &optional_scopes=profile:address
function connectWithPasspage() {
  const params = new URLSearchParams({
    client_id: 'pas_client_xxxxxxxxxxxx',
    redirect_uri: 'https://myapp.com/callback',
    required_scopes: 'profile:name,profile:email',
    optional_scopes: 'profile:address',
  });

  window.open(
    `https://app.passpage.outercirclelab.com/authorize?${params}`,
    'PasspageAuth',
    'width=450,height=650'
  );
}

If the user isn't logged into Passpage, they'll see a login/register screen first, on the same page, no separate redirect. Once authenticated, they see the consent screen with your app name, the required and optional fields, and which saved profile they're sharing from.

Step 4: Receive the redirect

After the user approves, Passpage redirects the popup to your registered redirect_uri with a code parameter:

https://myapp.com/callback?code=8f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c...

This code is single-use and expires 2 minutes after issuance. Send it immediately to your own backend, never call the exchange endpoint directly from the browser.

Step 5: Exchange the code (server-to-server only)

POST https://myipkticsugptcqldgmx.supabase.co/functions/v1/exchange
Content-Type: application/json

{
  "client_id": "pas_client_xxxxxxxxxxxx",
  "client_secret": "pas_sk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "code": "8f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c..."
}

Success response:

{
  "profile": {
    "full_name": "Sachin R.",
    "email": "sachin@example.com",
    "address": {
      "line1": "104, Green Park Society",
      "line2": null,
      "city": "Ahmedabad",
      "state": "Gujarat",
      "postal_code": "380015",
      "country": "IN"
    }
  }
}

Only fields the user actually approved are present in the response.

Error responses

StatusErrorMeaning
401invalid_clientclient_id not found, or client_secret doesn't match
400invalid_grantCode is invalid, unknown, or belongs to a different app
400consent_revokedUser revoked this grant before you exchanged it
400consent_expiredThe code's 2-minute window passed before exchange
500server_errorSomething failed on Passpage's side, rare, retry once

On consent_expired: this means a fresh authorization is needed, not a retry of the same code, expired codes are permanently dead.

Security requirements

What Passpage does not currently support

Testing

There is currently no separate sandbox/test mode. Integration testing happens against real Passpage accounts, use a personal test account with a dedicated test profile rather than real user data while building your integration.


Questions or integration issues: support@outercirclelab.com