JWKS

Fetch public keys for local JWT verification
View as Markdown

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
3// Fetch JWKS once at startup
4const { result: jwksResponse } = await gwop.auth.getJwks();
5const jwks = jose.createLocalJWKSet({ keys: jwksResponse.keys });
6
7// Verify on each request
8async function verifyGwopJwt(token: string) {
9 const { payload } = await jose.jwtVerify(token, jwks, {
10 issuer: "https://identity.gwop.io",
11 algorithms: ["RS256"],
12 });
13
14 return {
15 sub: payload.sub, // "base:0x742d..." or "solana:7sSi..."
16 merchantId: payload.mid, // Your merchant ID
17 sessionId: payload.sid, // Session identifier
18 };
19}

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 fetchJwks();
3
4// Refresh on kid mismatch (key rotation)
5async function getJwks() {
6 const tokenHeader = jose.decodeProtectedHeader(token);
7 const hasKey = cachedJwks.keys.some((k) => k.kid === tokenHeader.kid);
8 if (!hasKey) {
9 cachedJwks = await fetchJwks(); // key rotated
10 }
11 return cachedJwks;
12}

Next step