Skip to main content

Overview

The tokens client provides four operations for managing grant tokens:
  • Exchange an authorization code for a grant token
  • Refresh a grant token using a refresh token
  • Verify a grant token online via the Grantex API
  • Revoke a grant token by its token ID (JTI)
Access the tokens client via client.tokens.

Exchange

Exchange an authorization code for a grant token after the user approves the consent request.
from grantex import Grantex, ExchangeTokenParams

with Grantex(api_key="gx_live_...") as client:
    result = client.tokens.exchange(ExchangeTokenParams(
        code="auth_code_from_callback",
        agent_id="agt_abc123",
    ))

    print(f"Grant token: {result.grant_token}")
    print(f"Grant ID: {result.grant_id}")
    print(f"Scopes: {result.scopes}")
    print(f"Expires at: {result.expires_at}")
    print(f"Refresh token: {result.refresh_token}")

ExchangeTokenParams

FieldTypeRequiredDescription
codestrYesThe authorization code received at the redirect URI.
agent_idstrYesThe agent ID that initiated the authorization.
code_verifierstr | NoneNoThe PKCE code verifier, if PKCE was used during authorization.

ExchangeTokenResponse

FieldTypeDescription
grant_tokenstrThe JWT grant token.
grant_idstrThe unique grant identifier.
scopestuple[str, ...]The approved scopes.
expires_atstrISO 8601 timestamp when the token expires.
refresh_tokenstrA refresh token for obtaining new grant tokens.

Exchange with PKCE

from grantex import Grantex, ExchangeTokenParams

with Grantex(api_key="gx_live_...") as client:
    result = client.tokens.exchange(ExchangeTokenParams(
        code="auth_code_from_callback",
        agent_id="agt_abc123",
        code_verifier="dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk",
    ))

Refresh

Refresh a grant token using a refresh token. Returns a new grant token and a new refresh token (the old refresh token is invalidated). The grant_id stays the same. Refresh tokens are single-use and rotated on every refresh per SPEC §7.4.
from grantex import Grantex, RefreshTokenParams

with Grantex(api_key="gx_live_...") as client:
    new_token = client.tokens.refresh(RefreshTokenParams(
        refresh_token="rt_01HXYZ...",
        agent_id="agt_abc123",
    ))

    print(f"New grant token: {new_token.grant_token}")
    print(f"New refresh token: {new_token.refresh_token}")
    print(f"Same grant ID: {new_token.grant_id}")

RefreshTokenParams

FieldTypeRequiredDescription
refresh_tokenstrYesThe refresh token from a previous exchange() or refresh() response.
agent_idstrYesThe agent ID associated with the grant.

Response

Returns an ExchangeTokenResponse — same shape as exchange(). See above for field descriptions.
Each refresh token can only be used once. If you attempt to reuse a refresh token, the request will be rejected with a 400 error. Always store and use the new refresh_token from the response.

Verify

Verify a grant token online via the Grantex API. This sends the token to the server for validation and returns the token’s metadata.
from grantex import Grantex

with Grantex(api_key="gx_live_...") as client:
    result = client.tokens.verify("eyJhbGciOiJSUzI1NiIs...")

    if result.valid:
        print(f"Grant ID: {result.grant_id}")
        print(f"Scopes: {result.scopes}")
        print(f"Principal: {result.principal}")
        print(f"Agent: {result.agent}")
        print(f"Expires at: {result.expires_at}")
    else:
        print("Token is invalid or expired")

VerifyTokenResponse

FieldTypeDescription
validboolWhether the token is valid.
grant_idstr | NoneThe grant identifier (if valid).
scopestuple[str, ...] | NoneThe granted scopes (if valid).
principalstr | NoneThe user/principal ID (if valid).
agentstr | NoneThe agent DID (if valid).
expires_atstr | NoneISO 8601 expiration timestamp (if valid).
For offline verification that does not require a network call to the Grantex API, use the standalone verify_grant_token() function.

Revoke

Revoke a grant token by its token ID (JTI claim). The token is immediately invalidated and can no longer be used.
from grantex import Grantex

with Grantex(api_key="gx_live_...") as client:
    client.tokens.revoke("tok_abc123")
    # Returns None on success

Parameters

ParameterTypeDescription
token_idstrThe JTI (token ID) of the grant token to revoke.
The method returns None. A GrantexApiError is raised if the token does not exist or has already been revoked.

Complete Flow Example

from grantex import (
    Grantex,
    AuthorizeParams,
    ExchangeTokenParams,
    generate_pkce,
)

pkce = generate_pkce()

with Grantex(api_key="gx_live_...") as client:
    # 1. Start authorization with PKCE
    auth = client.authorize(AuthorizeParams(
        agent_id="agt_abc123",
        user_id="user_xyz",
        scopes=["files:read"],
        redirect_uri="https://myapp.com/callback",
        code_challenge=pkce.code_challenge,
        code_challenge_method=pkce.code_challenge_method,
    ))
    print(f"Redirect user to: {auth.consent_url}")

    # 2. After user approves, exchange the code
    code = "received_from_redirect"  # from your callback handler
    token_response = client.tokens.exchange(ExchangeTokenParams(
        code=code,
        agent_id="agt_abc123",
        code_verifier=pkce.code_verifier,
    ))

    # 3. Use the grant token with your agent
    grant_token = token_response.grant_token

    # 4. Verify the token is still valid
    verification = client.tokens.verify(grant_token)
    print(f"Valid: {verification.valid}")

    # 5. Revoke when no longer needed
    # Extract token ID from the JWT or use the known ID
    client.tokens.revoke("tok_abc123")