Skip to main content

Overview

Grantex can issue W3C Verifiable Credentials (VCs) alongside standard RS256 JWTs. While grant tokens are optimized for real-time authorization (short-lived, revocation-checked, scope-enforced), Verifiable Credentials provide a portable, standards-compliant proof of authorization that any party can verify independently using the Grantex DID document.
Verifiable Credentials are opt-in. Existing token exchange flows continue to work unchanged. Pass credentialFormat: "vc-jwt" during token exchange to receive a VC alongside the standard grant token.

Why Verifiable Credentials?

Grant tokens work well within systems that integrate with Grantex. But in agentic commerce, agents interact with third-party services that may have no relationship with Grantex:
  • A payment processor needs proof that the agent is authorized to spend on the user’s behalf
  • A contract-signing service needs proof of human consent
  • An insurance API needs proof of delegated authority from a specific principal
Verifiable Credentials solve this by providing a self-contained, cryptographically signed document that any verifier can check using publicly available keys. No Grantex account, no API calls, no trust relationship required.

W3C Compliance

Grantex VCs conform to:
StandardVersionDescription
VC Data Modelv2.0Credential structure and semantics
VC-JWTJWT encoding of VCs (compact, URL-safe)
StatusList2021Bitstring-based revocation mechanism
DID Corev1.0Issuer identification via did:web

Issuing a Verifiable Credential

Request a VC during token exchange by setting the credentialFormat parameter:
import { Grantex } from '@grantex/sdk';

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

const result = await grantex.tokens.exchange({
  code,
  agentId: agent.id,
  credentialFormat: 'vc-jwt',
});

console.log(result.grantToken);           // standard RS256 JWT (always present)
console.log(result.verifiableCredential);  // W3C VC-JWT (present when requested)

Credential Types

AgentGrantCredential

Issued for direct grants (user authorizes an agent directly). The credential subject attests that a specific principal authorized a specific agent with specific scopes.
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://grantex.dev/ns/credentials/v1"
  ],
  "type": ["VerifiableCredential", "AgentGrantCredential"],
  "issuer": "did:web:grantex.dev",
  "issuanceDate": "2026-03-08T12:00:00Z",
  "expirationDate": "2026-03-09T12:00:00Z",
  "credentialSubject": {
    "id": "did:grantex:ag_01HXYZ123abc",
    "type": "Agent",
    "grantId": "grnt_01HXYZ...",
    "principalId": "user_abc123",
    "developerId": "org_yourcompany",
    "scopes": ["calendar:read", "payments:initiate:max_500"],
    "authorizedAt": "2026-03-08T12:00:00Z"
  },
  "credentialStatus": {
    "id": "https://api.grantex.dev/v1/credentials/status/1#42",
    "type": "StatusList2021Entry",
    "statusPurpose": "revocation",
    "statusListIndex": "42",
    "statusListCredential": "https://api.grantex.dev/v1/credentials/status/1"
  }
}

DelegatedGrantCredential

Issued for delegated grants (agent delegates to a sub-agent). Includes the full delegation chain for traceability.
{
  "@context": [
    "https://www.w3.org/ns/credentials/v2",
    "https://grantex.dev/ns/credentials/v1"
  ],
  "type": ["VerifiableCredential", "DelegatedGrantCredential"],
  "issuer": "did:web:grantex.dev",
  "credentialSubject": {
    "id": "did:grantex:ag_SUB_AGENT",
    "type": "DelegatedAgent",
    "grantId": "grnt_01CHILD...",
    "parentGrantId": "grnt_01ROOT...",
    "parentAgentDid": "did:grantex:ag_ROOT_AGENT",
    "delegationDepth": 1,
    "principalId": "user_abc123",
    "scopes": ["calendar:read"]
  }
}

FIDO Evidence

