Skip to content

standardize GraphQL authorization errors - #3283

Draft
GregorShear wants to merge 2 commits into
agent/invite-link-capabilitiesfrom
agent/graphql-authorization-errors
Draft

standardize GraphQL authorization errors#3283
GregorShear wants to merge 2 commits into
agent/invite-link-capabilitiesfrom
agent/graphql-authorization-errors

Conversation

@GregorShear

@GregorShear GregorShear commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Description:

Standardizes terminal GraphQL authorization failures around runtime authorization requirements.

For caller-known scopes, the same requirement object is passed to the authorization evaluator and serialized into the GraphQL error, preventing the machine-readable contract from drifting from enforcement. Terminal denials include both the required capabilities and catalog prefixes:

{
  "code": "PERMISSION_DENIED",
  "authorization": {
    "requirements": [
      {
        "allOf": ["CreateInviteLink"],
        "catalogPrefixes": ["acmeCo/"]
      }
    ]
  }
}

For resources selected by opaque identifiers, the prefix remains internal. deleteInviteLink now returns the same client-visible response for a missing token and a terminal authorization denial, while still communicating the capability required by the operation:

{
  "code": "NOT_FOUND",
  "authorization": {
    "requirements": [
      {
        "allOf": ["DeleteInviteLink"]
      }
    ]
  }
}

The underlying ApiError remains attached as the non-serialized GraphQL error source. This preserves the existing stale-snapshot 307 refresh-and-retry flow and resolver behavior that intentionally downcasts selected permission denials.

Workflow steps:

Clients make the operation normally and inspect errors[].extensions after a terminal denial. Provisional denials continue through the existing retry response instead of returning a structured terminal error. For opaque resources, clients must not infer existence from the terminal NOT_FOUND response.

Documentation links affected:

None.

Notes for reviewers:

This PR is stacked on the invite-link capability PR. The opaque-resource test asserts that missing and denied errors are client-visible equivalents and that a sensitive internal prefix is absent from serialized output.

Validation:

  • cargo check -p control-plane-api
  • git diff --check

The focused control-plane unit-test target is currently blocked by five unrelated missing SQLx offline cache entries in service_accounts.rs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant