> ## 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.

# Tokens

> Exchange authorization codes for grant tokens, verify tokens online, and revoke them.

## Overview

The `tokens` sub-client handles the token lifecycle: exchanging authorization codes for grant tokens, verifying tokens via the API, and revoking tokens.

```typescript theme={null}
// Exchange, verify, revoke
const token = await grantex.tokens.exchange({ code, agentId: agent.id });
const result = await grantex.tokens.verify(token.grantToken);
await grantex.tokens.revoke(result.grantId);
```

## tokens.exchange()

Exchange an authorization code for a signed grant token (RS256 JWT).

```typescript theme={null}
const token = await grantex.tokens.exchange({
  code: 'auth_code_from_callback',
  agentId: agent.id,
});

console.log(token.grantToken);   // RS256 JWT string
console.log(token.grantId);      // 'grnt_01HXYZ...'
console.log(token.scopes);       // ['calendar:read', 'payments:initiate:max_500']
console.log(token.expiresAt);    // '2026-03-02T12:00:00Z'
console.log(token.refreshToken); // 'rt_01HXYZ...'
```

### Parameters

<ParamField body="code" type="string" required>
  The authorization code received at your `redirectUri` after user consent.
</ParamField>

<ParamField body="agentId" type="string" required>
  The ID of the agent that initiated the authorization request.
</ParamField>

<ParamField body="codeVerifier" type="string">
  The PKCE code verifier. Required if `codeChallenge` was provided in the authorize step. See [PKCE](/sdks/typescript/pkce).
</ParamField>

### Response: `ExchangeTokenResponse`

<ResponseField name="grantToken" type="string">
  The signed RS256 JWT grant token. Pass this to your agent for use in API calls.
</ResponseField>

<ResponseField name="grantId" type="string">
  The unique grant record ID.
</ResponseField>

<ResponseField name="scopes" type="string[]">
  The scopes granted by the user.
</ResponseField>

<ResponseField name="expiresAt" type="string">
  ISO 8601 timestamp when the underlying grant expires.
</ResponseField>

<ResponseField name="refreshToken" type="string">
  A refresh token for rotating credentials while the grant remains active.
</ResponseField>

***

## tokens.refresh()

Refresh a grant token using a refresh token while the underlying grant remains active. Returns a new grant token and a new refresh token. The `grantId` and `expiresAt` stay the same.

Refresh tokens are single-use and rotated on every refresh per SPEC §7.4. Refresh does not extend the grant lifetime; after `expiresAt`, the caller must re-authorize. If the HTTP response is lost after commit, retry the same previous refresh token with the same idempotency key. During a five-minute window, Grantex returns the already-rotated refresh token instead of rotating again. After that window, or once the rotated child token has been used, the previous token is rejected.

```typescript theme={null}
const newToken = await grantex.tokens.refresh({
  refreshToken: token.refreshToken,
  agentId: agent.id,
  // Persist this value with the old token until the response is durable.
  idempotencyKey: crypto.randomUUID(),
});

console.log(newToken.grantToken);   // new RS256 JWT
console.log(newToken.refreshToken); // new refresh token; store this value
console.log(newToken.grantId);      // same grant ID
console.log(newToken.expiresAt);    // same grant expiration
```

### Parameters

<ParamField body="refreshToken" type="string" required>
  The refresh token from a previous `exchange()` or `refresh()` response.
</ParamField>

<ParamField body="agentId" type="string" required>
  The agent ID associated with the grant.
</ParamField>

<ParamField body="idempotencyKey" type="string">
  A 16-256 character key that identifies this logical refresh attempt. The SDK
  retains an automatically generated key for five minutes in the current
  process. Supply and persist this field when recovery must survive a caller
  restart or failover.
</ParamField>

### Response: `ExchangeTokenResponse`

Returns the same shape as `exchange()` — see above for field descriptions.

<Warning>
  Always store and use the newest `refreshToken` from the response. Retry a lost response with the same old token and the same `idempotencyKey`; a new SDK process cannot reconstruct an omitted key. The previous refresh token is only accepted for five minutes while the grant remains active, and will be rejected after the recovery window, after the rotated token is used, or after the grant expires.
</Warning>

***

## tokens.verify()

Verify a grant token online via the Grantex API. This is useful when you want server-side validation without managing JWKS yourself.

```typescript theme={null}
const result = await grantex.tokens.verify(token.grantToken);

if (result.valid) {
  console.log(result.grantId);   // 'grnt_01HXYZ...'
  console.log(result.scopes);    // ['calendar:read']
  console.log(result.principal);  // 'user_abc123'
  console.log(result.agent);      // 'did:grantex:ag_01HXYZ...'
  console.log(result.expiresAt);  // '2026-03-02T12:00:00Z'
}
```

### Parameters

<ParamField body="token" type="string" required>
  The grant token JWT string to verify.
</ParamField>

### Response: `VerifyTokenResponse`

<ResponseField name="valid" type="boolean">
  Whether the token is valid and not expired/revoked.
</ResponseField>

<ResponseField name="grantId" type="string">
  The grant record ID (present when `valid` is `true`).
</ResponseField>

<ResponseField name="scopes" type="string[]">
  The granted scopes.
</ResponseField>

<ResponseField name="principal" type="string">
  The user (principal) who authorized the grant.
</ResponseField>

<ResponseField name="agent" type="string">
  The agent DID that holds the grant.
</ResponseField>

<ResponseField name="expiresAt" type="string">
  ISO 8601 timestamp when the token expires.
</ResponseField>

<Note>
  For local signature-and-claim verification without the online revocation
  endpoint, use [verifyGrantToken()](/sdks/typescript/offline-verification).
  The standalone helper still resolves the remote JWKS on each call.
</Note>

***

## tokens.revoke()

Revoke a token by its token ID (the `jti` claim). The API responds with `204 No Content`.

```typescript theme={null}
await grantex.tokens.revoke('tok_01HXYZ...');
// Returns void — the token is now invalid
```

### Parameters

<ParamField body="tokenId" type="string" required>
  The token ID (`jti` claim from the JWT) to revoke.
</ParamField>

### Response

Returns `void`. The token is immediately invalidated.

## Full example

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

const grantex = new Grantex({ apiKey: process.env.GRANTEX_API_KEY });

// Exchange the code from the OAuth callback
const token = await grantex.tokens.exchange({
  code: req.query.code,
  agentId: 'ag_01HXYZ...',
});

// Hand the grant token to your agent
const grantToken = token.grantToken;

// Later: verify the token is still valid
const check = await grantex.tokens.verify(grantToken);
if (!check.valid) {
  throw new Error('Token has been revoked or expired');
}

// When the task is complete, revoke the token
await grantex.tokens.revoke(check.grantId);
```

## Ownership

Grantex is owned by Orchestrum Technologies LLP. Inventor and owner: Sanjeev Kumar. Ownership contact: [sanjeev@orchestrum.in](mailto:sanjeev@orchestrum.in) or [mishra.sanjeev@gmail.com](mailto:mishra.sanjeev@gmail.com).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.