AUTH4D-64 guest claim in access tokens

Access tokens issued to a guest player carry the GUEST_CLAIM defined in AUTH4D-55 (repository file docs/api-spec/auth4d-55.md):

{ "sub": "usr_…", "token_use": "access", "scope": "openid profile", "auth4_guest": true }

When the claim is set

A user is a guest while it has a guest identity and no other identity. Upgrading attaches an email or Discord identity and keeps the guest identity, so an upgraded user is not a guest.

The session service (packages/sessions) reads this from D1 (isD1GuestUser, primary read, tenant-scoped) every time it signs an access token:

Issued by Guest user Upgraded or regular user
POST /t/{tenantId}/guest (AUTH4D-15 (repository file docs/api-spec/auth4d-15.md)) "auth4_guest": true n/a
POST /t/{tenantId}/guest/upgrade n/a claim absent
POST /oauth/token with authorization_code or device_code "auth4_guest": true claim absent
POST /oauth/token with refresh_token "auth4_guest": true claim absent

Refresh checks the claim again, so a guest that upgrades on another device loses the claim on its next refresh. Access tokens issued before the upgrade keep the claim until they expire, which takes at most five minutes.

The claim is either true or absent. Auth4 never sends false. An absent claim means “not a guest”, so tokens issued before this change stay valid and are read as non-guests. If the guest lookup fails, the session service throws user_unavailable and the endpoint returns its usual error for that case. No token is issued with a guessed value. A failed refresh lookup does not rotate the presented refresh token.

Unchanged

  • ID tokens never carry the claim. IdTokenClaimsSchema rejects it.
  • UserInfo (GET /oauth/userinfo) does not return it.
  • The claim comes from server-side identity records only. Callers of the session service cannot supply it.

Server SDK

@auth4/sdk-server (AUTH4D-25 (repository file docs/api-spec/auth4d-25.md)) returns isGuest: boolean in VerifiedAccessTokenClaims (and Auth4GuestClaims). It is true only when auth4_guest is true. A non-boolean value makes the token invalid. The speculative, never-issued guest field the SDK accepted before has been replaced by isGuest. Tokens that contain an unknown guest claim are now rejected by the strict contract schema.

Source: docs/api-spec/auth4d-64.md