Scopes and claims
The five supported OIDC scopes and the exact claims each one returns.
Scopes and claims
Hep.gg supports five scopes. You request them space-delimited in the scope parameter at the authorize endpoint. Two rules always apply:
- The scope set must include
openid. A request without it is rejected withinvalid_scope. - Each requested scope must be enabled for your app (its allowed scopes, which you choose in the app's settings). Requesting a scope your app is not allowed is rejected with
invalid_scope.
The granted scopes are recorded in the access token and echoed in the token response's scope field. The same scopes drive what UserInfo and the id_token return.
Scope catalog
| Scope | Effect |
|---|---|
openid | Required. Enables OIDC and the id_token. On its own it yields the sub claim. |
profile | Adds name, nickname, preferred_username, and picture. |
email | Adds email and email_verified. |
groups | Adds groups, the user's Hep.gg login-group names. |
offline_access | Causes the token endpoint to return a refresh_token. No effect on claims. |
Claims by scope
sub is the stable Hep.gg user ID. It is always present and is the value you should key your local user records on. It is never reassigned.
subemailemail_verifiedtrue when the email has been verified. Hep.gg requires a verified email before completing the flow, so this is true in practice.namenicknamename. Present only when the user has set a username.preferred_usernamepicturegroupsThe preferred_username caveat
preferred_username is meant to be a handle that downstream apps can adopt as a local username. Many self-hosted apps (Vaultwarden, Vikunja, GlitchTip, Cloudflare Access) validate usernames against a pattern like [a-zA-Z0-9._-]+ and reject the login outright if the value does not match.
Hep.gg display names are free-form Unicode, so the raw name is not safe for those validators. To make preferred_username always usable, Hep.gg derives it as follows:
- Take the display username and strip it to the character set
[a-zA-Z0-9._-], truncated to a maximum of 64 characters. - If that leaves nothing usable (for example an all-emoji username), fall back to the email local-part (the portion before
@), sanitized the same way. - If that is still empty, fall back to the user ID.
The result is therefore never empty. If you need the user's full, original display name, read name or nickname instead, which carry the raw value verbatim.
Requesting offline_access
offline_access does not change the claim set. It tells the token endpoint to issue a refresh_token alongside the access token, so your app can obtain new access tokens without sending the user back through the browser. See Refresh tokens for rotation and reuse-detection rules.