Skip to main content
JWT public key auth lets your app call the Struct API directly from the browser or a mobile client, authenticated as the individual end user, without shipping a secret key and without building a backend of your own to sit in front of Struct.

The problem it solves

Your sk_* secret key grants full access to your whole organisation, so it can never ship in a frontend bundle. The usual way around this is to build and operate a proxy backend: it holds the secret key, logs each of your users in, forwards their calls to Struct, and enforces a per-user rate limit so one user can’t burn your whole quota. That proxy is real infrastructure to write, host, and pay for, and it adds a network hop to every request. JWT public key auth removes that layer. You create a publishable pk_jwt_* key, point it at your auth provider’s public keys, and your frontend talks to Struct directly. Struct verifies each end user’s JWT, bills your organisation, and applies the per-user rate limit for you.

What you get

  • No secret key in the browser. The pk_jwt_* key is safe to hardcode in a frontend bundle. On its own it does nothing; every request also needs a valid JWT signed by your configured auth provider.
  • No proxy to build or run. Skip the auth-and-forward backend and call Struct directly from the client. Less infrastructure to maintain and host, lower cost.
  • Per-user rate limits. Set a per_session_rpm cap that Struct enforces per end user (keyed on the JWT sub claim), on top of your parent key’s limits, so a single user can’t exhaust your quota.
  • Any auth provider. Works with Privy, Auth0, Clerk, Turnkey, Google, or your own issuer, as long as it signs JWTs with an asymmetric key.
See JWT Public Keys for how to create and manage keys.

Wire Format

Every request requires two credentials: your pk_jwt_* key (hardcoded in your app) and the user’s JWT (obtained at login).

REST

curl https://api.struct.to/v1/markets \
  -H "X-Api-Key: pk_jwt_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4" \
  -H "Authorization: Bearer <user_jwt>"

WebSocket

wss://api.struct.to/ws?api-key=pk_jwt_a1b2c3d4e5f6a1b2c3d4&token=<user_jwt>
Both parameters are required on every request.

Auth Flow

1

Request received

Request arrives with X-Api-Key: pk_jwt_xxx and Authorization: Bearer <user_jwt>.
2

Key lookup

The pk_jwt_ prefix triggers the JWT public key auth flow. The key record is loaded from the database (cached 60 seconds). If the key is disabled or not found, the request returns 401.
3

JWT verification

JWKS URL keys: The JWKS is fetched from the configured URL (cached 5 minutes). If the JWT’s kid is not found in the cached set, the JWKS is re-fetched once to handle key rotation.Inline public key: The PEM or JWK JSON key is used directly to verify the JWT signature.Supported algorithms: RS256, RS384, RS512, ES256, ES384, EdDSA.
4

Claims validation

aud and iss claims are validated if configured on the key. If the JWT is expired or the signature is invalid, the request returns 401.
5

Rate limiting and billing

The sub claim is extracted as the session identifier. The parent API key’s rate limit and credit cap apply. If per_session_rpm is set, an additional per-user rate limit is checked (keyed on pk_jwt_xxx:sub).
6

Request proceeds

Credits are billed through the parent API key.

Supported Algorithms

Only asymmetric JWT signing algorithms are supported:
FamilyAlgorithms
RSARS256, RS384, RS512
Elliptic CurveES256, ES384
Edwards CurveEdDSA
Symmetric algorithms (HS256, HS384, HS512) are not supported. JWTs signed with shared secrets will be rejected. Your auth provider must use asymmetric key pairs where the public key is exposed via a JWKS endpoint or provided inline.

Key Verification Methods

JWKS URL

Provide a JWKS endpoint URL and Struct will fetch the public keys automatically. This is the standard approach for most auth providers. The JWKS is cached for 5 minutes, and if a JWT arrives with an unknown kid, the JWKS is re-fetched once to handle key rotation.

Inline Public Key

Alternatively, provide the public key directly in PEM format (-----BEGIN PUBLIC KEY-----) or as JWK JSON ({"kty":"RSA", ...}). The key is used directly to verify JWT signatures without any external fetch.
Last modified on May 31, 2026