Getting Started

Add 'Sign in with Passji' to your app in under 5 minutes. Standard OAuth 2.0 / OIDC flow.

Prerequisites

  • An application that can handle OAuth 2.0 / OIDC callbacks
  • A registered app in the Passji Developer Portal
  • Any OIDC client library (optional - raw HTTP works fine)

Step 1
Register Your App

Go to the Developer Portal and register your application. You'll need:

  • App name - Displayed to users during consent
  • Redirect URI(s) - Where users return after auth
  • App type - Web, SPA, mobile, or machine-to-machine

After registration, you'll receive your client_id and client_secret.

credentials
// 1. Go to the Developer Portal
// https://passji.com/developer

// 2. Register your app and get credentials:
// - client_id: "your_client_id"
// - client_secret: "your_client_secret"
// - redirect_uri: "https://yourapp.com/callback"

Step 2
Redirect to Authorization

When a user clicks "Sign in with Passji", redirect them to the authorization endpoint. The user will pick their emoji, authenticate with their passkey, and grant consent.

authorize.js
// Step 1: Build the authorization URL
const authUrl = new URL("https://passji.com/authorize");
authUrl.searchParams.set("client_id", "your_client_id");
authUrl.searchParams.set("redirect_uri", "https://yourapp.com/callback");
authUrl.searchParams.set("response_type", "code");
authUrl.searchParams.set("scope", "openid emoji trust");
authUrl.searchParams.set("state", crypto.randomUUID());

// With PKCE (recommended for SPAs and mobile):
const codeVerifier = generateCodeVerifier(); // 43-128 chars
const codeChallenge = await sha256(codeVerifier);
authUrl.searchParams.set("code_challenge", codeChallenge);
authUrl.searchParams.set("code_challenge_method", "S256");

// Step 2: Redirect user to Passji
window.location.href = authUrl.toString();

PKCE is recommended for single-page apps (SPAs) and mobile apps. It prevents authorization code interception attacks without requiring a client secret on the client side.

Step 3
Exchange Code for Tokens

After the user authorizes, they're redirected back to your redirect_uri with a code parameter. Exchange this for tokens.

token.js
// Step 3: Exchange code for tokens (server-side)
const response = await fetch("https://passji.com/token", {
  method: "POST",
  headers: {
    "Content-Type": "application/x-www-form-urlencoded",
  },
  body: new URLSearchParams({
    grant_type: "authorization_code",
    code: authorizationCode,
    redirect_uri: "https://yourapp.com/callback",
    client_id: "your_client_id",
    client_secret: "your_client_secret",
    // Include if using PKCE:
    code_verifier: codeVerifier,
  }),
});

const tokens = await response.json();
// {
//   access_token: "eyJhbGciOiJSUzI1NiIs...",
//   id_token: "eyJhbGciOiJSUzI1NiIs...",
//   token_type: "Bearer",
//   expires_in: 3600,
//   refresh_token: "refresh_abc123..."
// }

Step 4
Use the ID Token

The id_token is a signed JWT containing the user's identity claims. Verify the signature using Passji's public keys from the JWKS endpoint.

id_token.json
// Step 4: Decode the ID token
// The id_token contains user claims:
{
  "iss": "https://passji.com",
  "sub": "usr_abc123",          // Unique user ID
  "aud": "your_client_id",
  "iat": 1709856000,
  "exp": 1709859600,
  "emoji_id": "🦊🌸🎯",         // The user's emoji identity
  "emoji_length": 3,
  "trust_score": 0.85,          // If 'trust' scope requested
  "account_age_days": 45,
  "auth_method": "webauthn"
}

Available Scopes

ScopeClaims ReturnedDescription
openidsubRequired. Returns the unique user ID.
emojiemoji_id, emoji_lengthThe user's emoji sequence.
profileemoji_id, emoji_lengthAlias for emoji scope.
trusttrust_score, account_age_daysTrust score and account metadata.

Next Steps