From ee6df7773229a61f8081af3a1abf4023ea9dc984 Mon Sep 17 00:00:00 2001 From: Hydra SWE Agent Date: Sun, 26 Jul 2026 16:49:41 +0000 Subject: [PATCH 1/5] feat(pro): add frontend-jwt-auth Next.js example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New top-level `pro/frontend-jwt-auth/` example demonstrating the JWT auth flow required for the Pyth Pro History API. A Next.js App Router route (`POST /api/pyth-token`) mints short-lived JWTs on the server using `PRO_API_KEY`, the browser caches them 30s before `expires_at`, and a lightweight-charts UI renders 24h of 1m OHLC for BTC/USD, ETH/USD, and SOL/USD from the Pyth Pro History API, polling every 30s. Also adds `.github/workflows/ci-pro-frontend-jwt-auth.yml` — a paths-scoped CI job that runs prettier, tsc --noEmit, and next build (no secrets required). --- .../workflows/ci-pro-frontend-jwt-auth.yml | 27 ++ pro/frontend-jwt-auth/.env.example | 7 + pro/frontend-jwt-auth/.gitignore | 8 + pro/frontend-jwt-auth/README.md | 55 +++ pro/frontend-jwt-auth/next.config.mjs | 6 + pro/frontend-jwt-auth/package.json | 28 ++ pro/frontend-jwt-auth/pnpm-lock.yaml | 372 ++++++++++++++++++ .../src/app/api/pyth-token/route.ts | 77 ++++ pro/frontend-jwt-auth/src/app/globals.css | 89 +++++ pro/frontend-jwt-auth/src/app/layout.tsx | 18 + pro/frontend-jwt-auth/src/app/page.tsx | 45 +++ .../src/components/PythChart.tsx | 167 ++++++++ pro/frontend-jwt-auth/src/lib/pythClient.ts | 108 +++++ pro/frontend-jwt-auth/src/lib/pythToken.ts | 36 ++ pro/frontend-jwt-auth/tsconfig.json | 23 ++ 15 files changed, 1066 insertions(+) create mode 100644 .github/workflows/ci-pro-frontend-jwt-auth.yml create mode 100644 pro/frontend-jwt-auth/.env.example create mode 100644 pro/frontend-jwt-auth/.gitignore create mode 100644 pro/frontend-jwt-auth/README.md create mode 100644 pro/frontend-jwt-auth/next.config.mjs create mode 100644 pro/frontend-jwt-auth/package.json create mode 100644 pro/frontend-jwt-auth/pnpm-lock.yaml create mode 100644 pro/frontend-jwt-auth/src/app/api/pyth-token/route.ts create mode 100644 pro/frontend-jwt-auth/src/app/globals.css create mode 100644 pro/frontend-jwt-auth/src/app/layout.tsx create mode 100644 pro/frontend-jwt-auth/src/app/page.tsx create mode 100644 pro/frontend-jwt-auth/src/components/PythChart.tsx create mode 100644 pro/frontend-jwt-auth/src/lib/pythClient.ts create mode 100644 pro/frontend-jwt-auth/src/lib/pythToken.ts create mode 100644 pro/frontend-jwt-auth/tsconfig.json diff --git a/.github/workflows/ci-pro-frontend-jwt-auth.yml b/.github/workflows/ci-pro-frontend-jwt-auth.yml new file mode 100644 index 00000000..2d821587 --- /dev/null +++ b/.github/workflows/ci-pro-frontend-jwt-auth.yml @@ -0,0 +1,27 @@ +name: "Pro Frontend JWT Auth Example" +on: + push: + branches: + - main + pull_request: + paths: + - "pro/frontend-jwt-auth/**" + - ".github/workflows/ci-pro-frontend-jwt-auth.yml" + +jobs: + build: + name: Build + runs-on: ubuntu-22.04 + defaults: + run: + working-directory: pro/frontend-jwt-auth + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + - run: npm install --global pnpm@9.2.0 + - run: pnpm install --frozen-lockfile + - run: pnpm run test:format + - run: pnpm run test:types + - run: pnpm run build diff --git a/pro/frontend-jwt-auth/.env.example b/pro/frontend-jwt-auth/.env.example new file mode 100644 index 00000000..017dc70c --- /dev/null +++ b/pro/frontend-jwt-auth/.env.example @@ -0,0 +1,7 @@ +# Pyth Pro API key. Contact Pyth for a Pro key +# (see https://docs.pyth.network/price-feeds/pro). +PRO_API_KEY=your_pyth_pro_api_key_here + +# Optional. Override the default Pyth Pro API base URL +# if you are pointed at a non-prod environment. +# PYTH_API_BASE_URL=https://pyth.dourolabs.app diff --git a/pro/frontend-jwt-auth/.gitignore b/pro/frontend-jwt-auth/.gitignore new file mode 100644 index 00000000..19ef5c08 --- /dev/null +++ b/pro/frontend-jwt-auth/.gitignore @@ -0,0 +1,8 @@ +node_modules +.next +out +.env +.env.local +.env.*.local +next-env.d.ts +*.tsbuildinfo diff --git a/pro/frontend-jwt-auth/README.md b/pro/frontend-jwt-auth/README.md new file mode 100644 index 00000000..1d364dc5 --- /dev/null +++ b/pro/frontend-jwt-auth/README.md @@ -0,0 +1,55 @@ +# Pyth Pro Frontend JWT Auth Example + +A minimal [Next.js](https://nextjs.org/) app that renders live BTC/USD, ETH/USD, and SOL/USD candlestick charts backed by the [Pyth Pro History API](https://docs.pyth.network/price-feeds/pro/api/history), authenticating every request via the [JWT flow](https://docs.pyth.network/price-feeds/pro/frontend-auth) required since 2026-07-24. + +## Prerequisites + +- Node.js 18 or newer +- [pnpm](https://pnpm.io/) 9+ +- A Pyth Pro API key ([contact Pyth](https://docs.pyth.network/price-feeds/pro)) + +## Quick start + +```bash +cd pro/frontend-jwt-auth +cp .env.example .env.local # then edit .env.local and set PRO_API_KEY +pnpm install +pnpm dev +``` + +Open — you should see three charts populated with the last 24 hours of 1-minute candles. + +## How it works + +- `src/app/api/pyth-token/route.ts` is a server-only route that forwards `POST /api/pyth-token` to `POST https://pyth.dourolabs.app/auth/token` with `Authorization: Bearer $PRO_API_KEY` and returns the minted `{ access_token, expires_at, token_type }`. +- `src/lib/pythToken.ts` caches the token in the browser and refreshes it 30 seconds before `expires_at`, matching the caching pattern from the [frontend-auth docs](https://docs.pyth.network/price-feeds/pro/frontend-auth). +- `src/lib/pythClient.ts` calls `GET https://pyth.dourolabs.app/v1/fixed_rate@200ms/history?...` with the cached JWT, transparently retrying once on `401` after invalidating the cache. +- `src/components/PythChart.tsx` renders the returned OHLC arrays with [`lightweight-charts`](https://tradingview.github.io/lightweight-charts/) and polls every 30 seconds to append new candles. + +## Security notes + +- `PRO_API_KEY` is read from `process.env` in the server route only. It is never referenced from a `NEXT_PUBLIC_*` variable and never imported from a client-side file, so it is not included in the browser bundle. +- The mint route in this example has no request auth or rate limit — anyone who can reach `/api/pyth-token` can mint a JWT with your `PRO_API_KEY`. **Before running this in production, add authentication (e.g. a session cookie check) and a rate limit to `/api/pyth-token`.** +- The mint route mirrors the upstream error body verbatim for easier debugging. In production, log the upstream response server-side and return a generic error instead. + +## Configuration + +| Variable | Where | Default | Purpose | +| ------------------------------- | ----------- | ---------------------------- | ---------------------------------------------------------- | +| `PRO_API_KEY` | Server only | — (required) | Long-lived Pyth Pro API key used to mint short-lived JWTs. | +| `PYTH_API_BASE_URL` | Server | `https://pyth.dourolabs.app` | Override for non-prod environments. | +| `NEXT_PUBLIC_PYTH_API_BASE_URL` | Browser | `https://pyth.dourolabs.app` | Override the History API base used from the browser. | + +## Scripts + +- `pnpm dev` — Next.js dev server on `http://localhost:3000` +- `pnpm build` — Production build (does not require `PRO_API_KEY`) +- `pnpm start` — Serve the production build +- `pnpm test:format` — Prettier check +- `pnpm test:types` — `tsc --noEmit` + +## References + +- [Pyth Pro frontend auth](https://docs.pyth.network/price-feeds/pro/frontend-auth) (primary reference for the JWT flow) +- [Pyth Pro History API](https://docs.pyth.network/price-feeds/pro/api/history) +- [Auth-required announcement](https://dev-forum.pyth.network/t/action-required-pyth-pro-history-api-auth-required-starting-july-24/808/2) diff --git a/pro/frontend-jwt-auth/next.config.mjs b/pro/frontend-jwt-auth/next.config.mjs new file mode 100644 index 00000000..d5456a15 --- /dev/null +++ b/pro/frontend-jwt-auth/next.config.mjs @@ -0,0 +1,6 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, +}; + +export default nextConfig; diff --git a/pro/frontend-jwt-auth/package.json b/pro/frontend-jwt-auth/package.json new file mode 100644 index 00000000..6f5d46df --- /dev/null +++ b/pro/frontend-jwt-auth/package.json @@ -0,0 +1,28 @@ +{ + "name": "pyth-pro-frontend-jwt-auth-example", + "version": "1.0.0", + "description": "Next.js example: render live Pyth Pro price charts, authenticating every History API request via the JWT flow.", + "private": true, + "license": "Apache-2.0", + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "fix:format": "prettier --write \"**/*.{ts,tsx,js,mjs,cjs,json,md,css}\"", + "test:format": "prettier --check \"**/*.{ts,tsx,js,mjs,cjs,json,md,css}\"", + "test:types": "tsc --noEmit" + }, + "dependencies": { + "lightweight-charts": "^4.2.1", + "next": "^14.2.15", + "react": "^18.3.1", + "react-dom": "^18.3.1" + }, + "devDependencies": { + "@types/node": "^22.10.0", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "prettier": "^3.4.1", + "typescript": "^5.7.2" + } +} diff --git a/pro/frontend-jwt-auth/pnpm-lock.yaml b/pro/frontend-jwt-auth/pnpm-lock.yaml new file mode 100644 index 00000000..90442ee5 --- /dev/null +++ b/pro/frontend-jwt-auth/pnpm-lock.yaml @@ -0,0 +1,372 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + lightweight-charts: + specifier: ^4.2.1 + version: 4.2.3 + next: + specifier: ^14.2.15 + version: 14.2.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + devDependencies: + '@types/node': + specifier: ^22.10.0 + version: 22.20.1 + '@types/react': + specifier: ^18.3.12 + version: 18.3.31 + '@types/react-dom': + specifier: ^18.3.1 + version: 18.3.7(@types/react@18.3.31) + prettier: + specifier: ^3.4.1 + version: 3.9.6 + typescript: + specifier: ^5.7.2 + version: 5.9.3 + +packages: + + '@next/env@14.2.35': + resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} + + '@next/swc-darwin-arm64@14.2.33': + resolution: {integrity: sha512-HqYnb6pxlsshoSTubdXKu15g3iivcbsMXg4bYpjL2iS/V6aQot+iyF4BUc2qA/J/n55YtvE4PHMKWBKGCF/+wA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@next/swc-darwin-x64@14.2.33': + resolution: {integrity: sha512-8HGBeAE5rX3jzKvF593XTTFg3gxeU4f+UWnswa6JPhzaR6+zblO5+fjltJWIZc4aUalqTclvN2QtTC37LxvZAA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@next/swc-linux-arm64-gnu@14.2.33': + resolution: {integrity: sha512-JXMBka6lNNmqbkvcTtaX8Gu5by9547bukHQvPoLe9VRBx1gHwzf5tdt4AaezW85HAB3pikcvyqBToRTDA4DeLw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-musl@14.2.33': + resolution: {integrity: sha512-Bm+QulsAItD/x6Ih8wGIMfRJy4G73tu1HJsrccPW6AfqdZd0Sfm5Imhgkgq2+kly065rYMnCOxTBvmvFY1BKfg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@next/swc-linux-x64-gnu@14.2.33': + resolution: {integrity: sha512-FnFn+ZBgsVMbGDsTqo8zsnRzydvsGV8vfiWwUo1LD8FTmPTdV+otGSWKc4LJec0oSexFnCYVO4hX8P8qQKaSlg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-musl@14.2.33': + resolution: {integrity: sha512-345tsIWMzoXaQndUTDv1qypDRiebFxGYx9pYkhwY4hBRaOLt8UGfiWKr9FSSHs25dFIf8ZqIFaPdy5MljdoawA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + + '@next/swc-win32-arm64-msvc@14.2.33': + resolution: {integrity: sha512-nscpt0G6UCTkrT2ppnJnFsYbPDQwmum4GNXYTeoTIdsmMydSKFz9Iny2jpaRupTb+Wl298+Rh82WKzt9LCcqSQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@next/swc-win32-ia32-msvc@14.2.33': + resolution: {integrity: sha512-pc9LpGNKhJ0dXQhZ5QMmYxtARwwmWLpeocFmVG5Z0DzWq5Uf0izcI8tLc+qOpqxO1PWqZ5A7J1blrUIKrIFc7Q==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@next/swc-win32-x64-msvc@14.2.33': + resolution: {integrity: sha512-nOjfZMy8B94MdisuzZo9/57xuFVLHJaDj5e/xrduJp9CV2/HrfxTRH2fbyLe+K9QT41WBLUd4iXX3R7jBp0EUg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.5': + resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + + '@types/node@22.20.1': + resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} + + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + + '@types/react@18.3.31': + resolution: {integrity: sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==} + + busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + + caniuse-lite@1.0.30001806: + resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==} + + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + fancy-canvas@2.1.0: + resolution: {integrity: sha512-nifxXJ95JNLFR2NgRV4/MxVP45G9909wJTEKz5fg/TZS20JJZA6hfgRVh/bC9bwl2zBtBNcYPjiBE4njQHVBwQ==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + lightweight-charts@4.2.3: + resolution: {integrity: sha512-5kS/2hY3wNYNzhnS8Gb+GAS07DX8GPF2YVDnd2NMC85gJVQ6RLU6YrXNgNJ6eg0AnWPwCnvaGtYmGky3HiLQEw==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + next@14.2.35: + resolution: {integrity: sha512-KhYd2Hjt/O1/1aZVX3dCwGXM1QmOV4eNM2UTacK5gipDdPN/oHHK/4oVGy7X8GMfPMsUTUEmGlsy0EY1YGAkig==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.41.2 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + sass: + optional: true + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + + prettier@3.9.6: + resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} + engines: {node: '>=14'} + hasBin: true + + react-dom@18.3.1: + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + + react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + + scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + + styled-jsx@5.1.1: + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0' + peerDependenciesMeta: + '@babel/core': + optional: true + babel-plugin-macros: + optional: true + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + +snapshots: + + '@next/env@14.2.35': {} + + '@next/swc-darwin-arm64@14.2.33': + optional: true + + '@next/swc-darwin-x64@14.2.33': + optional: true + + '@next/swc-linux-arm64-gnu@14.2.33': + optional: true + + '@next/swc-linux-arm64-musl@14.2.33': + optional: true + + '@next/swc-linux-x64-gnu@14.2.33': + optional: true + + '@next/swc-linux-x64-musl@14.2.33': + optional: true + + '@next/swc-win32-arm64-msvc@14.2.33': + optional: true + + '@next/swc-win32-ia32-msvc@14.2.33': + optional: true + + '@next/swc-win32-x64-msvc@14.2.33': + optional: true + + '@swc/counter@0.1.3': {} + + '@swc/helpers@0.5.5': + dependencies: + '@swc/counter': 0.1.3 + tslib: 2.8.1 + + '@types/node@22.20.1': + dependencies: + undici-types: 6.21.0 + + '@types/prop-types@15.7.15': {} + + '@types/react-dom@18.3.7(@types/react@18.3.31)': + dependencies: + '@types/react': 18.3.31 + + '@types/react@18.3.31': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.2.3 + + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + + caniuse-lite@1.0.30001806: {} + + client-only@0.0.1: {} + + csstype@3.2.3: {} + + fancy-canvas@2.1.0: {} + + graceful-fs@4.2.11: {} + + js-tokens@4.0.0: {} + + lightweight-charts@4.2.3: + dependencies: + fancy-canvas: 2.1.0 + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + nanoid@3.3.16: {} + + next@14.2.35(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + '@next/env': 14.2.35 + '@swc/helpers': 0.5.5 + busboy: 1.6.0 + caniuse-lite: 1.0.30001806 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + styled-jsx: 5.1.1(react@18.3.1) + optionalDependencies: + '@next/swc-darwin-arm64': 14.2.33 + '@next/swc-darwin-x64': 14.2.33 + '@next/swc-linux-arm64-gnu': 14.2.33 + '@next/swc-linux-arm64-musl': 14.2.33 + '@next/swc-linux-x64-gnu': 14.2.33 + '@next/swc-linux-x64-musl': 14.2.33 + '@next/swc-win32-arm64-msvc': 14.2.33 + '@next/swc-win32-ia32-msvc': 14.2.33 + '@next/swc-win32-x64-msvc': 14.2.33 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + + picocolors@1.1.1: {} + + postcss@8.4.31: + dependencies: + nanoid: 3.3.16 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prettier@3.9.6: {} + + react-dom@18.3.1(react@18.3.1): + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + + react@18.3.1: + dependencies: + loose-envify: 1.4.0 + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + + source-map-js@1.2.1: {} + + streamsearch@1.1.0: {} + + styled-jsx@5.1.1(react@18.3.1): + dependencies: + client-only: 0.0.1 + react: 18.3.1 + + tslib@2.8.1: {} + + typescript@5.9.3: {} + + undici-types@6.21.0: {} diff --git a/pro/frontend-jwt-auth/src/app/api/pyth-token/route.ts b/pro/frontend-jwt-auth/src/app/api/pyth-token/route.ts new file mode 100644 index 00000000..50393b7c --- /dev/null +++ b/pro/frontend-jwt-auth/src/app/api/pyth-token/route.ts @@ -0,0 +1,77 @@ +import { NextResponse } from "next/server"; + +const DEFAULT_PYTH_API_BASE_URL = "https://pyth.dourolabs.app"; + +// Do not cache JWTs on the edge / Data Cache — each mint is a fresh call +// to the upstream token endpoint with the server-held `PRO_API_KEY`. +export const dynamic = "force-dynamic"; + +interface MintRequestBody { + ttl_seconds?: number; +} + +export async function POST(request: Request) { + const apiKey = process.env.PRO_API_KEY; + if (!apiKey) { + return NextResponse.json( + { + error: + "PRO_API_KEY is not set. Copy .env.example to .env.local and set PRO_API_KEY, then restart `pnpm dev`.", + }, + { status: 500 }, + ); + } + + const baseUrl = process.env.PYTH_API_BASE_URL ?? DEFAULT_PYTH_API_BASE_URL; + + let body: MintRequestBody = {}; + try { + const text = await request.text(); + if (text.length > 0) { + body = JSON.parse(text) as MintRequestBody; + } + } catch { + return NextResponse.json( + { error: "Request body must be valid JSON or empty." }, + { status: 400 }, + ); + } + + const upstreamBody: MintRequestBody = {}; + if (typeof body.ttl_seconds === "number") { + upstreamBody.ttl_seconds = body.ttl_seconds; + } + + const upstream = await fetch(`${baseUrl}/auth/token`, { + method: "POST", + headers: { + Authorization: `Bearer ${apiKey}`, + "Content-Type": "application/json", + }, + body: JSON.stringify(upstreamBody), + cache: "no-store", + }); + + if (!upstream.ok) { + // For an example, mirroring the upstream text keeps debugging simple. + // In production, log the upstream response server-side and return a + // generic error so mint failures don't leak internal details. + const text = await upstream.text(); + return new NextResponse(text, { + status: upstream.status, + headers: { + "Content-Type": upstream.headers.get("content-type") ?? "text/plain", + }, + }); + } + + const json = (await upstream.json()) as { + access_token: string; + expires_at: string; + token_type: string; + }; + + return NextResponse.json(json, { + headers: { "Cache-Control": "no-store" }, + }); +} diff --git a/pro/frontend-jwt-auth/src/app/globals.css b/pro/frontend-jwt-auth/src/app/globals.css new file mode 100644 index 00000000..e3a71630 --- /dev/null +++ b/pro/frontend-jwt-auth/src/app/globals.css @@ -0,0 +1,89 @@ +:root { + color-scheme: dark; + --bg: #0a0b10; + --panel-bg: #12141b; + --panel-border: #1f2330; + --text: #e6e8ef; + --text-muted: #8a90a2; + --danger: #ef5350; +} + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + padding: 0; + min-height: 100%; + background: var(--bg); + color: var(--text); + font-family: + -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, + Cantarell, sans-serif; +} + +.page { + max-width: 1400px; + margin: 0 auto; + padding: 32px 24px 64px; +} + +.page__header { + margin-bottom: 24px; +} + +.page__header h1 { + margin: 0 0 4px; + font-size: 24px; + font-weight: 600; +} + +.page__header p { + margin: 0; + color: var(--text-muted); + font-size: 13px; +} + +.page__grid { + display: grid; + gap: 20px; + grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); +} + +.chart-card { + background: var(--panel-bg); + border: 1px solid var(--panel-border); + border-radius: 10px; + padding: 16px; + display: flex; + flex-direction: column; + min-height: 360px; +} + +.chart-card__header { + display: flex; + justify-content: space-between; + align-items: baseline; + margin-bottom: 12px; +} + +.chart-card__title { + margin: 0; + font-size: 15px; + font-weight: 600; + letter-spacing: 0.02em; +} + +.chart-card__body { + flex: 1; + min-height: 300px; +} + +.chart-card__error { + margin: 12px 0 0; + color: var(--danger); + font-size: 12px; + word-break: break-word; +} diff --git a/pro/frontend-jwt-auth/src/app/layout.tsx b/pro/frontend-jwt-auth/src/app/layout.tsx new file mode 100644 index 00000000..825d09b5 --- /dev/null +++ b/pro/frontend-jwt-auth/src/app/layout.tsx @@ -0,0 +1,18 @@ +import type { Metadata } from "next"; +import type { ReactNode } from "react"; + +import "./globals.css"; + +export const metadata: Metadata = { + title: "Pyth Pro JWT Auth Example", + description: + "Next.js example: live Pyth Pro price charts with JWT-authenticated History API requests.", +}; + +export default function RootLayout({ children }: { children: ReactNode }) { + return ( + + {children} + + ); +} diff --git a/pro/frontend-jwt-auth/src/app/page.tsx b/pro/frontend-jwt-auth/src/app/page.tsx new file mode 100644 index 00000000..8bcffc84 --- /dev/null +++ b/pro/frontend-jwt-auth/src/app/page.tsx @@ -0,0 +1,45 @@ +"use client"; + +import { useCallback, useState } from "react"; + +import { PythChart } from "@/components/PythChart"; + +// `symbol` is the value the History API expects. The Pyth Pro `/v1/symbols` +// catalog exposes fully-qualified names (e.g. `Crypto.BTC/USD`); the shorter +// forms shown in the docs table (e.g. `BTC/USD`) are ambiguous today and +// return `symbol not found` — see the PR description for the discrepancy. +const FEEDS = [ + { symbol: "Crypto.BTC/USD", label: "BTC/USD" }, + { symbol: "Crypto.ETH/USD", label: "ETH/USD" }, + { symbol: "Crypto.SOL/USD", label: "SOL/USD" }, +]; + +export default function HomePage() { + const [lastUpdated, setLastUpdated] = useState(null); + + const handleUpdated = useCallback((at: Date) => { + setLastUpdated((previous) => (previous && previous > at ? previous : at)); + }, []); + + return ( +
+
+

