Skip to content

ARAP: signed approval state has no interoperable payload #659

Open

Description

@mcguinness

Problem

The Interoperability Baseline requires every PDP to support verifying an approval.state presented as a JWS, but no claim set is defined. Two implementations can both conform to that requirement and share no payload, so the portable bound-reference flow the profile describes is not reachable without a bilateral agreement.

The two binding boundaries are not symmetric. The denial side specifies issuer, audience, expiry, replay, the authorization-relevant Context member set, and an inline-or-hash representation of the bound tuple. The approval side specifies iss, aud, key discovery, and an unnamed equivalent of binding_context_members, while Approval Verification requires the PDP to determine the approval identifier, the task identifier, the original evaluation identifier, the approved Subject, Resource and Action or scope, requester and client binding, status, approval times, and revocation state.

Three further questions depend on the same claim set.

Approval scope has no portable representation. Exact-match scope is the stated interoperability baseline, yet the signed form carries no standardized representation of the approved tuple, so exact match works naturally only where the PDP can look the approval up in trusted state.

approved_until conflates two lifetimes. It is REQUIRED, and it is read as both the validity of the approval evidence and the lifetime of the authority the approval established. An approval that provisions a durable entitlement has no natural value for it.

Current-status checking is unsatisfiable for a self-contained artifact. The PDP MUST check whether an approval was revoked, cancelled, or superseded before approved_until. A signed artifact proves what was true when it was signed. It cannot prove that nothing has changed since. As written, the rule cannot be met in the topology that signed approval state exists to serve.

Recommendation

Define an Approval State JWT, structurally parallel to the denial binding claims: iss, aud, iat, exp, jti, approval_id, task_id, evaluation_id when available, the approved subject, resource and action or approval_scope, binding_context_members, and requester and client binding.

Carry the approved tuple inline or as a hash, using the same canonical construction as denial binding. Denial binding then proves the tuple that may be requested and approval binding proves the tuple that was approved, and exact-match scope becomes portable without a lookup.

State that approved_until bounds use of the Approval Result, not the lifetime of the authority the approval established. Renaming it is a wire change and should travel with the claim set if the group wants one.

Replace the single current-status rule with three validity models:

  • Lookup approval, approval.id resolved in trusted state: current status can be checked, so revocation, cancellation, and supersession MUST be enforced.
  • Signed approval with an online status source: current status can be checked and MUST be.
  • Self-contained signed approval: the artifact is valid through its protected expiry unless current PDP policy independently denies. Early revocation requires a profile-defined status or revocation mechanism.

Considered and rejected

A refreshed-proof design, in which a status resource keyed by the approval identifier reissues approval.state to an authorized PEP while the approval remains active. It fails on availability: refreshing at enforcement time makes the service a dependency of already-granted access, and the profile's fail-closed guidance then turns a service outage into fleet-wide revocation. It also requires the PEP to read an expiry it is forbidden to parse, and a distinct denial reason code.

Related

Five independent reviews of the restructured draft named this the largest remaining interoperability hole.

Whatever is decided here must be checked against the AuthZEN Access Request OAuth Profile, which places the PEP and PDP roles in three ways: an authorization server evaluating and deferring its own token request, a protected resource asserting the denial as a signed challenge, or both acting as PEP.

Once the claim set settles, the illustrative tokens need correcting. The approval.state in the base draft decodes to an approval identifier alone, with none of the iss, aud, or exp that the text requires or that verification depends on, and the one in the callback profile expires thirty minutes before its own approved_until, which is the lifetime question above shown by example. That is an editor task, not a decision for this issue.

Activity

  1. aeoess commented on Sep 22, 2026

    @aeoess

    The three validity models look right to me. One thing the online-status model needs, which is also where the rejected refresh design went wrong: status results should be three-valued, not two. When the status source is unreachable, the answer is unknown, not revoked. A PDP can still deny on unknown, but with its own reason code, so an outage stays an outage in audit and retry handling and is never recorded as a revocation of granted access.

    I've been testing this exact split in an open delegation-revocation implementation: active only with positive current-state evidence, revoked only with a verified revocation record, and unknown otherwise. The verifier treats unknown as indeterminate rather than valid. I also have deterministic negative vectors around this if a concrete status-model case would be useful.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions