iOS SDK

Identity

Use anonymous sessions by default, or map your signed-in users to Gleam with a short-lived HS256 signed identity token.

Anonymous Sessions Work By Default

When start() runs without an existing authenticated session, Gleam creates or restores a stable anonymous SDK identity for the device. Users can submit and follow feedback before your app asks them to sign in.

The anonymous identifier is stored by the SDK. Do not replace it with an account ID; use signed identity when the host app knows the current user.

Signed Identity

For signed-in users, generate a short-lived JWT on your backend and pass it to identify(signedIdentityToken:). The token must be signed with HS256 using the project identity secret configured on the Gleam server.

Never generate this token in the iOS app. The signing secret is server-only.

Why not pass a raw user ID?

A user ID sent directly from the iOS app is only a client assertion and can be modified. A backend-signed token proves your server has authenticated the user, keeps the identity secret off the device, lets Gleam accept only the intended profile fields, and expires quickly if a token is leaked.

ClaimRequiredMeaning
subYesStable user ID from your product.
expYesUnix timestamp in seconds. Keep it short, for example five minutes.
audRecommendedGleam project ID, slug, or portal subdomain.
name, display_name, or displayNameOptionalDisplay name copied into the Gleam profile.
avatar_url, avatarUrl, or pictureOptionalAvatar URL copied into the Gleam profile.
emailOptionalUser email stored on the managed Gleam profile.

Backend signing helpers

Use the same HS256 claim shape from any backend runtime. Keep the identity secret server-only.

import { createHmac } from "node:crypto";

function base64urlJson(value: unknown) {
  return Buffer.from(JSON.stringify(value)).toString("base64url");
}

export function createGleamIdentityToken(input: {
  identitySecret: string;
  projectId: string;
  user: {
    id: string;
    name?: string | null;
    avatarUrl?: string | null;
    email?: string | null;
  };
}) {
  const header = { alg: "HS256", typ: "JWT" };
  const payload = {
    sub: input.user.id,
    aud: input.projectId,
    exp: Math.floor(Date.now() / 1000) + 5 * 60,
    name: input.user.name ?? undefined,
    avatar_url: input.user.avatarUrl ?? undefined,
    email: input.user.email ?? undefined,
  };

  const unsigned = base64urlJson(header) + "." + base64urlJson(payload);
  const signature = createHmac("sha256", input.identitySecret)
    .update(unsigned)
    .digest("base64url");

  return unsigned + "." + signature;
}

Exchange in Swift

let signedIdentityToken = try await backend.fetchGleamIdentityToken()
let capabilities = try await Gleam.shared.identify(
  signedIdentityToken: signedIdentityToken
)

if capabilities.authenticated {
  // Portal UI and notification APIs now run as the signed-in user.
}

Logout Order

Unregister the current APNs token before clearing the session. The SDK stores the token with the session that registered it, so unregisterCurrentDeviceToken() still works during logout.

Clear a signed-in SDK session

try await Gleam.shared.unregisterCurrentDeviceToken()
try Gleam.shared.clearSession()
try await Gleam.shared.refreshSession()