Amba
SDKsFeatures

Auth

Anonymous, email/password, email OTP, SMS OTP, Sign in with Apple, Sign in with Google. Sessions persist across restarts on every SDK.

Establish a user session before calling any other client SDK method. Auth is a prerequisite for events, collections, storage, push, entitlements, AI, config, and flags — anything on /v1/client/* needs a session token.

Supported flows: anonymous, email / password, email OTP, SMS OTP, Sign in with Apple, Sign in with Google. Sessions persist across app restarts; refresh tokens rotate server-side automatically.

Quick start

import { Amba } from '@layers/amba-web';
 
await Amba.configure({
  projectId: process.env.AMBA_PROJECT_ID!,
  clientKey: process.env.AMBA_CLIENT_KEY!,
});
const session = await Amba.auth.signInAnonymously();
console.log('signed in as', session.user.id);

Operations

Anonymous sign-in

Mints a fresh user with no email or password. Useful for trial flows, gated demos, or any moment before you ask for credentials. The resulting app_user.id can later be linked to email or social credentials.

const session = await Amba.auth.signInAnonymously();

Email / password

signUpWithEmail creates a new user; signInWithEmail authenticates an existing one. Both return the same session shape.

// New user
await Amba.auth.signUpWithEmail('me@example.com', 'correct horse battery staple');
 
// Returning user
await Amba.auth.signInWithEmail('me@example.com', 'correct horse battery staple');

Email one-time passcode (OTP)

Passwordless email sign-in via a 6-digit code the user types into the app. Better fit than the password flow for mobile, embedded webviews, and games — no password to remember, no inbox round-trip to a browser-opened verify URL. requestEmailOtp always resolves successfully regardless of whether the email is registered — server uses uniform responses so an unauthenticated caller can't enumerate which addresses exist. Codes are 6 ASCII digits, expire in 10 minutes, single-use; the verify path returns a single INVALID_CODE error for every failure mode (wrong code / expired / exhausted attempts) so failure cases can't be distinguished by an attacker.

// 1. Request a code (always resolves).
await Amba.auth.requestEmailOtp('alice@example.com');
 
// 2. User types the 6-digit code from their email.
const session = await Amba.auth.verifyEmailOtp('alice@example.com', '123456');

SMS one-time passcode (OTP)

Sibling to email-OTP — same flow shape, phone-based delivery. Use when you need phone-number identity (rideshare drivers, delivery couriers, anywhere SMS is the user's primary contact), or when email deliverability is the bottleneck (some demographics check email rarely; SMS always reaches).

phone MUST be E.164 (starts with +, total 8–15 digits, no spaces or dashes). The SDK rejects non-conforming phones with a VALIDATION_ERROR before the network call. The SMS body includes a WebOTP-style @amba.host #<code> appstring iOS/Android use to surface "Tap to copy" suggestions.

Per-phone rate limits scale with project tier — Free: 3 requests per hour + 10 per day; Pro: 10/hour + 50/day; Scale: 50/hour + 500/day. SMS sends cost real money, so the free-tier caps are deliberately tight; upgrade if you need higher throughput.

// 1. Request a code (E.164 required).
await Amba.auth.requestSmsOtp('+15551234567');
 
// 2. User types the 6-digit code from their SMS inbox.
const session = await Amba.auth.verifySmsOtp('+15551234567', '123456');

Sign in with Apple

The SDK accepts the identity token returned by Apple's native authorization flow. You're responsible for triggering that flow on the platform — see the per-platform quickstart for the platform-native bridge.

// Pass the identity token from Apple's `AppleID.auth.signIn()` web SDK
await Amba.auth.signInWithApple(appleIdentityToken);

Sign in with Google

Pass the Google ID token from your platform's auth library.

// Pass the id_token from Google Identity Services
await Amba.auth.signInWithGoogle(googleIdToken);

Read current session

const isSignedIn = Amba.isAuthenticated; // boolean, synchronous
const userId = Amba.appUserId; // string or undefined
const me = await Amba.auth.me(); // full user record

Sign out

await Amba.auth.signOut(/* rotateAnonymousId? */ false);

signOut(false) keeps the anonymous identifier stable across the next sign-in. signOut(true) rotates it — use after binding an anonymous session to a real account so the next visitor on the same device starts fresh.

Patterns

Anonymous → linked account

Mint anonymous early, link real credentials later. The user's events, collections, and entitlements all carry over because the app_user.id is stable across the link:

// First visit
await Amba.auth.signInAnonymously();
await Amba.events.track('landing_viewed');
 
// Later, in the signup flow
await Amba.auth.signUpWithEmail(email, password);
// Same app_user.id; landing_viewed event still attributes to this user.

React hook subscription

useUser() re-renders when the auth state changes, so you don't have to wire your own listener:

import { useUser } from '@layers/amba-react';
 
function Avatar() {
  const { user, isAuthenticated } = useUser();
  if (!isAuthenticated) return <SignInButton />;
  return <img src={user!.avatar_url} />;
}

Server-side per-user scoping (Node)

For server contexts, amba.asUser(uid) returns a handle that acts as a specific user — auto-scoped on collections, events attributed to that user, etc.

const userId = req.session.userId; // however your app resolves end-user identity
const scoped = amba.asUser(userId);
await scoped.events.track('order_created', { order_id: order.id });

asUser(uid) requires the user to already exist. For fresh tenants, mint an anonymous session first to create the user, then call asUser() with the returned id.

Limits

  • Email format: standard RFC 5322 validation server-side.
  • Password length: 8–256 characters; no character-class requirements enforced server-side (recommend your own minimum entropy check in the UI).
  • Anonymous user rotation: cleared when the user explicitly signs out with rotateAnonymousId: true, or when the user installs your app fresh.
  • Session token lifetime: short-lived; the SDK schedules silent refresh ahead of expiry. You generally never call auth.refresh() manually.
  • Apple identity token freshness: must be passed to the SDK immediately. Don't cache and reuse — Apple's tokens are short-lived.

Reference

On this page