Authentication
Three auth modes for the Profile API — SSO bearer and session cookie for first-party UI, service key for server-to-server.
SSO Bearer (first-party UI)
Pass the Supabase session access token as a Bearer token. The acting user_id is derived from the verified token subject — no ?user_id param needed.
GET https://api.misar.io/io/profile
Authorization: Bearer <supabase_access_token>
Session Cookie (same-origin)
Same-origin requests from www.misar.io are authenticated by the first-party Supabase session cookie. The account page uses this mode for GET/PATCH and for avatar upload.
GET https://www.misar.io/io/profile
Cookie: sb-<project>-auth-token=…
Service Key (server-to-server)
Used by MisarMail, MisarReach, and any other Misar product reading a user's profile on their behalf. Pass the service key in a custom header plus the target user's central UUID as a query param.
GET https://api.misar.io/io/profile?user_id=<uuid>
x-profile-service-key: <PROFILE_SERVICE_KEY>
Environment variable
The service key is stored in the PROFILE_SERVICE_KEY environment variable on the calling product's server, alongside WALLET_SERVICE_KEY and AUDIENCE_SERVICE_KEY. Never expose it in client-side code.
Avatar upload is first-party only
POST /io/profile/avatar rejects the service key with 403. Avatar uploads must come from a first-party authenticated session — products read the resulting avatar_url, they do not write it.
Resolving the central user id
Products provision users in their own Supabase and store the central id in user.user_metadata.sso_provider_user_id. Use that value as ?user_id when calling with the service key:
const BASE = process.env.PROFILE_SERVICE_URL ?? "https://api.misar.io/io/profile";
const centralId = user.user_metadata.sso_provider_user_id;
const profile = await fetch(`${BASE}?user_id=${centralId}`, {
headers: { "x-profile-service-key": process.env.PROFILE_SERVICE_KEY! },
cache: "no-store",
}).then((r) => (r.ok ? r.json() : null));