Authorized Apps

These endpoints manage the authenticated consumer account's OAuth consent. They are separate from registration ownership, organization invitations, app-to-app connections, and root SSO session revocation.

Use JSON POST requests at https://api.user.m7.org/api/v2 and the standard API response envelope. Responses are non-cacheable. Send the consumer access token and required binding headers. Each operation requires its corresponding account.me.authorized_apps.list, .view, or .revoke scope. Machine and organization credentials cannot select another user; uid, user, user_id, tenant, org, and owner inputs are rejected.

Method Route under /api/v2 Input
POST /account/me/authorized-apps/list None
POST /account/me/authorized-apps/view application_id
POST /account/me/authorized-apps/revoke application_id, optional boolean revoke_sessions; revocation_request_id when true

application_id is the internal registration UUID returned by list. View shows individual immutable permission snapshots. The grouped scope/resource union in list is a display summary, never an authorization grant. List returns comment: "OK" with data.items (an unpaginated array, empty when there is no saved consent or pending revocation). Each item contains application_id, client_id, name, last_consented_at, grant_count, scopes, audiences, session_revocation, and nullable revocation_request_id. Results sort by latest consent first, then application name. An unavailable registration can retain its consent summary; it does not become an active application.

View returns comment: "OK" with the application summary and grants: each grant has id, consented_at, scopes, audiences, and flow (browser, browser_direct, device, or null). Pending revocation can include withdrawn snapshots so its original work remains visible. A missing account/app consent returns HTTP 404 with the normal failure envelope.

For example, list the signed-in consumer’s authorizations:

curl --fail-with-body --silent --show-error \
  --request POST 'https://api.user.m7.org/api/v2/account/me/authorized-apps/list' \
  --header 'Authorization: Bearer ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{}'

For a bound token, add the required sender proof.

Revocation choices

With revoke_sessions: false (the default), revoke removes saved consent and leaves issued tokens under their normal expiry and rotation rules. The response includes revoked_count, session_revocation: "not_requested", and tokens_revoked: 0.

To withdraw current token access as well, send:

{
  "application_id": "APPLICATION_UUID_FROM_LIST",
  "revoke_sessions": true,
  "revocation_request_id": "FRESH_REQUEST_UUID"
}

Generate a new revocation_request_id UUID for each new action. Reuse it for every retry of that action, including an ambiguous/lost response. The server freezes the account/app's original grant IDs in a durable request before remote work. A request ID cannot be reused by another account or for another app. Retries use that snapshot even after completion and cannot revoke a newer grant.

session_revocation is "complete" only after Identity confirms every grant's access and refresh sessions revoked. "pending" means saved consent is already revoked but remote termination still requires retry. The request ID is echoed; tokens_revoked counts confirmed token-session changes. List retains pending work with its revocation_request_id, so users can retry after reloading. remaining_application, when present, describes a newer active authorization that must stay visible after the old request completes.

Revocation affects the selected account/app's grant-bound access and refresh records, including sibling tokens, descendants, grace predecessors, and pending ACK candidates. The shared SSO root, unrelated apps and other users remain active. Issuance and revocation serialize on an immutable Identity grant binding; revoking an old grant never bans later approval with a new grant ID.

Online Identity validation rejects revoked tokens. Offline JWT verification cannot observe server-side revocation until expiry. This operation does not delete application-owned browser cookies or broadcast root-session logout.

After deploying grant/session linkage to this pre-release system, obtain fresh tokens once. Earlier issued tokens have no durable consent ID: refresh requires fresh authorization, and unlinked access tokens retain their existing expiry. They are never guessed from a shared root or broadly revoked across apps.

Errors and recovery

Revoke returns comment: "REVOKED" with the application_id and the result fields above. Check the envelope’s status and session_revocation; HTTP success alone does not mean remote token termination completed. Invalid application/request UUIDs, a nonboolean revoke_sessions, or a principal selector fail through the ordinary API failure envelope. A request UUID owned by another account or app returns HTTP 403 with Revocation request is unavailable.

When a session revocation is already pending, do not initiate a consent-only withdrawal or invent a new request UUID. Recover the stored request UUID from list and repeat the same revoke request with revoke_sessions: true. A new approval requires a new authorization transaction. See the SSO consent contract.