When the grant was approved via a FIDO2/WebAuthn assertion, the credential includes cryptographic proof of human presence:
{
  "credentialSubject": {
    "id": "did:grantex:ag_01HXYZ123abc",
    "type": "Agent",
    "grantId": "grnt_01HXYZ...",
    "principalId": "user_abc123",
    "scopes": ["payments:initiate:max_500"],
    "fidoEvidence": {
      "type": "WebAuthnAssertion",
      "authenticatorType": "platform",
      "userVerified": true,
      "assertedAt": "2026-03-08T12:00:00Z"
    }
  }
}
This FIDO evidence is compatible with the Mastercard Verifiable Intent specification for agentic commerce, providing the cryptographic human-presence proof that payment networks require.

Verifying a VC

Using the Grantex SDK

const verification = await grantex.credentials.verify(vcJwt);

if (verification.valid) {
  console.log('Issuer:', verification.issuer);
  console.log('Subject:', verification.credentialSubject);
  console.log('Scopes:', verification.credentialSubject.scopes);
  console.log('Status:', verification.status); // "active"
} else {
  console.log('Invalid:', verification.reason);
}

Independent Verification

Any party can verify a Grantex VC without the SDK by:
  1. Decoding the VC-JWT (standard JWT decode)
  2. Resolving the issuer DID (did:web:grantex.dev resolves to https://grantex.dev/.well-known/did.json)
  3. Extracting the public key from the DID document
  4. Verifying the JWT signature against the public key
  5. Checking the credentialStatus endpoint for revocation
# Resolve the DID document
curl https://api.grantex.dev/.well-known/did.json

# Check revocation status
curl https://api.grantex.dev/v1/credentials/status/1
No Grantex account or API key is required for verification. The DID document and status list endpoints are public.

Revocation via StatusList2021

Grantex uses the W3C StatusList2021 standard for credential revocation. Each VC references a position in a bitstring-based status list. When a grant is revoked, the corresponding bit is flipped.

How It Works

  1. Each credential is assigned a statusListIndex (a position in the bitstring)
  2. The status list credential is published at a public URL (/v1/credentials/status/:id)
  3. When a grant is revoked, Grantex sets the bit at that index
  4. Verifiers fetch the status list and check the bit to determine revocation

Checking Status

// Via SDK
const cred = await grantex.credentials.get('vc_01HXYZ...');
console.log(cred.status);  // "active" or "revoked"

// The SDK also checks status during verify()
const result = await grantex.credentials.verify(vcJwt);
console.log(result.status); // "active" or "revoked"

Revocation Timing

When you revoke a grant (via DELETE /v1/grants/:id, the permission dashboard, or cascade revocation), the following happens atomically:
  1. The grant record is marked as revoked
  2. The Redis revocation key is set (grant token rejected immediately)
  3. The StatusList2021 bit is flipped (VC shows as revoked)
  4. All delegated sub-grants are cascade-revoked (and their VCs)

Listing Credentials

// List all credentials
const { credentials } = await grantex.credentials.list();

// Filter by grant
const { credentials: grantCreds } = await grantex.credentials.list({
  grantId: 'grnt_01HXYZ...',
});

// Filter by principal
const { credentials: userCreds } = await grantex.credentials.list({
  principalId: 'user_abc123',
  status: 'active',
});

Mastercard Verifiable Intent

Grantex VCs are designed for compatibility with the Mastercard Verifiable Intent specification for agentic commerce. The key alignment points are:
RequirementGrantex Implementation
Cryptographic human presence proofFIDO2 WebAuthn assertion evidence in VC
Verifiable agent identityAgent DID (did:grantex:ag_...) as credential subject
Scoped authorizationscopes array in credential subject
Revocable credentialsStatusList2021 with real-time revocation
Standard-compliant formatW3C VC Data Model v2.0 + VC-JWT encoding
Independent verificationPublic DID document + public status list endpoints

API Reference

MethodEndpointDescription
GET/v1/credentials/:idRetrieve a specific Verifiable Credential
GET/v1/credentialsList credentials with optional filters
POST/v1/credentials/verifyVerify a VC-JWT (signature + status + expiry)
GET/v1/credentials/status/:idStatusList2021 credential (public, no auth)

Next Steps