> ## Documentation Index
> Fetch the complete documentation index at: https://docs.grantex.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# AI Agent Authorization Guide for 2026: Scopes, Consent, and Revocation

> Implement AI agent authorization with scoped grants, consent, JWT verification, current revocation checks, and TypeScript and Python examples.

AI agent authorization is the policy and enforcement layer that determines which agent may perform which action for which principal. It supplements authentication: identifying a workload or API client is not the same as deciding whether a particular agent may invoke a particular tool now.

This guide explains the implementation boundaries that matter in production: agent identity, scoped consent, token verification, action-boundary enforcement, current revocation state, and explicit audit integration.

## What Is AI Agent Authorization?

An agent often selects tools at runtime. The protected service therefore needs more context than a valid application credential:

* the agent identity;
* the principal or organization that approved the authority;
* the exact scopes granted to that agent;
* the token audience and expiry;
* any delegation constraints; and
* the current grant state when revocation freshness matters.

The service that executes the action is the final enforcement point. A prompt, tool description, or framework wrapper can reduce mistakes, but it should not be the only authorization control.

## How API Keys, OAuth, and Agent Grants Fit Together

These mechanisms solve overlapping but distinct problems; they are not mutually exclusive.

**API keys and service credentials** can be appropriate for application-to-service authentication. Providers may support restricted keys, rotation, access policy, and audit records. A shared credential usually does not, by itself, identify the individual agent and approving principal for each action. Keep upstream credentials behind the service boundary where possible.

**OAuth 2.0 and OpenID Connect** provide mature authorization and identity building blocks, including scopes, consent, token expiry, and revocation mechanisms. An implementation can model agents with OAuth-native concepts. Agent-specific identity, delegation-chain rules, and per-tool policy still need explicit claim semantics and enforcement.

**Grantex grant tokens** carry agent, principal, scope, expiry, and delegation context for the protected service to verify. Grantex complements upstream OAuth, identity providers, secret managers, and provider credentials rather than replacing them.

For MCP over HTTP, use an authorization server that follows the current MCP authorization specification for transport access. Add agent-specific checks inside the MCP tool or protected downstream service when tool authority must be narrower than transport access.

## A Delegated Agent Authorization Flow

A typical flow has seven explicit steps:

1. **Register the agent.** The developer registers the agent and its permitted scope catalog. Grantex returns an agent ID and DID.
2. **Request authority.** The application requests exact scopes for a known principal and redirect URI.
3. **Collect consent.** The principal reviews the request. The application receives a code only after approval.
4. **Exchange the code.** The application exchanges the callback code for a signed grant token.
5. **Verify at the action boundary.** The protected service validates the signature, issuer, audience, expiry, and required scopes before executing the action.
6. **Check current state when required.** Local JWT validation cannot discover a later revocation on its own. Use an online grant check or synchronized revocation data for current status.
7. **Record configured events.** The application or gateway explicitly records authorization decisions and action outcomes. External tool calls are not automatically audited merely because a token exists.

Scope names should describe the resource and action clearly, such as `calendar:read` or `payments:initiate:max_500`. The SDK manifest enforcer uses `tool:{connector}:{permission}`, for example `tool:expense-api:write`.

## Install the Current SDKs

The SDKs are independently versioned. These pins match the current published releases documented in the machine-readable implementation guide:

```bash theme={null}
npm install @grantex/sdk@0.3.13
python -m pip install grantex==0.3.14
```

Check [release status](/release-status) before changing versions.

## TypeScript: Register, Authorize, Exchange, and Verify

```typescript theme={null}
import { Grantex, verifyGrantToken } from '@grantex/sdk';

const gx = new Grantex({ apiKey: process.env.GRANTEX_API_KEY });
const principalId = 'user_alice';

const agent = await gx.agents.register({
  name: 'expense-report-agent',
  description: 'Reads receipts and creates expense reports after approval',
  scopes: ['tool:expense-api:read', 'tool:expense-api:write'],
});

const auth = await gx.authorize({
  agentId: agent.id,
  userId: principalId,
  scopes: ['tool:expense-api:read', 'tool:expense-api:write'],
  redirectUri: 'https://app.example.com/auth/callback',
});

console.log('Send the principal to: ' + auth.consentUrl);

// Call this from the registered callback after reading its code parameter.
export async function finishAuthorization(code: string) {
  const token = await gx.tokens.exchange({ code, agentId: agent.id });

  const localGrant = await verifyGrantToken(token.grantToken, {
    jwksUri: 'https://api.grantex.dev/.well-known/jwks.json',
    requiredScopes: ['tool:expense-api:write'],
  });

  // Online verification checks current server-side grant state.
  const currentGrant = await gx.grants.verify(token.grantToken);

  return { token, localGrant, currentGrant };
}
```

`verifyGrantToken()` validates cryptographic and JWT claims after resolving the issuer's JWKS. The TypeScript verifier keeps a bounded process-level JWKS resolver cache. That cache is about signing keys, not grant revocation.

`gx.grants.verify()` performs an online check. Use it, or an equivalent synchronized state mechanism, when the service must reject a grant that was revoked after the JWT was issued.

## Python: The Same Flow with Current Types

