Skip to Content
MuoCeon Docs
Third-party OAuth IntegrationPermissions and security

Fine-grained authorization

RFC 9396 — use authorization_details to express "which object, which action".

Scope can only express "whether a class of permission exists", not "which object, which action". authorization_details (RFC 9396) adds that layer, and MuoCeon uses it to replace the proprietary "elevated action" string.

Not applicable to third-party applications

All three supported authorization detail types map to account self-management capabilities (managing verification methods, sessions and grant relationships), and only MuoCeon's own admin console requests them. Third-party applications should use scopes — see Scopes and audiences. This page documents the mechanism so you can understand token structure.

Request format

authorization_details is a JSON array, passed as a string in the authorization request:

&authorization_details=[{"type":"muoceon_session_management","actions":["session:revoke"]}]

Common fields of a single element:

FieldRequiredNotes
type✅The authorization detail type; must be on the server allowlist
actionsOptionalAllowed action list; omitting it means all actions of that type
locationsOptionalRestrict the location scope
identifierOptionalRestrict the object identifier

Up to 10 elements; unknown fields beyond type are preserved verbatim so downstream can read them per its own semantics.

Three authorization detail types

typeMeaningAllowed actions
muoceon_credential_managementVerification method managementpasskey:add, passkey:delete, authenticator:add, authenticator:delete, password:update, recovery_code:delete, oauth:unlink
muoceon_session_managementLogin session managementsession:revoke
muoceon_grant_managementOAuth grant managementgrant:revoke

This allowlist is the sole authority for "what a client may request". Letting arbitrary action strings into authorization codes or tokens would degrade action checks into "the client authorizing itself".

Server-side validation

Every submitted detail is checked item by item:

  • type not on the allowlist → 400 OAUTH_INVALID_AUTHORIZATION_DETAILS
  • An action in actions not permitted for that type → same error
  • Structurally invalid (not an array, more than 10 elements, empty type) → same error

The consent page expands validated details into human-readable permission entries for the user.

authorization_details in the token

After successful authorization, the details enter the access token:

{
  "authorization_details": [
    { "type": "muoceon_session_management", "actions": ["session:revoke"] }
  ]
}

Resource servers decide actions as follows:

  • Find the detail with the matching type;
  • actions omitted → all actions of that type are allowed;
  • actions explicitly listed → the action must match exactly.

Details that fail to parse are treated as "no fine-grained authorization" and never turn a request into a 500.

Two easy-to-miss boundaries

  • Refresh does not restore details: authorization_details hold only for the initial authorization and are not carried in refreshed tokens. To get new fine-grained authorization, the user must go through the authorization flow again.
  • Details and scopes are separate gates: details without sufficient scopes still get blocked by insufficient_scope, and vice versa.

On this page