Skip to main content
After your iOS app calls grantiva.validateAttestation(), it receives a signed JWT. Your backend should verify this token on every authenticated request to confirm the device passed attestation and to read device intelligence claims.

How it works

  1. Your app sends the JWT as a Bearer token in the Authorization header
  2. Your backend fetches Grantiva’s public key from /.well-known/jwks.json
  3. You verify the JWT signature and expiry locally (no network call per request)
  4. You extract device claims: risk_score, risk_category, jailbreak status, and any custom claims

JWT Claims Reference

Node.js

Uses jose (ESM/CJS, works in Node.js and edge runtimes).

Python

Uses PyJWT with cryptography for RS256.

Swift (Vapor)

Uses vapor/jwt which has native JWKS support via JWKSet.

Go

Uses golang-jwt/jwt with JWKS fetching via MicahParks/keyfunc.

Reading custom claims

Custom claims you configure in the Grantiva dashboard appear in the custom_claims object:

Reading the subscription claim

If your organization uses subscription entitlement ingestion (Enterprise), the managed subscription object appears under custom_claims:
Gate on the single is_active boolean — it already accounts for billing-retry grace periods. expires_at is epoch seconds. The claim is absent entirely when the device’s sharing unit has no entitlement.

Risk-based access control

Caching the public key

All three examples cache the JWKS response and refresh it automatically when key rotation occurs. Do not fetch the public key on every request — it adds latency and will trigger rate limiting.