```python theme={null}
import os

from grantex import (
    AuthorizeParams,
    ExchangeTokenParams,
    Grantex,
    VerifyGrantTokenOptions,
    verify_grant_token,
)

client = Grantex(api_key=os.environ["GRANTEX_API_KEY"])
principal_id = "user_alice"

agent = client.agents.register(
    name="expense-report-agent",
    description="Reads receipts and creates expense reports after approval",
    scopes=["tool:expense-api:read", "tool:expense-api:write"],
)

auth = client.authorize(AuthorizeParams(
    agent_id=agent.id,
    user_id=principal_id,
    scopes=["tool:expense-api:read", "tool:expense-api:write"],
    redirect_uri="https://app.example.com/auth/callback",
))

print(f"Send the principal to: {auth.consent_url}")

# Call this from the registered callback after reading its code parameter.
def finish_authorization(code: str):
    token = client.tokens.exchange(ExchangeTokenParams(
        code=code,
        agent_id=agent.id,
    ))

    local_grant = verify_grant_token(
        token.grant_token,
        VerifyGrantTokenOptions(
            jwks_uri="https://api.grantex.dev/.well-known/jwks.json",
            required_scopes=["tool:expense-api:write"],
        ),
    )

    current_grant = client.grants.verify(token.grant_token)
    return token, local_grant, current_grant
```

The current Python verifier retrieves JWKS during each `verify_grant_token()` call. It still checks signatures and claims, not current revocation state. The online `client.grants.verify()` call supplies that state check.

## Enforce a Tool Manifest Before Execution

The TypeScript SDK can map connector tools to permission levels. Loading a manifest does not intercept every tool automatically; your application must call `enforce()`, use a configured wrapper, or place equivalent middleware at the execution boundary.

```typescript theme={null}
import { Permission, ToolManifest } from '@grantex/sdk';

gx.loadManifest(new ToolManifest({
  connector: 'expense-api',
  description: 'Internal expense service',
  tools: {
    read_receipt: Permission.READ,
    create_report: Permission.WRITE,
  },
}));

// Obtain token from finishAuthorization() above.
await gx.grants.verify(token.grantToken); // current-state check

const decision = await gx.enforce({
  grantToken: token.grantToken,
  connector: 'expense-api',
  tool: 'create_report',
});

if (!decision.allowed) {
  throw new Error(decision.reason);
}

// Call the expense API only after the decision is allowed.
// After the action completes, explicitly record the outcome if desired:
await gx.audit.log({
  agentId: agent.id,
  agentDid: agent.did,
  grantId: token.grantId,
  principalId,
  action: 'expense-api.create_report',
  status: 'success',
});
```

`enforce()` verifies the JWT through the configured JWKS URI and evaluates the loaded manifest. It does not perform the online grant-state check shown immediately before it. Keep both checks at the same trusted boundary when current revocation is required.

Audit logging is also explicit. `gx.audit.log()` records the event submitted by the application; it does not prove that every external side effect was captured. Log denied decisions, attempted actions, and final outcomes according to your threat model.

## Local Verification Versus Current Revocation

This distinction is central to JWT-based authorization:

| Check                        | What it establishes                                                       | What it does not establish                   |
| ---------------------------- | ------------------------------------------------------------------------- | -------------------------------------------- |
| Local JWT verification       | Trusted signature, expected claims, expiry, audience, and required scopes | Whether the grant was revoked after issuance |
| Online grant verification    | Current status known to the authorization service                         | Availability without a network path          |
| Synchronized revocation data | Current status up to the last successful synchronization                  | Changes newer than the local snapshot        |
| Short token lifetime         | Bounds how long an unrefreshed token remains usable                       | Immediate revocation                         |

Revoking a grant updates authorization state:

```typescript theme={null}
await gx.grants.revoke(token.grantId);
```

An enforcement point learns about that change only when it performs an online check, consumes updated revocation state, or waits for the token to expire. Key rotation and JWKS refresh are separate from grant revocation.

## Design Checklist

Before enabling an agent action:

1. Give each agent a stable identity separate from the application credential.
2. Request only the scopes required for the current workflow.
3. Bind tokens to the intended audience where supported.
4. Verify signature and claims at the service that executes the action.
5. Map every exposed tool to an explicit required scope or permission.
6. Choose an online or synchronized revocation strategy based on freshness and availability needs.
7. Keep upstream provider credentials behind the enforcement boundary.
8. Record authorization decisions and action outcomes explicitly.
9. Test missing scopes, unknown tools, expired tokens, revoked grants, stale state, and issuer mismatches.

## Frequently Asked Questions

### Are API keys unsuitable for every AI agent?

No. API keys can authenticate an application to a provider and may support useful restrictions. The risk is treating a shared application credential as sufficient evidence that a particular agent was authorized by a particular principal for a particular action.

### Does agent authorization replace OAuth 2.0?

No. OAuth can provide transport authorization, delegated user access, token lifecycle, and identity integration. Agent-specific claims and per-tool policy can be built with OAuth or layered alongside it. Grantex focuses on that agent-specific authority and enforcement context.

### Does local verification immediately reject a revoked grant?

No. Local JWT verification sees the signed token and available keys. It needs an online state check or synchronized revocation data to learn that an otherwise unexpired token was revoked.

### Does Grantex automatically audit every agent action?

No. The SDK exposes audit APIs and integrations, but the application or gateway must submit the relevant decision and outcome events at the execution boundary.

### How does this relate to MCP?

MCP connects clients to tools and defines OAuth-based authorization for HTTP transports. Agent-specific authorization answers a narrower action question: which agent may call which tool for which principal. Use both layers when both transport access and delegated tool authority matter.

## Next Steps

* Follow the [quickstart](/quickstart) for the complete callback flow.
* Read [scope enforcement](/guides/scope-enforcement) for manifest and middleware patterns.
* Review [offline verification](/sdks/typescript/offline-verification) before choosing a revocation strategy.
* See the [MCP authorization guide](/blog/mcp-server-oauth-authentication) for transport and tool-boundary architecture.
* Check the [protocol specification](/protocol/specification) for the normative grant model.
* Inspect the [Apache-2.0 repository](https://github.com/mishrasanjeev/grantex).

The important design decision is not which label to use. It is where the protected action is enforced, which claims are verified there, and how that enforcement point obtains current authorization state.
