Authorization State
What Authorization State Is
Authorization state determines whether a subject is currently permitted to access a resource.
This document defines the states an authorization can occupy and the rules governing transitions between them.
Why It Matters
Different instruments (subscriptions, credits) have different state machines, but they share common concepts:
- active vs inactive
- why authorization lapses
- how it recovers
This document provides the common vocabulary for reasoning about authorization across all instrument types.
State Definitions
Active
The subject is currently authorized.
For subscriptions: payment has occurred and the access window has not expired.
For credits: credits have been allocated and not fully consumed.
isActive() returns true.
Inactive
The subject is not currently authorized.
This is the absence of active authorization. It may be temporary (awaiting payment) or permanent (canceled).
isActive() returns false.
Paused
The user has explicitly suspended their authorization.
The subscription or envelope exists and may have remaining value, but the user has chosen to halt execution. No payments process while paused.
Resuming returns to the previous state (minus any time elapsed).
Expired
The authorization's time bounds have been exceeded.
For subscriptions: lastPaidAt + interval + gracePeriod < now
For credits: the Permit2 allowance expiration has passed
Expiration is automatic. No transaction is required.
Exhausted
The authorization's usage bounds have been exceeded.
For subscriptions: remainingExecutions == 0
For credits: creditsConsumed == batchAmount
Exhaustion requires explicit action to reach.
Settled (Credits Only)
A credit batch has been fully consumed and is awaiting the next payment.
isSettled == true means the envelope is ready for a keeper to trigger the next batch purchase.
Subscription State Transitions
Trigger: Time
Subscriptions are time-driven. The key question:
Has enough time passed since the last payment that access should continue?
Access window = lastPaidAt + interval + gracePeriod
If now <= accessWindow, the subscription is active.
Key Transitions
| From | To | Trigger |
|---|---|---|
| Awaiting Payment | Active | First payment executes |
| Active | Due | now >= nextChargeAt |
| Due | Active | Payment executes |
| Active | Paused | User pauses |
| Paused | Active | User resumes |
| Active | Expired | Access window passes |
| Active | Exhausted | No remaining executions |
What isActive() Checks
- Subscription exists
lastPaidAt > 0(at least one payment made)now <= lastPaidAt + interval + gracePeriod
If all three are true, the subscription is active.
Credit State Transitions
Trigger: Usage
Credits are usage-driven. The key question:
Has the agent consumed all allocated credits in this batch?
If creditsConsumed < batchAmount, credits remain. The agent is active.
If creditsConsumed == batchAmount, the batch is exhausted.
Key Transitions
| From | To | Trigger |
|---|---|---|
| Settled | Active | Payment executes |
| Active | Active | Checkpoint submitted |
| Active | Exhausted | Full batch consumed |
| Exhausted | Settled | Settlement voucher submitted |
| Active | Paused | User pauses |
| Paused | Active | User resumes |
What isActive() Checks
- Envelope exists
isSettled == false(has funded credits)- Not paused
- Subject matches subscriber or agent
If all are true, the agent is active.
Subscriptions vs Credits
| Aspect | Subscriptions | Credits |
|---|---|---|
| Trigger | Time | Usage |
| Active means | Within paid access window | Has unconsumed credits |
| Inactive means | Access window expired | Batch exhausted or unfunded |
| Payment timing | Predictable intervals | When batch depletes |
| User action | Mostly passive | Agent consumes actively |
| Grace period | Time-based buffer | None |
Execution Failures and State
Failed executions do not change authorization state.
If a keeper attempts execution and it fails:
- Idempotency is not consumed (can retry)
- Module state is unchanged
- Authorization remains as it was
The only state changes occur on successful execution:
lastPaidAtupdates (subscriptions)sequenceadvances (credits)remainingExecutionsorremainingBatchesdecrements
Failures are logged but do not corrupt state.
Deriving Access From Chain State
Access is always computable from on-chain state alone.
For subscriptions:
active = (lastPaidAt > 0) && (now <= lastPaidAt + interval + gracePeriod)
For credits:
active = (isSettled == false) && (paused == false)
No off-chain state is required. The indexer may cache these computations, but any party can verify by querying the chain directly.
This is the core trust property: authorization is derived from immutable on-chain facts, not from a database that could be modified.
Relationship to RAI
Authorization state is the core primitive of Recurring Authorization Infrastructure.
The entire system exists to answer one question reliably:
Is this subject authorized to access this resource right now?
State transitions are the mechanics. Authorization is the product.
Non-Goals
The following are out of scope:
-
Subscription upgrades: Changing plans requires cancel and resubscribe.
-
Partial access: Authorization is binary. Tiered access is an application concern.
-
Historical queries: "Was this user active on date X?" requires event replay.
-
Cross-instrument authorization: A subscription does not grant credits. Each instrument is independent.
-
Automatic reactivation: Expired authorizations do not self-heal. User action is required.