User ids

What sub is, why it is different on every site by default, when you get the UNET user id instead, and what to key your own users table on.

When a person signs in, UNET tells your app who they are with a value called sub (the "subject"). It is the key your own user table should be built on. What sub is depends on the kind of app.

Two kinds of id

Per-site id (pairwise)The UNET user id (public)
What sub isA stable value private to your siteThe UNET user id, a number written as a string
Same person on another siteA different valueThe same value
Can two sites tell they know the same person?NoYes
Default forSign-in-only appsApps that use the REST API

The per-site id is derived from the person and from your site, so the same person always has the same sub on your site, never a value you can match against another site, and never the number that appears in the UNET API.

Which one your app gets

The kind is set when the app is created, and the console picks a default:

  • Per-site when the app asks only for openid, profile and offline_access, and all its return URLs are on one host.
  • The UNET user id when the app has any REST API permission. The REST API shows real UNET user ids everywhere, so a per-site sub would only make it harder to tell which user is "me".
  • If you choose a kind yourself under Advanced when you create the app, you get what you chose. A per-site id needs all return URLs on one host.

What counts as "your site"

  • For a website with a server, the site is the registered domain. Two apps registered on the same domain see the same id for a person.
  • For a single-page site or an app (a public app, which has no verified domain), the site is the App ID. Two such apps see different ids even for the same person.

What to key your table on

Key your users by sub, and only by sub.

  • username can change. Show it, do not key on it.
  • displayName is free text. Show it, do not key on it.
  • There is no email address: UNET accounts have none. See Privacy.
const user = await unet.restore();
if (user) {
  // your own table: key by user.sub, keep the name only as something to show
  console.log(user.sub, user.username);
}

On your server, take sub from a token you verified, never from what the browser sends. See Verify on your server.

Getting the UNET user id

If your app has a REST API permission, the API gives you the real id: Profile.id and the id of every author it returns. For example, to find your own:

const me = unet.getUser();
if (me?.username) {
  const { profile } = await unet.api.profile(me.username); // needs content:read
  console.log(profile.id);
}

An app that signs in only for identity, with a per-site id, cannot get the UNET user id. That is by design: it is what keeps two sites from recognising the same person.

The avatar

The profile has the picture as avatarUrl, ready for an image tag. The raw avatar value is an internal storage key that older apps read; use avatarUrl. The userinfo endpoint also returns a standard picture claim with the same address. A person with a private account may not have their picture served to the public, so it can fail to load on your site.