Skip to main content
An Ephemeral Key is a short-lived credential that your backend mints from a normal GoldRush API key (cqt_… / ckey_…) and hands to an untrusted client - a browser, a mobile app, or a WebSocket URL. It is prefixed gr_ek_…, expires in 30 minutes by default, is scoped to (and never wider than) the API key that minted it, and rolls all usage and billing up into that parent API key. Ephemeral Keys exist so you can put GoldRush data directly in front of your end users without ever exposing your API key to them. A leaked Ephemeral Key is worthless within one refresh window.
Two credentials, two jobs. Your API key is a long-lived server-side secret - it mints Ephemeral Keys and is never shipped to a client. An Ephemeral Key is the disposable, client-side token your app actually connects with. This mirrors the β€œsecret key mints an ephemeral key” pattern you may know from Stripe.

When to use Ephemeral Keys

Reach for Ephemeral Keys when the credential will live somewhere you don’t control:
  • Client-side apps - a browser SPA or mobile app that calls GoldRush directly, where any embedded API key is trivially extractable from network traffic or bundled JS.
  • WebSockets - the Hyperliquid WebSocket (wss://hypercore.goldrushdata.com/ws) takes its credential as a key query parameter at connect time. That URL is visible to the client, so it must not carry your API key.
  • High-fan-out embeds - thousands of end users each holding a credential. With Ephemeral Keys, each client gets its own short-lived token that self-expires within one refresh window.
If your GoldRush calls only ever happen server-side, you don’t need Ephemeral Keys - just use your API key directly, as described in Authentication.
Why not web-locked (referrer/origin) keys? Origin allowlisting can gate browser REST traffic, but it does not cover WebSockets (there is no reliable Origin enforcement on a raw WS URL), and an origin restriction still ships your real API key to the client, where it can be lifted and replayed from any environment that spoofs the header. Ephemeral Keys solve both: the API key never leaves your backend, and the client-side token is worthless after 30 minutes.

The security model

The design rests on three properties:
  1. Your API key never reaches the client. Only your backend holds it. It is used once per refresh, server-to-server, to mint an Ephemeral Key.
  2. Ephemeral Keys inherit the parent’s access. An Ephemeral Key carries exactly the parent API key’s bindings - never wider, and in this release never narrower. The edge enforces the parent’s access on every request, and all usage attributes to the parent, so quotas and billing are unchanged. (Per-child scope narrowing is planned but not part of this release.)
  3. Ephemeral Keys are safe if stolen. They are signed RS256 JWTs with a 30-minute expiry. An attacker who captures one from a browser or a WS URL can use it only until it expires - a small, self-healing blast radius. No secret is recoverable from the token.
Because the token is a self-contained signed JWT, the GoldRush edge verifies it offline against a published public key (JWKS) - no database or cache round-trip per request. That is what makes Ephemeral Keys viable at Hyperliquid WebSocket message volume.

The 30-minute TTL

The default TTL is 30 minutes (1800 seconds); the maximum you can request is 60 minutes (3600 seconds). Short TTLs are the primary revocation mechanism: instead of maintaining a per-token online blocklist, we let tokens expire quickly and refresh them on a timer.
  • Too short and clients refresh constantly, adding mint load.
  • Too long and a stolen token stays useful.
  • 30 minutes keeps the leaked-token window small while a client only mints ~48 times a day.

Lifecycle: mint β†’ embed β†’ refresh

  1. Mint (server-side). Your backend calls POST /platform/ephemeral_keys/ with your API key and gets back { ephemeral_key, expires_at }.
  2. Embed (client-side). Your backend passes the gr_ek_… token to the client, which uses it exactly where it would have used an API key - as a key query parameter, a bearer token, or Basic Auth.
  3. Refresh (client-side). Shortly before expires_at, the client asks your backend for a fresh Ephemeral Key and swaps it in. For long-lived WebSocket connections, reconnect (or re-authenticate) with the new token before the old one expires.
The TypeScript SDK’s EphemeralKeyProvider handles this refresh loop for you.

Quick start (curl)

Two calls: your backend mints an Ephemeral Key with your API key, then the client uses that gr_ek_… token exactly where it would have used an API key. 1. Mint (server-side, with your API key).
2. Use (client-side, with the gr_ek_… token). An Ephemeral Key authenticates the data APIs the same way an API key does - as a Bearer token, Basic Auth username, or key query parameter. Against the Foundational API:
For the Hyperliquid WebSocket, pass it as the key query parameter at connect time:
That is the whole flow. In production the client never sees your API key - it only ever receives the short-lived gr_ek_… token from your mint proxy (Recipe A) and refreshes it before expires_at.

API reference

All Ephemeral Key management endpoints live under the Platform control plane at https://api.covalenthq.com and are authenticated with your API key, not with an Ephemeral Key. Each has a dedicated reference page under API Reference β€Ί Ephemeral Keys; the summary below is the narrative version.

Mint an Ephemeral Key

Authenticate with a parent API key (cqt_… / ckey_…) as a bearer token. The request body is optional JSON. An Ephemeral Key cannot mint another Ephemeral Key - the request is rejected with 403 if authenticated with a gr_ek_… token (and likewise for a gr_sk_… service key).
integer
Requested lifetime in seconds. Optional; defaults to 1800 (30 min). Clamped to [1, 3600] - the server maximum is 3600 (60 min), so larger requests are silently reduced to the cap. A non-integer value returns 400.
In this release the mint accepts no other fields - an Ephemeral Key always inherits the parent’s full access (see the security model). Any additional body fields are ignored. Response 200 OK
string
The signed RS256 JWT, prefixed gr_ek_. This is what you hand to the client.
string
ISO-8601 UTC timestamp at which the token’s exp claim falls due. Refresh before this time.
This endpoint is rate-limited per parent API key (default 60 mints/minute). Mint one Ephemeral Key per client session and refresh on a timer - do not mint a fresh token on every request. If you hit the limit you’ll receive 429 Too Many Requests.

Ephemeral JWKS endpoint

Public - no authentication. Returns the JSON Web Key Set of public keys used to sign Ephemeral Keys, so that any verifier (including the GoldRush edge) can validate a token’s signature offline. Keys are identified by kid; up to two are active at once to allow zero-downtime rotation. Cache the response and refetch when you encounter an unknown kid.
This is a dedicated key set for Ephemeral Keys. It is unrelated to any other GoldRush signing key.

Token claims

An Ephemeral Key is a standard RS256 JWT. Decode (without needing the private key) to inspect its claims - useful for debugging expiry: The signing key id (kid) travels in the JWT header (not the claims), so a verifier can select the right JWKS key before checking the signature. There is no scopes claim in this release - a token inherits the parent’s full access. The token deliberately carries no secret - everything in it is safe for the client to see. It is trusted only because of the signature.

Error codes

Minting (the platform/ephemeral_keys/ endpoint). Errors are returned in the standard GoldRush envelope ({ "error": true, "error_message": …, "error_code": … }): Using an Ephemeral Key on the data APIs (Foundational, JSON-RPC, Hyperliquid, x402): The distinct expired vs invalid 401 responses let SDKs refresh automatically on expiry without retry-looping on a genuinely bad token. The EphemeralKeyProvider refreshes proactively, before exp, so a well-behaved client rarely sees an expired 401 at all.

Recipes

Recipe A - Node/Express mint proxy

Your backend exposes one small endpoint that mints an Ephemeral Key from your (secret) API key. This is the only place your API key is ever used. The browser does call this proxy - that is the intended design, and it is safe for two independent reasons:
  1. The proxy is not open. It sits behind your app’s existing user session (cookie, session token, or whatever you already use to know who is logged in). A random visitor with no session gets 401 and never mints anything. Only your authenticated users can obtain a token, so nobody can run up your bill by hammering the endpoint. That is the job of requireYourUserAuth below - your own auth middleware, not something GoldRush provides.
  2. The token it returns is safe to hold in the browser. An Ephemeral Key is meant to live in an untrusted client - it is a 30-minute, parent-scoped, secret-free JWT (see the security model). What must never reach the browser is your API key; the Ephemeral Key reaching the browser is the whole point.
Why isn’t the mint endpoint itself the weak link? A common worry: β€œif the browser can call /api/goldrush-ephemeral-key, can’t anyone call it and steal a token?” No - because the endpoint is gated by your login (property 1), an unauthenticated caller gets nothing, and even a token handed to a legitimate-but-untrusted client is disposable by design (property 2). The endpoint returns a short-lived child credential to people who are already your logged-in users; it never returns your API key.
Guard this route with your own authentication (requireYourUserAuth above). An open mint proxy lets anyone mint tokens against your API key and your bill.

Recipe B - Browser WebSocket with auto-refresh

Connect a browser to the Hyperliquid WebSocket using an Ephemeral Key, and refresh it before it expires. The TypeScript SDK’s EphemeralKeyProvider calls your mint proxy (Recipe A) and keeps a valid token ready:
If you prefer not to use the SDK, the manual pattern is the same: fetch a token from your proxy, open wss://hypercore.goldrushdata.com/ws?key=<gr_ek_…>, and set a timer for expires_at βˆ’ 5 min that fetches a fresh token and reconnects. See the WebSocket API overview for subscription payloads.
A WebSocket authenticated with an Ephemeral Key cannot outlive the token’s expiry beyond the max TTL - the edge drops or requires re-auth at exp. Always reconnect with a fresh token before then; don’t rely on an open socket staying open indefinitely.

FAQ

  • Do Ephemeral Keys change my billing? No. All usage attributes to the parent API key’s parent_key_id, exactly as if the parent had made the calls. There is no separate meter or plan for Ephemeral Keys.
  • Can I mint an Ephemeral Key from another Ephemeral Key? No. Only a parent API key (cqt_… / ckey_…) can mint. Minting with a gr_ek_… token is rejected - this prevents a leaked client token from bootstrapping fresh long-lived access.
  • Can I restrict what an Ephemeral Key can do (per-child scopes)? Not in this release. A token inherits exactly the parent API key’s access - it can’t be widened, and per-child narrowing (fewer chains/endpoints) is planned but not yet available. The only mint-time parameter today is ttl_seconds.
  • If the browser calls my mint proxy, can’t anyone call it and steal a token? No. Your mint proxy sits behind your app’s own login (the requireYourUserAuth step in Recipe A) - an unauthenticated request gets 401 and mints nothing, so nobody can run up your bill. And a token handed to one of your legitimate users is safe to hold client-side anyway: it is a 30-minute, parent-scoped, secret-free JWT. The thing that must stay server-side is your API key, never the Ephemeral Key.
  • Is this the same as a ServiceKey? No - different job. ServiceKeys authenticate account-level Platform operations (like reading your usage) and are rejected on the data APIs. Ephemeral Keys authenticate data requests on behalf of a parent API key and are for client-side embedding. See also Authentication for server-side API-key usage.