Skip to main content

Consumer Identity Management

The Fanfare SDK supports multiple authentication methods to identify consumers. The auth module handles session creation, OTP verification, and session management.

Authentication Methods

Guest Sessions

Guest sessions allow consumers to participate without providing identifying information. Guest sessions are device-bound.
const guestSession = await fanfare.auth.guest();

console.log("Consumer ID:", guestSession.consumerId);
console.log("Guest ID:", guestSession.guestId);
console.log("Session type:", guestSession.type); // "guest"

Email OTP Authentication

Email-based OTP provides verified consumer identity:
// Step 1: Request OTP
await fanfare.auth.requestOtp({ email: "[email protected]" });

// Step 2: Verify OTP (user enters code from email)
const session = await fanfare.auth.verifyOtp({
  email: "[email protected]",
  code: "123456",
});

console.log("Authenticated:", session.email);
console.log("Session type:", session.type); // "authenticated"

Phone OTP Authentication

Phone-based OTP for SMS verification:
// Step 1: Request OTP
await fanfare.auth.requestOtp({
  phone: "+14155551234",
  defaultCountry: "US",
});

// Step 2: Verify OTP
const session = await fanfare.auth.verifyOtp({
  phone: "+14155551234",
  code: "123456",
});

console.log("Authenticated:", session.phone);

External Exchange

Exchange a one-time code from an external authentication system:
// Exchange code from your auth system
const session = await fanfare.auth.exchangeExternal({
  exchangeCode: "ext_code_xxx",
});
This is useful when integrating with existing authentication systems like Shopify, Auth0, or custom systems.

Type Definitions

Session Types

interface Session {
  type: "guest" | "authenticated";
  consumerId: string;
  email?: string;
  phone?: string;
  expiresAt: string;
  deviceFingerprint?: string;
}

interface GuestSession extends Session {
  type: "guest";
  guestId: string;
  email: undefined;
}

interface AuthenticatedSession extends Session {
  type: "authenticated";
  email?: string;
  phone?: string;
}

AuthStatus

interface AuthStatus {
  isAuthenticated: boolean;
  isGuest?: boolean;
  session?: Session;
}

OTP Request/Verify

interface OtpRequest {
  email?: string;
  phone?: string;
  defaultCountry?: string;
  name?: string;
}

interface OtpVerify {
  email?: string;
  phone?: string;
  code: string;
  defaultCountry?: string;
}

Auth Module API

check()

Returns the current authentication status (synchronous).
check(): AuthStatus
Example:
const status = fanfare.auth.check();

if (status.isAuthenticated) {
  console.log("Logged in as:", status.session?.email);
} else if (status.isGuest) {
  console.log("Guest session:", status.session?.consumerId);
} else {
  console.log("No session");
}

guest()

Creates a new guest session.
guest(): Promise<GuestSession>
Example:
const session = await fanfare.auth.guest();
console.log("Guest consumer ID:", session.consumerId);

requestOtp()

Sends an OTP to the provided email or phone.
requestOtp(options: OtpRequest | string): Promise<void>
Parameters:
  • options - Email/phone and optional name, or just an email string
Example:
// Email only (shorthand)
await fanfare.auth.requestOtp("[email protected]");

// Full options
await fanfare.auth.requestOtp({
  email: "[email protected]",
  name: "John Doe",
});

// Phone
await fanfare.auth.requestOtp({
  phone: "+14155551234",
  defaultCountry: "US",
});

verifyOtp()

Verifies the OTP and creates an authenticated session.
verifyOtp(options: OtpVerify): Promise<AuthenticatedSession>
Parameters:
  • options - Email/phone with the verification code
Example:
const session = await fanfare.auth.verifyOtp({
  email: "[email protected]",
  code: "123456",
});

exchangeExternal()

Exchanges an external authentication code for a session.
exchangeExternal(options: ExternalExchange | string): Promise<AuthenticatedSession>
Example:
// From external auth callback
const session = await fanfare.auth.exchangeExternal("ext_code_xxx");

login()

Combined OTP flow (sends code to email).
login(options: LoginOptions): Promise<void>
interface LoginOptions {
  email: string;
}
Example:
await fanfare.auth.login({ email: "[email protected]" });
// User receives email with code

logout()

Ends the current session.
logout(): Promise<void>
Example:
await fanfare.auth.logout();

getSession()

Returns the current session or null.
getSession(): Session | null
Example:
const session = fanfare.auth.getSession();
if (session) {
  console.log("Session expires:", session.expiresAt);
}

refresh()

Refreshes the access token.
refresh(): Promise<void>
This is called automatically when tokens near expiration.

Authentication Events

Subscribe to authentication events:
// Session authenticated
fanfare.on("auth:authenticated", (data) => {
  console.log("Authenticated:", data.session.consumerId);
});

// Session logged out
fanfare.on("auth:logout", () => {
  console.log("Logged out");
});

Session Persistence

By default, sessions are persisted to localStorage:
const fanfare = await Fanfare.init({
  organizationId: "org_xxx",
  publishableKey: "pk_live_xxx",
  auth: {
    persistSession: true, // Default
  },
});
To disable persistence:
const fanfare = await Fanfare.init({
  organizationId: "org_xxx",
  publishableKey: "pk_live_xxx",
  auth: {
    persistSession: false,
  },
});

Guest-to-Authenticated Upgrade

Guests can be upgraded to authenticated sessions while preserving their participation:
// Start as guest
await fanfare.auth.guest();

// Enter a queue as guest
await fanfare.queues.enter("queue_123");

// Later: upgrade to authenticated
await fanfare.auth.requestOtp({ email: "[email protected]" });
const session = await fanfare.auth.verifyOtp({
  email: "[email protected]",
  code: "123456",
});

// Queue participation is preserved
const status = await fanfare.queues.status("queue_123");
console.log("Still in queue:", status.status === "QUEUED");

Error Handling

import { FanfareError, ErrorCodes } from "@waitify-io/fanfare-sdk-core";

try {
  await fanfare.auth.verifyOtp({
    email: "[email protected]",
    code: "wrong_code",
  });
} catch (error) {
  if (error instanceof FanfareError) {
    switch (error.code) {
      case ErrorCodes.INVALID_OTP:
        console.error("Invalid code. Please try again.");
        break;
      case ErrorCodes.SESSION_EXPIRED:
        console.error("Code expired. Request a new one.");
        break;
      default:
        console.error("Auth error:", error.message);
    }
  }
}

Complete Authentication Flow

import Fanfare, { FanfareError, ErrorCodes } from "@waitify-io/fanfare-sdk-core";

async function authenticateUser(email: string) {
  const fanfare = await Fanfare.init({
    organizationId: "org_xxx",
    publishableKey: "pk_live_xxx",
  });

  // Check existing session
  const { session } = await fanfare.restore();

  if (session?.type === "authenticated") {
    console.log("Already authenticated:", session.email);
    return session;
  }

  // Start OTP flow
  try {
    await fanfare.auth.requestOtp({ email });
    console.log("OTP sent to", email);

    // In a real app, prompt user for code
    const code = await promptUserForCode();

    const authenticatedSession = await fanfare.auth.verifyOtp({
      email,
      code,
    });

    console.log("Authenticated successfully!");
    return authenticatedSession;
  } catch (error) {
    if (error instanceof FanfareError && error.code === ErrorCodes.INVALID_OTP) {
      console.error("Invalid code");
      throw error;
    }
    throw error;
  }
}