Skip to main content
JWT public keys let builders expose Struct API access to their end users without sharing their real sk_* API key. End users authenticate with JWTs from the builder’s own auth provider (Privy, Turnkey, Google, Auth0, etc.). Struct only verifies the JWT, never creates or manages it. Each JWT public key (pk_jwt_*) is safe to hardcode in frontend bundles. It tells Struct:
  • Which JWKS URL or inline public key to use to verify the end user’s JWT
  • Which builder organisation to bill the request to
  • What per-session rate limit to enforce
End users never see or interact with the pk_jwt_* key. Their only credential is the JWT issued by their own auth provider.

How It Works

Builder dashboard          Builder's frontend app          Struct API
─────────────────────────────────────────────────────────────────────
Create pk_jwt_xxx  ──►  Hardcode pk_jwt_xxx
Configure JWKS URL
                           User logs in via Privy ──►
                           Privy issues JWT        ◄──

                           API request with:       ──►  Verify JWT against JWKS
                           X-Api-Key: pk_jwt_xxx        Bill credits to builder's org
                           Authorization: Bearer JWT     Apply per-session rate limit

Setting Up a JWT Public Key

JWT public keys are configured from within an API key’s settings page.
1

Navigate to your API key

Go to API Keys in your organisation’s dashboard and select the API key you want to associate with JWT auth.
2

Open the Settings tab

On the API key detail page, click the Settings tab.
3

Configure JWT public key

Fill in the JWT public key configuration:
  • A name for the key (e.g. My App (Privy))
  • A JWKS URL or an inline public key for JWT verification
  • Optionally, expected audience and issuer claims
  • Optionally, a per-session rate limit (requests per minute per end user)
4

Copy your key

Your pk_jwt_* key is shown once at creation. Embed it in your frontend application.

Managing Keys

From the API key’s Settings tab you can:
  • Update a key’s name, JWKS URL, public key, audience, issuer, rate limit, or enabled status
  • Disable a key to temporarily block all requests using it (takes effect within 60 seconds)
  • Delete a key to permanently invalidate it (takes effect immediately)
Updates take effect within 60 seconds as the cached record expires.

Configuration Fields

FieldTypeRequiredDescription
namestringYesHuman-readable label
jwks_urlstringEither/orJWKS endpoint URL. Used for RS256, RS384, RS512, ES256, ES384 (Privy, Google, Turnkey, Auth0, etc.)
public_keystringEither/orInline public key (PEM or JWK JSON). Supports RSA, EC, and EdDSA algorithms. Alternative to jwks_url; provide one, not both
audiencestringNoIf set, the aud claim in the user JWT must match this value
issuerstringNoIf set, the iss claim in the user JWT must match this value
per_session_rpmintegerNoRate limit per end user session (per sub claim), in requests per minute. null = no per-session limit
Exactly one of jwks_url or public_key must be provided: not both, not neither.

Billing

Each pk_jwt_* key is associated with a standard API key at creation time. All credits and rate limits are billed through that parent API key, so the parent key’s rate limit and credit cap apply. End users do not need a Struct account or credits. The per_session_rpm is an additional per-user cap applied on top of the parent key’s limits, keyed on the sub claim from the user JWT.

Security

  • A leaked pk_jwt_* key cannot be exploited alone; it is useless without a valid user JWT from the configured provider
  • Struct only stores public verification material (JWKS URLs or public keys), never private keys or signing secrets
  • Only asymmetric JWT algorithms are supported (RS256, RS384, RS512, ES256, ES384, EdDSA); symmetric secrets (HS256) are not accepted
  • Disabling or deleting a key takes effect within 60 seconds (cache TTL)
  • JWKS keys are cached for 5 minutes. If a provider rotates signing keys, the first request with a new kid will trigger an immediate re-fetch
Last modified on April 11, 2026