Scopes and audiences
How permissions are named, which ones you may request, and what the token's aud actually decides.
Scope answers "what may be done", audience (aud) answers "to whom". They are two independent gates: a request can pass the scope check and still be rejected for the wrong audience.
Scope naming convention
Self-management scopes are always three segments:
<resource audience>:<object>:<action>For example auth:sessions:read means "perform read on the sessions object of the auth resource server". The benefit is that authorization can be derived directly from the name without a second mapping table, and logs immediately reveal which resource a scope belongs to.
OIDC standard scopes (openid, profile, email, offline_access) have no prefix — they belong to no resource audience and are classified separately.
Scopes you may request
Delegable scopes
| Scope | Meaning | Consent page label |
|---|---|---|
openid | Request OIDC identity: an id_token is issued at token exchange, and UserInfo becomes available | "Verify your identity" |
profile | Read nickname and display name (preferred_username, name) | "Read your basic profile" |
email | Read email address and verification status (email, email_verified) | "Read your email address" |
offline_access | Access continues while the user is away: a refresh token is issued | "Continue accessing while you are away" |
Self-management scopes (not available to third parties)
| Scope | Audience | Meaning |
|---|---|---|
auth:credentials:read | auth | List the user's verification methods |
auth:credentials:write | auth | Add or remove verification methods |
auth:sessions:read | auth | List active sessions |
auth:sessions:revoke | auth | Revoke sessions |
oauth:grants:read | oauth | List authorized applications |
oauth:grants:revoke | oauth | Revoke granted authorizations |
account:profile:read | account | Read the account's extended profile |
account:profile:write | account | Update the account's extended profile |
These scopes express "the user's authority over their own account". They appear only in MuoCeon's own management UI and are never delegated to third-party applications.
Audiences (aud)
| Audience | Resource identifier | Endpoints it covers |
|---|---|---|
auth (default) | {origin}/v1/auth | Session state, verification methods, sessions, UserInfo |
oauth | {origin}/v1/oauth | Authorized applications and grant management |
account | {origin}/v1/account | Account extended profile |
Tokens from third-party authorization carry the auth audience — because the only thing you can do is read the user's identity. There is neither a scope to request nor a grant type to use for obtaining oauth or account audience tokens.
The token's aud contains both the shorthand and the full resource identifier:
{
"aud": ["auth", "https://id.example.com/v1/auth"]
}- The shorthand is used by internal routing for allowlist comparison;
- The full URI is used by standard clients to compare against the RFC 9728 metadata's
resource.
If your library performs strict string array matching, compare against the full URI and the protected resource metadata — do not match on the shorthand alone.
Filtering: requesting is not receiving
The server filters scopes by client capability in both the code exchange and the refresh:
- Delegable scopes: allowed.
- Self-management scopes: allowed only for clients granted the corresponding audience at registration; filtered out for third parties.
- Filtering is a silent drop, not an error — the
scopein the response is the effective list.
Always read the scope in the response
Requesting openid profile email auth:sessions:read may actually return only openid profile email.
If you build downstream logic on "I requested it, so I have it", you will get a 403 insufficient_scope
when calling management endpoints instead of a clear error at token exchange.
Two more boundaries:
- On refresh,
scopemay only narrow; values outside the original grant yieldinvalid_scope. client_credentials(machineclients) cannot requestoffline_access— no user means no session to refresh.
Practical advice
- Request least privilege: if you only read identity, ask for
openid profile emailand do not addoffline_accessreflexively. offline_accessmeans you can still access data while the user is away; it is listed separately on the consent page, and overusing it measurably reduces consent rates.- Do not treat anything other than
subas a stable identifier: email changes, nicknames change,subdoes not. - Update your local record with the
scopereturned on every refresh; never carry the old value forward.