feat: remove API key requirement from public API#11984
feat: remove API key requirement from public API#119840xApotheosis wants to merge 1 commit intodevelopfrom
Conversation
The partner info attached via req.partner was never used in any route handler — it only served as an access gate. Removing it makes the API truly public and simplifies integration for consumers including the swap widget. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR removes API key-based authentication from the public API and swap widget packages. It deletes the STATIC_API_KEYS configuration, auth middleware functions, OpenAPI security schemes, and apiKey properties from client and component configurations. Routes and components now operate without authentication validation or header requirements. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~28 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Closing, neo already tackled this here: #11959 |
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/public-api/src/index.ts (1)
48-59: LGTM — consider adding rate limiting now that the auth gate is gone.The auth removal is clean. One operational note: with authentication removed, the only protection against endpoint abuse is the underlying infrastructure. If this API is exposed publicly, a lightweight rate-limiting middleware (e.g.,
express-rate-limit) on the v1 router would help prevent runaway costs from the downstream swapper integrations.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/public-api/src/index.ts` around lines 48 - 59, Authentication was removed leaving v1Router endpoints (v1Router.get('/swap/rates', getRates), v1Router.post('/swap/quote', getQuote), v1Router.get('/chains', getChains), getChainCount, getAssets, getAssetCount, getAssetById) unprotected from abuse; add a lightweight rate-limiting middleware (e.g., express-rate-limit) and apply it to the v1Router (or specifically to swap endpoints) by creating a rateLimit instance with sensible defaults (windowMs, max, and a standard handler) and use v1Router.use(rateLimit(...)) before the route registrations so all listed handlers are throttled.packages/public-api/tests/smoke-tests.ts (1)
88-174: Consider extracting the shared rates-test body to a helper.Tests 7 and 8 are structurally identical — same
URLSearchParamsconstruction, same 30 sfetchWithTimeoutcall, samevalidRatesfilter, and the sameconsole.warn/console.logbranches. The only differences are the pair variable and the test name.♻️ Suggested extraction
+const runRatesTest = async ( + API_URL: string, + pair: { name: string; sellAssetId: string; buyAssetId: string; sellAmountCryptoBaseUnit: string }, +): Promise<void> => { + const params = new URLSearchParams({ + sellAssetId: pair.sellAssetId, + buyAssetId: pair.buyAssetId, + sellAmountCryptoBaseUnit: pair.sellAmountCryptoBaseUnit, + }) + const res = await fetchWithTimeout(`${API_URL}/v1/swap/rates?${params}`, {}, 30000) + if (!res.ok) throw new Error(`Rates request failed: ${res.status}`) + const data = (await res.json()) as { + rates?: { swapperName: string; error?: unknown; buyAmountCryptoBaseUnit?: string }[] + } + if (!Array.isArray(data.rates)) throw new Error('Invalid rates response structure') + const validRates = data.rates.filter( + r => !r.error && r.buyAmountCryptoBaseUnit && r.buyAmountCryptoBaseUnit !== '0', + ) + if (validRates.length === 0) { + const swappersWithErrors = data.rates.filter(r => r.error).map(r => r.swapperName).join(', ') + console.warn( + `Warning: No valid rates returned for ${pair.name}. Swappers with errors: ${swappersWithErrors || 'none'}`, + ) + } else { + console.log(` Found ${validRates.length} valid rate(s) from: ${validRates.map(r => r.swapperName).join(', ')}`) + } +} - // 7. EVM Same-Chain Rates (Informative) - const evmPair = TEST_PAIRS.evmSameChain[0] - results.push( - await runTest(`Rates: ${evmPair.name}`, false, async () => { - ... - }), - ) - - // 8. Cross-Chain Rates (Informative) - const crossChainPair = TEST_PAIRS.crossChain[0] - results.push( - await runTest(`Rates: ${crossChainPair.name}`, false, async () => { - ... - }), - ) + for (const [label, pair] of [ + ['evmSameChain', TEST_PAIRS.evmSameChain[0]], + ['crossChain', TEST_PAIRS.crossChain[0]], + ] as const) { + results.push(await runTest(`Rates: ${pair.name}`, false, () => runRatesTest(API_URL, pair))) + }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/public-api/tests/smoke-tests.ts` around lines 88 - 174, Extract the duplicated rates-test body into a helper like checkRatesForPair(pair, testLabel) and call it from the two runTest invocations; the helper should (1) construct URLSearchParams from pair.sellAssetId / pair.buyAssetId / pair.sellAmountCryptoBaseUnit, (2) call fetchWithTimeout(`${API_URL}/v1/swap/rates?${params}`, {}, 30000), (3) assert res.ok and parse JSON, (4) validate Array.isArray(data.rates), filter validRates by !r.error && r.buyAmountCryptoBaseUnit && r.buyAmountCryptoBaseUnit !== '0', and (5) emit the same console.warn/console.log branches. Replace the duplicated inline async bodies for evmPair and crossChainPair with results.push(await runTest(`Rates: ${pair.name}`, false, async () => checkRatesForPair(pair, pair.name))). Ensure helper references: API_URL, fetchWithTimeout, runTest, evmPair, crossChainPair, and TEST_PAIRS.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/public-api/src/index.ts`:
- Around line 48-59: Authentication was removed leaving v1Router endpoints
(v1Router.get('/swap/rates', getRates), v1Router.post('/swap/quote', getQuote),
v1Router.get('/chains', getChains), getChainCount, getAssets, getAssetCount,
getAssetById) unprotected from abuse; add a lightweight rate-limiting middleware
(e.g., express-rate-limit) and apply it to the v1Router (or specifically to swap
endpoints) by creating a rateLimit instance with sensible defaults (windowMs,
max, and a standard handler) and use v1Router.use(rateLimit(...)) before the
route registrations so all listed handlers are throttled.
In `@packages/public-api/tests/smoke-tests.ts`:
- Around line 88-174: Extract the duplicated rates-test body into a helper like
checkRatesForPair(pair, testLabel) and call it from the two runTest invocations;
the helper should (1) construct URLSearchParams from pair.sellAssetId /
pair.buyAssetId / pair.sellAmountCryptoBaseUnit, (2) call
fetchWithTimeout(`${API_URL}/v1/swap/rates?${params}`, {}, 30000), (3) assert
res.ok and parse JSON, (4) validate Array.isArray(data.rates), filter validRates
by !r.error && r.buyAmountCryptoBaseUnit && r.buyAmountCryptoBaseUnit !== '0',
and (5) emit the same console.warn/console.log branches. Replace the duplicated
inline async bodies for evmPair and crossChainPair with results.push(await
runTest(`Rates: ${pair.name}`, false, async () => checkRatesForPair(pair,
pair.name))). Ensure helper references: API_URL, fetchWithTimeout, runTest,
evmPair, crossChainPair, and TEST_PAIRS.
Description
Remove the API key requirement from the public API. The
req.partnerdata attached by the auth middleware was never consumed by any route handler — it only served as an access gate without functional value. This makes the API truly public and simplifies integration for consumers including the swap widget.Changes:
packages/public-api/src/middleware/auth.tsSTATIC_API_KEYSfrom config,PartnerConfigtype, and Express Request augmentationindex.tsapiKeyAuthsecurity scheme andsecurityannotations from OpenAPI specapiKeyprop from swap widget (SwapWidgetProps,ApiClientConfig,SwapWidgetcomponent, demo app)apiKeyreferencesRisk
Low. This is purely removing an unused access gate — no route handler logic changes. The API endpoints themselves are unchanged. The swap widget already worked with or without the key (it was optional in props).
None. This only affects HTTP API access control and widget configuration.
Testing
Engineering
yarn workspace @shapeshiftoss/public-api build:bundle && yarn workspace @shapeshiftoss/public-api start:prodhttp://localhost:3001/docshas no Authentication sectionyarn lintandyarn type-checkpassOperations
Verify that the public API docs page (
/docs) no longer shows an Authentication section, and that swap endpoints respond without requiring anX-API-Keyheader.🤖 Generated with Claude Code
Summary by CodeRabbit
API Changes
Documentation