For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
Apply for AccessDashboard
Guides
Guides
  • Get Started
    • Introduction
    • Quickstart
  • Agent Identity
    • Overview
    • Create Auth Intent
    • Exchange for JWT
    • Sessions
    • JWKS
  • Agent Checkout
    • Overview
    • Create an Invoice
    • List Invoices
    • Get Invoice
    • Cancel Invoice
  • Integration Patterns
    • Overview
    • Shared SDK Client
    • Wallet Auth
    • JWT Verification
    • Subscription Checkout
    • Webhook Verification
  • Concepts
    • Two Invoice IDs
    • Wallet Identity
    • Session vs Token
    • Webhook-Driven State
  • Webhooks
    • Overview
    • Verify Signatures
  • Reliability
    • Errors
    • SDK Reference
Apply for AccessDashboard
On this page
  • Fetch JWKS
  • Response
  • Verify JWTs with jose
  • Key details
  • Caching strategy
  • Next step
Agent Identity

JWKS

Fetch public keys for local JWT verification
||View as Markdown|
Was this page helpful?
Edit this page
Previous

Sessions

Next

Invoices

Built with

Fetch JWKS

Fetch Gwop’s public keys to verify JWTs locally without calling the API on every request:

1import { Gwop } from "@gwop/sdk";
2
3const gwop = new Gwop({
4 merchantApiKey: process.env.GWOP_MERCHANT_API_KEY,
5});
6
7const { result: jwks } = await gwop.auth.getJwks();
8console.log(jwks.keys[0].kid); // "gwop-auth-v1"

Response

1{
2 "keys": [
3 {
4 "kty": "RSA",
5 "alg": "RS256",
6 "use": "sig",
7 "kid": "gwop-auth-v1",
8 "n": "iHbqj9EbDXmZThb_ho13opho...",
9 "e": "AQAB"
10 }
11 ]
12}

This endpoint requires no authentication and is not rate-limited. Cache the keys on startup and refresh periodically (e.g., every hour or on kid mismatch).

Verify JWTs with jose

1import * as jose from "jose";
2
3async function fetchGwopJwks() {
4 const { result } = await gwop.auth.getJwks();
5 return result;
6}
7
8// Fetch JWKS once at startup
9let cachedJwks = await fetchGwopJwks();
10let jwks = jose.createLocalJWKSet({ keys: cachedJwks.keys });
11
12// Verify on each request
13async function verifyGwopJwt(token: string) {
14 try {
15 const { payload } = await jose.jwtVerify(token, jwks, {
16 issuer: "https://identity.gwop.io",
17 algorithms: ["RS256"],
18 });
19
20 return {
21 sub: payload.sub, // "base:0x742d..." or "solana:7sSi..."
22 merchantId: payload.mid, // Your merchant ID
23 sessionId: payload.sid, // Session identifier
24 };
25 } catch (error) {
26 if (error instanceof jose.errors.JWKSNoMatchingKey) {
27 cachedJwks = await fetchGwopJwks();
28 jwks = jose.createLocalJWKSet({ keys: cachedJwks.keys });
29
30 const { payload } = await jose.jwtVerify(token, jwks, {
31 issuer: "https://identity.gwop.io",
32 algorithms: ["RS256"],
33 });
34
35 return {
36 sub: payload.sub,
37 merchantId: payload.mid,
38 sessionId: payload.sid,
39 };
40 }
41
42 throw error;
43 }
44}

Key details

FieldValueDescription
ktyRSARSA key type
algRS256RSA with SHA-256
usesigSigning key
kidgwop-auth-v1Key identifier — match against JWT header kid
eAQABPublic exponent (65537)

Caching strategy

1// Cache JWKS on startup
2let cachedJwks = await fetchGwopJwks();
3let verifier = jose.createLocalJWKSet({ keys: cachedJwks.keys });
4
5// Refresh on kid mismatch (key rotation)
6async function getVerifier(token: string) {
7 const tokenHeader = jose.decodeProtectedHeader(token);
8 const hasKey = cachedJwks.keys.some((k) => k.kid === tokenHeader.kid);
9
10 if (!hasKey) {
11 cachedJwks = await fetchGwopJwks();
12 verifier = jose.createLocalJWKSet({ keys: cachedJwks.keys });
13 }
14
15 return verifier;
16}

Next step

Sessions

Check session status and revoke sessions (logout)

Auth Overview

Full auth flow, wallet identity, and what auth unlocks