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

# Offline Verification

> Verify signatures and claims locally with a remote JWKS request per standalone call

## Overview

`VerifyGrantToken` verifies a grant token JWT locally using keys from the Grantex
JWKS endpoint. It avoids the online token-verification endpoint, including its
revocation lookup.

The standalone helper fetches keys from the configured JWKS endpoint on every
verification call, so that endpoint must be reachable. It does not call the
online token-verification/revocation API, but it is not network-free.

```go theme={null}
grant, err := grantex.VerifyGrantToken(ctx, tokenString, grantex.VerifyOptions{
    JwksURI: "https://api.grantex.dev/.well-known/jwks.json",
})
if err != nil {
    log.Fatal(err)
}
fmt.Printf("Principal: %s, Scopes: %v\n", grant.PrincipalID, grant.Scopes)
```

## Options

| Field | Type | Required | Description |
| - | - | - | - |
| `JwksURI` | `string` | Yes | URL to fetch the JWKS from |
| `RequiredScopes` | `[]string` | No | Scopes the token must contain |
| `Audience` | `string` | No | Expected `aud` claim |
| `Issuer` | `string` | No | Expected `iss` claim. The hosted JWKS alias expects `https://grantex.dev`; custom JWKS URLs derive an issuer when omitted. |
| `IssuerDID` | `string` | No | A `did:web` issuer used to derive the JWKS URL and expected issuer. An explicit `Issuer` takes precedence. |
| `ClockTolerance` | `time.Duration` | No | Tolerance for clock skew |
| `ProofJKT` | `string` | No | Thumbprint of the key the caller proved possession of; the token's `cnf.jkt` must match. The verifier does not check DPoP proofs. |
| `RequireProofOfPossession` | `bool` | No | Fail closed unless `ProofJKT` is set and matches `cnf.jkt`. |
| `StandardClaimsOnly` | `bool` | No | Ignore legacy claim aliases and require `typ: at+jwt`. `false` in 0.6: an alias is read when the standard claim is absent. |
| `OnLegacyClaim` | `func(alias, standard string)` | No | Called for each legacy alias a verification relied on; by default a deprecation message is logged once per alias. |
| `Algorithms` | `[]string` | No | Narrow the accepted algorithms to a subset of `GrantTokenAlgorithms()` (`RS256`, `ES256`, the default). Any other value returns a `TokenError`. |

Grant tokens are signed with RS256 or ES256. The key is the JWK Set entry named by
`kid`, and it must be an RSA public key for RS256 or an EC P-256 public key for
ES256, published without a different `alg` and with `use` absent or `sig`.
`alg: none` and HS256 are always rejected.

Hosted tokens use the canonical issuer `https://grantex.dev`, even though the
stable JWKS URL is served from `https://api.grantex.dev`. The SDK handles this
alias automatically.

## Response (`VerifiedGrant`)

| Field | Type | Description |
| - | - | - |
| `TokenID` | `string` | JWT `jti` claim |
| `GrantID` | `string` | Grant ID (`grnt` claim, falls back to `jti`) |
| `PrincipalID` | `string` | End-user (`sub` claim) |
| `AgentDID` | `string` | Agent DID (`agt` claim) |
| `DeveloperID` | `string` | Developer (`dev` claim) |
| `Scopes` | `[]string` | Granted scopes (`scp` claim) |
| `IssuedAt` | `int64` | Unix timestamp |
| `ExpiresAt` | `int64` | Unix timestamp |
| `ParentAgentDID` | `*string` | Parent agent for delegated grants |
| `ParentGrantID` | `*string` | Parent grant for delegated grants |
| `DelegationDepth` | `*int` | Delegation depth (0 = root) |
| `AuthorizationDetails` | `[]interface{}` | The `authorization_details` claim |
| `Act` | `*ActorClaim` | RFC 8693 actor chain (delegated grants) |
| `Cnf` | `map[string]interface{}` | Confirmation claim, e.g. `jkt` |
| `Audience` | `[]string` | The `aud` claim |
| `LegacyClaimsUsed` | `[]string` | Legacy aliases read because the standard claim was absent |

## Scope Checking

```go theme={null}
grant, err := grantex.VerifyGrantToken(ctx, token, grantex.VerifyOptions{
    JwksURI:        "https://api.grantex.dev/.well-known/jwks.json",
    RequiredScopes: []string{"read:email", "send:email"},
})
// Returns *TokenError if any required scope is missing
```

## Error Handling

Returns `*grantex.TokenError` for:

* Missing or invalid JWKS URI
* Expired tokens
* Invalid signatures
* Issuer or audience mismatches
* Missing or incorrectly typed required claims (`jti`, `sub`, `agt`, `dev`,
  `scp`, `iat`, `exp`)
* Missing required scopes
* Malformed JWTs

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