Pyth Pro Price Charts

+

+ Last updated:{" "} + {lastUpdated ? lastUpdated.toLocaleTimeString() : "loading…"} +

+
+
+ {FEEDS.map(({ symbol, label }) => ( + + ))} +
+
+ ); +} diff --git a/pro/frontend-jwt-auth/src/components/PythChart.tsx b/pro/frontend-jwt-auth/src/components/PythChart.tsx new file mode 100644 index 00000000..ed1f1638 --- /dev/null +++ b/pro/frontend-jwt-auth/src/components/PythChart.tsx @@ -0,0 +1,167 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; +import { + createChart, + ColorType, + type IChartApi, + type ISeriesApi, + type UTCTimestamp, +} from "lightweight-charts"; + +import { + candlesFromHistory, + fetchHistory, + type Candle, +} from "@/lib/pythClient"; + +const RESOLUTION_MINUTES = "1"; +const HISTORY_WINDOW_SECONDS = 24 * 60 * 60; +const POLL_INTERVAL_MS = 30_000; + +interface PythChartProps { + symbol: string; + label?: string; + onUpdated?: (updatedAt: Date) => void; +} + +function toChartCandle(c: Candle): { + time: UTCTimestamp; + open: number; + high: number; + low: number; + close: number; +} { + return { + time: c.time as UTCTimestamp, + open: c.open, + high: c.high, + low: c.low, + close: c.close, + }; +} + +export function PythChart({ symbol, label, onUpdated }: PythChartProps) { + const containerRef = useRef(null); + const chartRef = useRef(null); + const seriesRef = useRef | null>(null); + const [error, setError] = useState(null); + + useEffect(() => { + if (!containerRef.current) return; + + const chart = createChart(containerRef.current, { + autoSize: true, + layout: { + background: { type: ColorType.Solid, color: "#0e1015" }, + textColor: "#d1d4dc", + }, + grid: { + vertLines: { color: "#1e222d" }, + horzLines: { color: "#1e222d" }, + }, + timeScale: { + timeVisible: true, + secondsVisible: false, + }, + rightPriceScale: { + borderColor: "#2a2e39", + }, + }); + const series = chart.addCandlestickSeries({ + upColor: "#26a69a", + downColor: "#ef5350", + wickUpColor: "#26a69a", + wickDownColor: "#ef5350", + borderVisible: false, + }); + + chartRef.current = chart; + seriesRef.current = series; + + return () => { + chart.remove(); + chartRef.current = null; + seriesRef.current = null; + }; + }, []); + + useEffect(() => { + let cancelled = false; + + const load = async () => { + try { + const now = Math.floor(Date.now() / 1000); + const from = now - HISTORY_WINDOW_SECONDS; + const history = await fetchHistory({ + symbol, + from, + to: now, + resolution: RESOLUTION_MINUTES, + }); + if (cancelled) return; + + const candles = candlesFromHistory(history).map(toChartCandle); + const series = seriesRef.current; + if (!series) return; + series.setData(candles); + if (candles.length > 0) { + chartRef.current?.timeScale().fitContent(); + } + setError(null); + onUpdated?.(new Date()); + } catch (err) { + if (cancelled) return; + setError(err instanceof Error ? err.message : String(err)); + } + }; + + const refresh = async () => { + try { + const now = Math.floor(Date.now() / 1000); + // Ask for the last two candles' worth of data so the current in-progress + // candle overwrites cleanly via `series.update`. + const from = now - Number.parseInt(RESOLUTION_MINUTES, 10) * 60 * 2; + const history = await fetchHistory({ + symbol, + from, + to: now, + resolution: RESOLUTION_MINUTES, + }); + if (cancelled) return; + + const series = seriesRef.current; + if (!series) return; + const latest = candlesFromHistory(history); + for (const candle of latest) { + series.update(toChartCandle(candle)); + } + setError(null); + onUpdated?.(new Date()); + } catch (err) { + if (cancelled) return; + setError(err instanceof Error ? err.message : String(err)); + } + }; + + void load(); + const timer = window.setInterval(() => { + void refresh(); + }, POLL_INTERVAL_MS); + + return () => { + cancelled = true; + window.clearInterval(timer); + }; + }, [symbol, onUpdated]); + + return ( +
+
+

{label ?? symbol}

+
+
+ {error &&

{error}

} +
+ ); +} diff --git a/pro/frontend-jwt-auth/src/lib/pythClient.ts b/pro/frontend-jwt-auth/src/lib/pythClient.ts new file mode 100644 index 00000000..23be2393 --- /dev/null +++ b/pro/frontend-jwt-auth/src/lib/pythClient.ts @@ -0,0 +1,108 @@ +import { getPythToken, invalidatePythToken } from "./pythToken"; + +// The public browser default matches the server default in +// src/app/api/pyth-token/route.ts. History requests go directly from the +// browser to the Pyth Pro API — only the mint endpoint is proxied through +// this app so `PRO_API_KEY` stays server-side. +const DEFAULT_PYTH_API_BASE_URL = "https://pyth.dourolabs.app"; + +// The `fixed_rate@200ms` channel matches the example in the docs. Change here +// to try a different channel (e.g. `real_time`). +export const PYTH_CHANNEL = "fixed_rate@200ms"; + +// Public, non-secret. `NEXT_PUBLIC_*` env vars are inlined into the browser +// bundle at build time; `PRO_API_KEY` must never be exposed this way. +const PYTH_API_BASE_URL = + process.env.NEXT_PUBLIC_PYTH_API_BASE_URL ?? DEFAULT_PYTH_API_BASE_URL; + +export interface HistoryResponse { + s: "ok" | "no_data" | "error"; + t: number[]; + o: number[]; + h: number[]; + l: number[]; + c: number[]; + v?: number[]; + errmsg?: string; +} + +export interface Candle { + time: number; + open: number; + high: number; + low: number; + close: number; +} + +export function candlesFromHistory(history: HistoryResponse): Candle[] { + const n = Math.min( + history.t.length, + history.o.length, + history.h.length, + history.l.length, + history.c.length, + ); + const out: Candle[] = new Array(n); + for (let i = 0; i < n; i++) { + out[i] = { + time: history.t[i]!, + open: history.o[i]!, + high: history.h[i]!, + low: history.l[i]!, + close: history.c[i]!, + }; + } + return out; +} + +export interface FetchHistoryOptions { + symbol: string; + from: number; + to: number; + resolution: string; + channel?: string; +} + +async function fetchHistoryOnce( + { symbol, from, to, resolution, channel = PYTH_CHANNEL }: FetchHistoryOptions, + token: string, +): Promise { + const url = new URL(`${PYTH_API_BASE_URL}/v1/${channel}/history`); + url.searchParams.set("symbol", symbol); + url.searchParams.set("from", String(from)); + url.searchParams.set("to", String(to)); + url.searchParams.set("resolution", resolution); + return fetch(url.toString(), { + headers: { Authorization: `Bearer ${token}` }, + }); +} + +export async function fetchHistory( + options: FetchHistoryOptions, +): Promise { + let token = await getPythToken(); + let response = await fetchHistoryOnce(options, token); + + if (response.status === 401) { + // Token likely expired in-flight or was revoked. Force a fresh mint and + // retry exactly once. + invalidatePythToken(); + token = await getPythToken(); + response = await fetchHistoryOnce(options, token); + } + + if (!response.ok) { + const detail = await response.text(); + throw new Error( + `Pyth history request failed: ${response.status} ${response.statusText}${ + detail ? ` — ${detail}` : "" + }`, + ); + } + + const body = (await response.json()) as HistoryResponse; + if (body.s === "error") { + throw new Error(`Pyth history returned error: ${body.errmsg ?? "unknown"}`); + } + return body; +} diff --git a/pro/frontend-jwt-auth/src/lib/pythToken.ts b/pro/frontend-jwt-auth/src/lib/pythToken.ts new file mode 100644 index 00000000..33870e9b --- /dev/null +++ b/pro/frontend-jwt-auth/src/lib/pythToken.ts @@ -0,0 +1,36 @@ +export interface PythToken { + access_token: string; + expires_at: string; + token_type?: string; +} + +let cached: PythToken | undefined; + +const SAFETY_MARGIN_MS = 30_000; + +function isFresh(token: PythToken): boolean { + return Date.parse(token.expires_at) - Date.now() > SAFETY_MARGIN_MS; +} + +export async function getPythToken(): Promise { + if (cached && isFresh(cached)) { + return cached.access_token; + } + + const response = await fetch("/api/pyth-token", { method: "POST" }); + if (!response.ok) { + const detail = await response.text(); + throw new Error( + `Failed to mint Pyth token: ${response.status} ${response.statusText}${ + detail ? ` — ${detail}` : "" + }`, + ); + } + + cached = (await response.json()) as PythToken; + return cached.access_token; +} + +export function invalidatePythToken(): void { + cached = undefined; +} diff --git a/pro/frontend-jwt-auth/tsconfig.json b/pro/frontend-jwt-auth/tsconfig.json new file mode 100644 index 00000000..07de7bc0 --- /dev/null +++ b/pro/frontend-jwt-auth/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": false, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [{ "name": "next" }], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} From 056c44e654a1de68cd9ae09255a95c9b62a539cb Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Mon, 27 Jul 2026 12:09:36 -0400 Subject: [PATCH 2/5] fix(pro/frontend-jwt-auth): make 30s refresh work, dedupe mints, handle no_data - PythChart: series.update() in lightweight-charts v4 rejects bars older than the last one, which made every 30s refresh throw "Cannot update oldest data" and permanently freeze the charts after initial load. Track the newest applied bar time and skip older candles. - pythToken: share one in-flight mint across concurrent callers so a page load performs a single upstream /auth/token call instead of one per chart. Also expose getTokenStatus() for the UI. - pythClient: a no_data history response may omit the OHLC arrays, which crashed candlesFromHistory. Treat missing arrays as an empty candle set. Co-Authored-By: Claude Fable 5 --- .../src/components/PythChart.tsx | 6 +++ pro/frontend-jwt-auth/src/lib/pythClient.ts | 37 ++++++++-------- pro/frontend-jwt-auth/src/lib/pythToken.ts | 44 ++++++++++++++++--- 3 files changed, 61 insertions(+), 26 deletions(-) diff --git a/pro/frontend-jwt-auth/src/components/PythChart.tsx b/pro/frontend-jwt-auth/src/components/PythChart.tsx index ed1f1638..5bec9d7d 100644 --- a/pro/frontend-jwt-auth/src/components/PythChart.tsx +++ b/pro/frontend-jwt-auth/src/components/PythChart.tsx @@ -45,6 +45,7 @@ export function PythChart({ symbol, label, onUpdated }: PythChartProps) { const containerRef = useRef(null); const chartRef = useRef(null); const seriesRef = useRef | null>(null); + const lastBarTimeRef = useRef(0); const [error, setError] = useState(null); useEffect(() => { @@ -106,6 +107,7 @@ export function PythChart({ symbol, label, onUpdated }: PythChartProps) { if (!series) return; series.setData(candles); if (candles.length > 0) { + lastBarTimeRef.current = candles[candles.length - 1]!.time; chartRef.current?.timeScale().fitContent(); } setError(null); @@ -134,7 +136,11 @@ export function PythChart({ symbol, label, onUpdated }: PythChartProps) { if (!series) return; const latest = candlesFromHistory(history); for (const candle of latest) { + // `series.update` only accepts the last bar or newer ones; an + // older bar throws "Cannot update oldest data". + if (candle.time < lastBarTimeRef.current) continue; series.update(toChartCandle(candle)); + lastBarTimeRef.current = candle.time; } setError(null); onUpdated?.(new Date()); diff --git a/pro/frontend-jwt-auth/src/lib/pythClient.ts b/pro/frontend-jwt-auth/src/lib/pythClient.ts index 23be2393..b21c8a79 100644 --- a/pro/frontend-jwt-auth/src/lib/pythClient.ts +++ b/pro/frontend-jwt-auth/src/lib/pythClient.ts @@ -2,7 +2,7 @@ import { getPythToken, invalidatePythToken } from "./pythToken"; // The public browser default matches the server default in // src/app/api/pyth-token/route.ts. History requests go directly from the -// browser to the Pyth Pro API — only the mint endpoint is proxied through +// browser to the Pyth Pro API; only the mint endpoint is proxied through // this app so `PRO_API_KEY` stays server-side. const DEFAULT_PYTH_API_BASE_URL = "https://pyth.dourolabs.app"; @@ -17,11 +17,12 @@ const PYTH_API_BASE_URL = export interface HistoryResponse { s: "ok" | "no_data" | "error"; - t: number[]; - o: number[]; - h: number[]; - l: number[]; - c: number[]; + // A `no_data` (or `error`) response may omit the OHLC arrays entirely. + t?: number[]; + o?: number[]; + h?: number[]; + l?: number[]; + c?: number[]; v?: number[]; errmsg?: string; } @@ -35,21 +36,19 @@ export interface Candle { } export function candlesFromHistory(history: HistoryResponse): Candle[] { - const n = Math.min( - history.t.length, - history.o.length, - history.h.length, - history.l.length, - history.c.length, - ); + const { t, o, h, l, c } = history; + if (!t || !o || !h || !l || !c) { + return []; + } + const n = Math.min(t.length, o.length, h.length, l.length, c.length); const out: Candle[] = new Array(n); for (let i = 0; i < n; i++) { out[i] = { - time: history.t[i]!, - open: history.o[i]!, - high: history.h[i]!, - low: history.l[i]!, - close: history.c[i]!, + time: t[i]!, + open: o[i]!, + high: h[i]!, + low: l[i]!, + close: c[i]!, }; } return out; @@ -95,7 +94,7 @@ export async function fetchHistory( const detail = await response.text(); throw new Error( `Pyth history request failed: ${response.status} ${response.statusText}${ - detail ? ` — ${detail}` : "" + detail ? ` (${detail})` : "" }`, ); } diff --git a/pro/frontend-jwt-auth/src/lib/pythToken.ts b/pro/frontend-jwt-auth/src/lib/pythToken.ts index 33870e9b..7fa94f8e 100644 --- a/pro/frontend-jwt-auth/src/lib/pythToken.ts +++ b/pro/frontend-jwt-auth/src/lib/pythToken.ts @@ -5,6 +5,8 @@ export interface PythToken { } let cached: PythToken | undefined; +let inflight: Promise | undefined; +let mintCount = 0; const SAFETY_MARGIN_MS = 30_000; @@ -12,23 +14,51 @@ function isFresh(token: PythToken): boolean { return Date.parse(token.expires_at) - Date.now() > SAFETY_MARGIN_MS; } -export async function getPythToken(): Promise { - if (cached && isFresh(cached)) { - return cached.access_token; - } - +async function mintToken(): Promise { const response = await fetch("/api/pyth-token", { method: "POST" }); if (!response.ok) { const detail = await response.text(); throw new Error( `Failed to mint Pyth token: ${response.status} ${response.statusText}${ - detail ? ` — ${detail}` : "" + detail ? ` (${detail})` : "" }`, ); } cached = (await response.json()) as PythToken; - return cached.access_token; + mintCount += 1; + return cached; +} + +export interface TokenStatus { + expiresAt: string | undefined; + isFresh: boolean; + mintCount: number; +} + +// Read-only snapshot of the cache, used by the in-page auth-flow explainer. +export function getTokenStatus(): TokenStatus { + return { + expiresAt: cached?.expires_at, + isFresh: cached !== undefined && isFresh(cached), + mintCount, + }; +} + +export async function getPythToken(): Promise { + if (cached && isFresh(cached)) { + return cached.access_token; + } + + // Share one in-flight mint across concurrent callers (e.g. several charts + // mounting at once) so a page load performs a single upstream mint. + if (!inflight) { + inflight = mintToken().finally(() => { + inflight = undefined; + }); + } + const token = await inflight; + return token.access_token; } export function invalidatePythToken(): void { From 56e15100e7f993f7e41359485612bc7e76acc01d Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Mon, 27 Jul 2026 12:09:45 -0400 Subject: [PATCH 3/5] feat(pro/frontend-jwt-auth): tutorial README and live auth-flow panel - Rewrite the README as a step-by-step tutorial: why the JWT exchange exists, a mermaid sequence diagram, a walkthrough of the four files, the symbol-name gotcha, and a troubleshooting table. - Add an in-page "How these charts authenticate" panel that teaches the flow from the auth-required announcement and shows a live view of the token cache (expiry countdown, mints this session). Co-Authored-By: Claude Fable 5 --- pro/frontend-jwt-auth/README.md | 213 ++++++++++++++++-- .../src/app/api/pyth-token/route.ts | 2 +- pro/frontend-jwt-auth/src/app/globals.css | 139 ++++++++++++ pro/frontend-jwt-auth/src/app/page.tsx | 4 +- .../src/components/AuthFlowPanel.tsx | 120 ++++++++++ 5 files changed, 453 insertions(+), 25 deletions(-) create mode 100644 pro/frontend-jwt-auth/src/components/AuthFlowPanel.tsx diff --git a/pro/frontend-jwt-auth/README.md b/pro/frontend-jwt-auth/README.md index 1d364dc5..8ff660e8 100644 --- a/pro/frontend-jwt-auth/README.md +++ b/pro/frontend-jwt-auth/README.md @@ -1,15 +1,59 @@ -# Pyth Pro Frontend JWT Auth Example - -A minimal [Next.js](https://nextjs.org/) app that renders live BTC/USD, ETH/USD, and SOL/USD candlestick charts backed by the [Pyth Pro History API](https://docs.pyth.network/price-feeds/pro/api/history), authenticating every request via the [JWT flow](https://docs.pyth.network/price-feeds/pro/frontend-auth) required since 2026-07-24. - -## Prerequisites +# Tutorial: Authenticating a Frontend Against the Pyth Pro API with JWTs + +This example is a minimal [Next.js](https://nextjs.org/) app that renders live +BTC/USD, ETH/USD, and SOL/USD candlestick charts from the +[Pyth Pro History API](https://docs.pyth.network/price-feeds/pro/api/history), +and more importantly shows the **right way to authenticate a browser app** +against it. Every History API request must carry a JWT +([announcement](https://dev-forum.pyth.network/t/action-required-pyth-pro-history-api-auth-required-starting-july-24/808/2)), +and the JWT is minted with your long-lived Pro API key, which must **never** +ship to the browser. + +The finished app also renders a "How these charts authenticate" panel at the +bottom of the page with a live view of the token cache (expiry countdown, +mints this session), so you can watch the flow described below actually happen. + +## The problem this solves + +A naive frontend would call the History API with +`Authorization: Bearer $PRO_API_KEY` directly. That puts your permanent API +key in the JavaScript bundle where anyone can extract it. The +[frontend-auth flow](https://docs.pyth.network/price-feeds/pro/frontend-auth) +fixes this with a token exchange: + +1. Your **server** holds the API key and trades it for a **short-lived JWT**. +2. Your **browser** code caches that JWT and uses it for API calls. +3. When the JWT is about to expire, the browser asks your server for a new one. + +The browser only ever holds a token that expires in minutes; the key that can +mint tokens never leaves your server. + +## Architecture + +```mermaid +sequenceDiagram + participant B as Browser (charts) + participant S as Next.js server route + participant P as Pyth Pro API + + B->>S: POST /api/pyth-token + S->>P: POST /auth/token (Authorization: Bearer PRO_API_KEY) + P-->>S: { access_token, expires_at } + S-->>B: { access_token, expires_at } + Note over B: cache JWT, reuse until 30s before expiry + B->>P: GET /v1/fixed_rate@200ms/history (Authorization: Bearer JWT) + P-->>B: OHLC candles + Note over B: on 401 → invalidate, re-mint once, retry +``` -- Node.js 18 or newer -- [pnpm](https://pnpm.io/) 9+ -- A Pyth Pro API key ([contact Pyth](https://docs.pyth.network/price-feeds/pro)) +Only the **mint** step goes through your server. History requests go straight +from the browser to the Pyth Pro API; your server never proxies price data. ## Quick start +Prerequisites: Node.js 18+, [pnpm](https://pnpm.io/) 9+, and a Pyth Pro API +key ([contact Pyth](https://docs.pyth.network/price-feeds/pro)). + ```bash cd pro/frontend-jwt-auth cp .env.example .env.local # then edit .env.local and set PRO_API_KEY @@ -17,36 +61,159 @@ pnpm install pnpm dev ``` -Open — you should see three charts populated with the last 24 hours of 1-minute candles. +Open . You should see three charts with the last 24 +hours of 1-minute candles, refreshing every 30 seconds. + +## Walkthrough + +The whole flow lives in four small files. Read them in this order. + +### Step 1: The server-only mint route + +[`src/app/api/pyth-token/route.ts`](src/app/api/pyth-token/route.ts) is the +only place `PRO_API_KEY` is read. It forwards `POST /api/pyth-token` to the +Pyth Pro token endpoint: + +```ts +const upstream = await fetch(`${baseUrl}/auth/token`, { + method: "POST", + headers: { + Authorization: `Bearer ${apiKey}`, // server-held PRO_API_KEY + "Content-Type": "application/json", + }, + body: JSON.stringify(upstreamBody), + cache: "no-store", +}); +``` + +Because this file is an App Router **route handler**, it runs exclusively on +the server. The key is read from `process.env.PRO_API_KEY`, never from a +`NEXT_PUBLIC_*` variable, which Next.js would inline into the browser bundle. +On upstream errors the route mirrors the status and body back to the caller, +which makes debugging (wrong key, revoked key) much easier during development. + +### Step 2: The browser token cache + +[`src/lib/pythToken.ts`](src/lib/pythToken.ts) wraps the mint route in a tiny +module-level cache: + +```ts +export async function getPythToken(): Promise { + if (cached && isFresh(cached)) { + return cached.access_token; + } + if (!inflight) { + inflight = mintToken().finally(() => { + inflight = undefined; + }); + } + const token = await inflight; + return token.access_token; +} +``` + +Two details matter here: + +- **Safety margin.** `isFresh` treats a token as stale 30 seconds _before_ + `expires_at`, so a request never leaves the browser with a token that + expires mid-flight. +- **In-flight dedup.** Three charts mount at once and all ask for a token. + Without the shared `inflight` promise each would mint its own JWT: three + upstream calls with your API key for no benefit. With it, one mint serves + all concurrent callers. + +### Step 3: Calling the History API from the browser + +[`src/lib/pythClient.ts`](src/lib/pythClient.ts) attaches the JWT and handles +expiry-in-flight: + +```ts +let token = await getPythToken(); +let response = await fetchHistoryOnce(options, token); + +if (response.status === 401) { + invalidatePythToken(); // token expired or was revoked + token = await getPythToken(); // forces a fresh mint + response = await fetchHistoryOnce(options, token); +} +``` + +The `401` retry is the safety net for anything the safety margin can't catch: +a revoked token, a clock skew, a laptop waking from sleep. Invalidate, re-mint +once, retry once. If it still fails, surface the error. + +### Step 4: Rendering and refreshing the charts + +[`src/components/PythChart.tsx`](src/components/PythChart.tsx) draws the data +with [`lightweight-charts`](https://tradingview.github.io/lightweight-charts/): + +- On mount it loads the last 24 hours at 1-minute resolution and calls + `series.setData(...)`. +- Every 30 seconds it fetches just the last two minutes and applies them with + `series.update(...)`. One quirk to know: `series.update` only accepts the + chart's **last bar or newer**; passing an older bar throws + `Cannot update oldest data`. The component tracks the newest applied bar + time and skips anything older. -## How it works +### Watching it work -- `src/app/api/pyth-token/route.ts` is a server-only route that forwards `POST /api/pyth-token` to `POST https://pyth.dourolabs.app/auth/token` with `Authorization: Bearer $PRO_API_KEY` and returns the minted `{ access_token, expires_at, token_type }`. -- `src/lib/pythToken.ts` caches the token in the browser and refreshes it 30 seconds before `expires_at`, matching the caching pattern from the [frontend-auth docs](https://docs.pyth.network/price-feeds/pro/frontend-auth). -- `src/lib/pythClient.ts` calls `GET https://pyth.dourolabs.app/v1/fixed_rate@200ms/history?...` with the cached JWT, transparently retrying once on `401` after invalidating the cache. -- `src/components/PythChart.tsx` renders the returned OHLC arrays with [`lightweight-charts`](https://tradingview.github.io/lightweight-charts/) and polls every 30 seconds to append new candles. +The page's bottom panel (`src/components/AuthFlowPanel.tsx`) polls the token +cache once a second and shows the current JWT's expiry countdown and how many +mints have happened this session. Leave the page open for ~5 minutes and you +can watch the countdown hit the 30-second safety margin and a new mint occur. +The charts never notice. + +## Gotcha: symbol names + +The docs list symbols like `BTC/USD`, but the live `/v1/symbols` catalog +exposes crypto spot feeds under fully-qualified names like `Crypto.BTC/USD`; +the bare form returns `HTTP 404 symbol not found`. This example uses +`Crypto.{BTC,ETH,SOL}/USD` in API calls and shows the short form as the card +label. If a symbol 404s for you, check the catalog: + +```bash +curl -s "https://pyth.dourolabs.app/v1/symbols" \ + -H "Authorization: Bearer $JWT" | jq -r '.[].symbol' | grep BTC +``` ## Security notes -- `PRO_API_KEY` is read from `process.env` in the server route only. It is never referenced from a `NEXT_PUBLIC_*` variable and never imported from a client-side file, so it is not included in the browser bundle. -- The mint route in this example has no request auth or rate limit — anyone who can reach `/api/pyth-token` can mint a JWT with your `PRO_API_KEY`. **Before running this in production, add authentication (e.g. a session cookie check) and a rate limit to `/api/pyth-token`.** -- The mint route mirrors the upstream error body verbatim for easier debugging. In production, log the upstream response server-side and return a generic error instead. +- `PRO_API_KEY` is read from `process.env` in the server route only. It is + never referenced from a `NEXT_PUBLIC_*` variable and never imported from a + client-side file, so it is not included in the browser bundle. You can + verify: `pnpm build && grep -rn PRO_API_KEY .next/static` → no matches. +- The mint route in this example has **no request auth or rate limit**. + Anyone who can reach `/api/pyth-token` can mint a JWT with your key. + **Before running this in production, add authentication (e.g. a session + cookie check) and a rate limit to `/api/pyth-token`.** +- The mint route mirrors the upstream error body verbatim for easier + debugging. In production, log the upstream response server-side and return + a generic error instead. ## Configuration | Variable | Where | Default | Purpose | | ------------------------------- | ----------- | ---------------------------- | ---------------------------------------------------------- | -| `PRO_API_KEY` | Server only | — (required) | Long-lived Pyth Pro API key used to mint short-lived JWTs. | +| `PRO_API_KEY` | Server only | (required) | Long-lived Pyth Pro API key used to mint short-lived JWTs. | | `PYTH_API_BASE_URL` | Server | `https://pyth.dourolabs.app` | Override for non-prod environments. | | `NEXT_PUBLIC_PYTH_API_BASE_URL` | Browser | `https://pyth.dourolabs.app` | Override the History API base used from the browser. | ## Scripts -- `pnpm dev` — Next.js dev server on `http://localhost:3000` -- `pnpm build` — Production build (does not require `PRO_API_KEY`) -- `pnpm start` — Serve the production build -- `pnpm test:format` — Prettier check -- `pnpm test:types` — `tsc --noEmit` +- `pnpm dev`: Next.js dev server on `http://localhost:3000` +- `pnpm build`: Production build (does not require `PRO_API_KEY`) +- `pnpm start`: Serve the production build +- `pnpm test:format`: Prettier check +- `pnpm test:types`: `tsc --noEmit` + +## Troubleshooting + +| Symptom | Cause and fix | +| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| Charts show `Failed to mint Pyth token: 500…` | `PRO_API_KEY` is not set. Copy `.env.example` to `.env.local`, set the key, restart `pnpm dev`. | +| Charts show a `401` invalid API key error | The key in `.env.local` is wrong or revoked. The route mirrors the upstream body, so this is Pyth's reply. | +| Charts show a `404` symbol not found error | Use fully-qualified symbols (`Crypto.BTC/USD`), see [Gotcha: symbol names](#gotcha-symbol-names). | +| Token env changes not picked up | Next.js reads `.env.local` at startup, so restart `pnpm dev` after editing it. | ## References diff --git a/pro/frontend-jwt-auth/src/app/api/pyth-token/route.ts b/pro/frontend-jwt-auth/src/app/api/pyth-token/route.ts index 50393b7c..8b2be981 100644 --- a/pro/frontend-jwt-auth/src/app/api/pyth-token/route.ts +++ b/pro/frontend-jwt-auth/src/app/api/pyth-token/route.ts @@ -2,7 +2,7 @@ import { NextResponse } from "next/server"; const DEFAULT_PYTH_API_BASE_URL = "https://pyth.dourolabs.app"; -// Do not cache JWTs on the edge / Data Cache — each mint is a fresh call +// Do not cache JWTs on the edge / Data Cache; each mint is a fresh call // to the upstream token endpoint with the server-held `PRO_API_KEY`. export const dynamic = "force-dynamic"; diff --git a/pro/frontend-jwt-auth/src/app/globals.css b/pro/frontend-jwt-auth/src/app/globals.css index e3a71630..e5b8dba3 100644 --- a/pro/frontend-jwt-auth/src/app/globals.css +++ b/pro/frontend-jwt-auth/src/app/globals.css @@ -87,3 +87,142 @@ body { font-size: 12px; word-break: break-word; } + +.flow { + margin-top: 28px; + background: var(--panel-bg); + border: 1px solid var(--panel-border); + border-radius: 10px; + padding: 20px; +} + +.flow__header { + display: flex; + flex-direction: column; + gap: 10px; + margin-bottom: 20px; +} + +.flow__intro { + margin: 0; + max-width: 720px; + color: var(--text-muted); + font-size: 13px; + line-height: 1.65; +} + +.flow__intro strong { + color: var(--text); + font-weight: 600; +} + +.flow__title { + margin: 0; + font-size: 15px; + font-weight: 600; + letter-spacing: 0.02em; +} + +.flow__status { + margin: 0; + color: var(--text-muted); + font-size: 12.5px; + display: flex; + align-items: center; + gap: 7px; +} + +.flow__dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: var(--text-muted); + flex-shrink: 0; +} + +.flow__dot--fresh { + background: #26a69a; +} + +.flow__steps { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; +} + +.flow__step { + position: relative; + display: grid; + grid-template-columns: 28px 1fr; + column-gap: 14px; + padding-bottom: 22px; +} + +.flow__step:last-child { + padding-bottom: 0; +} + +/* Connector line between the number badges */ +.flow__step:not(:last-child)::before { + content: ""; + position: absolute; + left: 14px; + top: 32px; + bottom: 4px; + width: 1px; + background: var(--panel-border); +} + +.flow__num { + width: 28px; + height: 28px; + border-radius: 50%; + background: #1a1e2a; + border: 1px solid var(--panel-border); + font-size: 13px; + font-weight: 600; + display: flex; + align-items: center; + justify-content: center; +} + +.flow__body h3 { + margin: 5px 0 6px; + font-size: 13.5px; + font-weight: 600; +} + +.flow__body p { + margin: 0; + max-width: 660px; + color: var(--text-muted); + font-size: 13px; + line-height: 1.65; +} + +.flow__step code { + background: #1a1e2a; + border: 1px solid var(--panel-border); + border-radius: 4px; + padding: 1px 5px; + font-size: 0.92em; + color: var(--text); + word-break: break-word; +} + +.flow__footer { + margin: 20px 0 0; + padding-top: 14px; + border-top: 1px solid var(--panel-border); + color: var(--text-muted); + font-size: 12.5px; + line-height: 1.6; +} + +.flow__footer a { + color: #26a69a; + text-decoration: underline; + text-underline-offset: 2px; +} diff --git a/pro/frontend-jwt-auth/src/app/page.tsx b/pro/frontend-jwt-auth/src/app/page.tsx index 8bcffc84..4ea3c4aa 100644 --- a/pro/frontend-jwt-auth/src/app/page.tsx +++ b/pro/frontend-jwt-auth/src/app/page.tsx @@ -2,12 +2,13 @@ import { useCallback, useState } from "react"; +import { AuthFlowPanel } from "@/components/AuthFlowPanel"; import { PythChart } from "@/components/PythChart"; // `symbol` is the value the History API expects. The Pyth Pro `/v1/symbols` // catalog exposes fully-qualified names (e.g. `Crypto.BTC/USD`); the shorter // forms shown in the docs table (e.g. `BTC/USD`) are ambiguous today and -// return `symbol not found` — see the PR description for the discrepancy. +// return `symbol not found`; see the README for the discrepancy. const FEEDS = [ { symbol: "Crypto.BTC/USD", label: "BTC/USD" }, { symbol: "Crypto.ETH/USD", label: "ETH/USD" }, @@ -40,6 +41,7 @@ export default function HomePage() { /> ))} + ); } diff --git a/pro/frontend-jwt-auth/src/components/AuthFlowPanel.tsx b/pro/frontend-jwt-auth/src/components/AuthFlowPanel.tsx new file mode 100644 index 00000000..82ed840d --- /dev/null +++ b/pro/frontend-jwt-auth/src/components/AuthFlowPanel.tsx @@ -0,0 +1,120 @@ +"use client"; + +import { useEffect, useState } from "react"; + +import { getTokenStatus, type TokenStatus } from "@/lib/pythToken"; + +const ANNOUNCEMENT_URL = + "https://dev-forum.pyth.network/t/action-required-pyth-pro-history-api-auth-required-starting-july-24/808/2"; +const FRONTEND_AUTH_DOCS_URL = + "https://docs.pyth.network/price-feeds/pro/frontend-auth"; + +function formatRemaining(expiresAt: string): string { + const ms = Date.parse(expiresAt) - Date.now(); + if (Number.isNaN(ms) || ms <= 0) { + return "expired"; + } + const totalSeconds = Math.floor(ms / 1000); + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds % 60; + return minutes > 0 ? `${minutes}m ${seconds}s` : `${seconds}s`; +} + +/** + * Teaches the JWT auth flow these charts use, with a live view of the token + * cache (expiry countdown, mints this session) so the flow is observable. + */ +export function AuthFlowPanel() { + const [status, setStatus] = useState(null); + + useEffect(() => { + const tick = () => setStatus(getTokenStatus()); + tick(); + const timer = window.setInterval(tick, 1_000); + return () => window.clearInterval(timer); + }, []); + + let statusLine = "No JWT minted yet. Waiting for the first chart request."; + let statusFresh = false; + if (status && status.expiresAt) { + statusFresh = status.isFresh; + const remaining = formatRemaining(status.expiresAt); + statusLine = status.isFresh + ? `JWT cached, expires in ${remaining}` + : `JWT expiring, re-mints on the next request`; + statusLine += ` · ${status.mintCount} mint${status.mintCount === 1 ? "" : "s"} this session`; + } + + return ( +
+
+

How these charts authenticate

+

+ The Pyth Pro API key is a long-lived secret that must never reach the + browser. Instead, the server trades it for short-lived JWTs the charts + can use safely: +

+

+ + {statusLine} +

+
+
    +
  1. + 1 +
    +

    The browser asks the backend for a token

    +

    + Charts never touch the API key. They request a JWT from this + app's backend and share one cached token. +

    +
    +
  2. +
  3. + 2 +
    +

    The backend mints a JWT

    +

    + It calls POST /auth/token with the server-held API + key, the only place the secret is ever used. +

    +
    +
  4. +
  5. + 3 +
    +

    The browser calls the Pyth Pro API directly

    +

    + Candles are fetched with{" "} + Authorization: Bearer <jwt>, with no proxy in + the data path. A leaked JWT dies in minutes. +

    +
    +
  6. +
  7. + 4 +
    +

    Tokens rotate automatically

    +

    + A new JWT is minted just before expiry (watch the countdown + above), and any 401 triggers a re-mint and retry. +

    +
    +
  8. +
+

+ From the{" "} + + announcement + {" "} + and{" "} + + frontend-auth docs + + . The README walks through the code behind each step. +

+
+ ); +} From a7416748a38e7425de32247f16e811bfa3452ee9 Mon Sep 17 00:00:00 2001 From: Aditya Arora Date: Mon, 27 Jul 2026 12:24:21 -0400 Subject: [PATCH 4/5] docs(pro/frontend-jwt-auth): pair base URL overrides, add screenshot and JWT snippet - Document in .env.example and the README that PYTH_API_BASE_URL and NEXT_PUBLIC_PYTH_API_BASE_URL must be overridden together, since the server mints tokens against one while the browser fetches history from the other (addresses the Codex P2 review comment). - Add an app screenshot to the README and the bearer-token attach snippet to the walkthrough, so the full JWT flow is visible in the docs. Co-Authored-By: Claude Fable 5 --- pro/frontend-jwt-auth/.env.example | 8 ++++++-- pro/frontend-jwt-auth/README.md | 24 ++++++++++++++++++++++-- pro/frontend-jwt-auth/screenshot.png | Bin 0 -> 129381 bytes 3 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 pro/frontend-jwt-auth/screenshot.png diff --git a/pro/frontend-jwt-auth/.env.example b/pro/frontend-jwt-auth/.env.example index 017dc70c..610c56a4 100644 --- a/pro/frontend-jwt-auth/.env.example +++ b/pro/frontend-jwt-auth/.env.example @@ -2,6 +2,10 @@ # (see https://docs.pyth.network/price-feeds/pro). PRO_API_KEY=your_pyth_pro_api_key_here -# Optional. Override the default Pyth Pro API base URL -# if you are pointed at a non-prod environment. +# Optional. Override the default Pyth Pro API base URL if you are pointed +# at a non-prod environment. Set BOTH variables together: the server mints +# tokens against PYTH_API_BASE_URL, while the browser sends history requests +# to NEXT_PUBLIC_PYTH_API_BASE_URL. Overriding only one splits the app +# across two environments. # PYTH_API_BASE_URL=https://pyth.dourolabs.app +# NEXT_PUBLIC_PYTH_API_BASE_URL=https://pyth.dourolabs.app diff --git a/pro/frontend-jwt-auth/README.md b/pro/frontend-jwt-auth/README.md index 8ff660e8..fac6ac09 100644 --- a/pro/frontend-jwt-auth/README.md +++ b/pro/frontend-jwt-auth/README.md @@ -9,6 +9,8 @@ against it. Every History API request must carry a JWT and the JWT is minted with your long-lived Pro API key, which must **never** ship to the browser. +![Live BTC, ETH, and SOL candlestick charts above the auth flow panel](screenshot.png) + The finished app also renders a "How these charts authenticate" panel at the bottom of the page with a live view of the token cache (expiry countdown, mints this session), so you can watch the flow described below actually happen. @@ -124,8 +126,21 @@ Two details matter here: ### Step 3: Calling the History API from the browser -[`src/lib/pythClient.ts`](src/lib/pythClient.ts) attaches the JWT and handles -expiry-in-flight: +[`src/lib/pythClient.ts`](src/lib/pythClient.ts) attaches the JWT as a bearer +token on every history request: + +```ts +const url = new URL(`${PYTH_API_BASE_URL}/v1/${channel}/history`); +url.searchParams.set("symbol", symbol); +url.searchParams.set("from", String(from)); +url.searchParams.set("to", String(to)); +url.searchParams.set("resolution", resolution); +return fetch(url.toString(), { + headers: { Authorization: `Bearer ${token}` }, // short-lived JWT, not the API key +}); +``` + +It also handles expiry-in-flight: ```ts let token = await getPythToken(); @@ -198,6 +213,11 @@ curl -s "https://pyth.dourolabs.app/v1/symbols" \ | `PYTH_API_BASE_URL` | Server | `https://pyth.dourolabs.app` | Override for non-prod environments. | | `NEXT_PUBLIC_PYTH_API_BASE_URL` | Browser | `https://pyth.dourolabs.app` | Override the History API base used from the browser. | +Set the two base URL overrides together: the server mints tokens against +`PYTH_API_BASE_URL`, while the browser fetches history from +`NEXT_PUBLIC_PYTH_API_BASE_URL`. Overriding only one splits the app across +two environments. + ## Scripts - `pnpm dev`: Next.js dev server on `http://localhost:3000` diff --git a/pro/frontend-jwt-auth/screenshot.png b/pro/frontend-jwt-auth/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..3477b68fc73dce3481471c7fe4dbab162a7f1c23 GIT binary patch literal 129381 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 Date: Mon, 27 Jul 2026 12:36:55 -0400 Subject: [PATCH 5/5] ops: add greenlight config to enable review Greenlight requires .github/greenlight.yml with enabled: true at the PR head before it will review. Minimal config, no auto-approve paths. Co-Authored-By: Claude Fable 5 --- .github/greenlight.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/greenlight.yml diff --git a/.github/greenlight.yml b/.github/greenlight.yml new file mode 100644 index 00000000..45935ff9 --- /dev/null +++ b/.github/greenlight.yml @@ -0,0 +1,2 @@ +enabled: true +required_reviewer_checks: []