Skip to content
Documentation menu

Guides

Authentication and permissions

Understand member consent, server-side login, profile permissions, and credential expiry.

Authentication flow

Every app must implement backend authentication, including apps with no profile scopes. A serverless function can serve as the backend. The version 2 iframe bridge carries readiness and authorization codes; member IDs and profile fields are available only through the authenticated REST API.

  1. Run the browser code in the registered iframe and complete ready.
  2. Have your backend generate a random state challenge bound to the visitor's server-side session.
  3. Call iframe authenticate with the current launchId and that state. Zetapad requests member consent.
  4. Receive only { code, expiresIn, state } from the bridge and forward the code and state to your backend.
  5. Validate and consume state in the same visitor session, then exchange the one-use code with your client ID and secret at POST /v1/apps/token.
  6. Call GET /v1/apps/userinfo with the returned bearer token to obtain the verified member.
  7. Establish app access in the server session and initialize the browser UI only after this succeeds.

Use the complete browser example and server example. The iframe receives the code; your backend retrieves userId, scopes, and approved profile fields from userinfo.

Why the backend is required

An app that trusts a browser request such as { "userId": "zp_member_123", "progress": 80 } lets the caller choose whose progress to overwrite. A member can change request bodies and browser code. A stable ID identifies a record; it does not prove who is making a request.

Your backend verifies the authorization code with Zetapad using credentials that stay on the server. Userinfo supplies the member identity for that session. Protected reads and writes use this verified userId rather than an ID in the request body or URL. Check current access before the action, even with scopes: [].

The iframe can render a public loading shell without credentials, but readiness or consent alone does not complete app login. Every app must finish the backend flow before enabling its experience. Zetapad enforces credentials for its member data; your hosted app enforces its own sessions, protected routes, and direct URL restrictions.

Identity in the browser

Your backend may return verified userId and approved display fields after login if your UI needs them. It may instead return only the fields the UI uses. The ID is not a secret, and sending it to the UI does not turn it into a credential. Client secrets and bearer tokens must remain on the backend.

On later requests, resolve the member through the server session. Do not authorize access using an ID the browser sends back, even if your backend originally returned it.

authenticate asks the member to approve every registered scope or cancel. Returning members reuse their saved approval. Changing the registered origin or required scopes asks for approval again.

Apps with no registered scopes still ask for approval to identify the member. The consent dialog explains that the shared Zetapad user ID lets developers recognize the same account across apps.

When the member cancels, the bridge returns CONSENT_DENIED and Zetapad closes the room. Your app should stop initialization and avoid automatically reopening consent.

Scope changes and reauthentication

Developers can edit published registrations. Every save invalidates existing launches, codes, and access tokens. Adding or removing registered scopes, or changing the launch origin, also invalidates remembered consent. Changes to the name, description, or URL path/query on the same origin preserve consent.

Your backend must verify current userinfo and its scopes before enabling features that require those permissions, even when the visitor has an existing app session. Approval of an earlier scope list does not authorize newly requested scopes; this system grants the complete current list rather than retaining partial access.

After ACCESS_REVOKED caused by an update, stop protected actions and polling and have the member reopen the room for a fresh launch. Run ready, generate fresh session-bound state, call authenticate, and exchange the new code on the backend. Zetapad presents the current permissions when new approval is required. Resume only after backend verification succeeds; stop on CONSENT_DENIED. Calling authenticate on the old launch cannot renew it after a registration save.

For app calls, clear stale grant, presentation, and tile bindings. The native call continues while app presentation returns to Zetapad. After renewed scope/origin consent, attach again and obtain native call approval before preparing a fresh presentation. Routine token expiry with unchanged configuration can use authenticate on the same valid launch and preserve the live call presentation.

Permissions and profile fields

ScopeFields addedMeaning
profile:readusername, name, countryCodeMember's current username, name, and country
birthdate:readbirthdateFull birthdate in YYYY-MM-DD format
calls:readSilent owning-tab call availability; public roster and hosted tilesStatus needs normal app consent; roster and tiles also require native approval for each app and participation
calls:controlCall invitation, stage, playback, and activity requestsRequires calls:read; native and server call rules apply

Successful REST userinfo responses always include userId, Zetapad's server-generated primary member ID shared across apps, and scopes. No profile or birthdate scope is required for this ID. It requires member approval and a token obtained with the app's client ID and secret.

An app with scopes: [] receives this ID after approval and can use it for saved experiences without collecting profile fields. scopes is the granted scope list. Unapproved fields are omitted. name, countryCode, and birthdate can be null until the member completes their profile. Do not treat omitted and null fields as the same condition.

username is a unique public handle of 3–30 lowercase letters, numbers, or underscores. Every member has one, including before profile completion. Members can change it anytime in their profile; the previous handle becomes available to another member. With profile:read, userinfo returns the current username on every read. Store app records under the permanent userId; use username for display and recognition. Existing profile approvals must be renewed once to include username sharing.

json
{
  "userId": "zp_member_...",
  "scopes": ["profile:read"],
  "username": "member_01",
  "name": "Member",
  "countryCode": "IN"
}

Client secrets, access tokens, Firebase IDs, Firebase tokens, and Zetapad account credentials are never provided as profile fields. Your app owns the handling and retention of data it receives.

Persist experiences across apps

userId is Zetapad's server-generated primary member ID. Treat it as an opaque string. It is not a Firebase UID, email address, or value generated separately by each app. Firebase identifiers remain private to Zetapad's sign-in mapping.

Store saved progress, preferences, or other member records under the userId returned by your backend's verified userinfo call. The same account receives the same userId across registrations and across later sessions, even after app disconnection and reconnection, secret rotation, or username and profile changes. Different accounts have different public IDs. Profile completion is not required.

Deleting and recreating an app registration also preserves the member's userId.

Authentication does not share an app's saved data automatically. Apps must implement their own storage and any intended sharing. Never accept a browser-supplied userId as proof of access; verify the session and userinfo before reading or writing member data.

Credential lifetime

CredentialLifetimeUsage
Launch ID1 hourBound to the current room; reopen the room when stale or expired
Authorization code60 secondsExchange once, using its registered app's credentials
Access token15 minutesRead approved userinfo from the backend

Obtain a fresh code through authenticate to renew access. There are no refresh tokens or browser-only token exchanges. The server example's visitor state challenge expires after five minutes and is consumed on a login attempt; this challenge belongs to your app.

Revocation and app sessions

Registration saves, member disconnection, unpublishing, deleting the app, and secret rotation end issued Zetapad access immediately. Republishing does not restore old codes or tokens. Rotation and unpublishing preserve remembered consent; scope or origin changes require it again. Deletion removes the registration and connections.

Check userinfo whenever a protected action relies on current Zetapad access, including after your app has created its own session. End that session's access when the token expires or userinfo fails. Disconnection prevents future Zetapad data reads; it cannot erase data your app already received.

Never put secrets or bearer tokens in browser code, iframe URLs, analytics, or logs. For route-level enforcement, follow restrict app access.