Skip to content

Move YouVersion calls behind fluent-api so the API key stays server-side #458

Description

@kaseywright

Parent epic: fluent-web#387
Repos affected: fluent-api, fluent-web
Scope: YouVersion only. Aquifer is tracked separately as the sibling sub-ticket.

Problem

VITE_YOUVERSION_API_KEY is inlined into the client JS bundle by Vite at build time (.github/workflows/deploy.yml, env block on the Deploy to Azure step) and read in the browser at src/lib/config.tsgetYouVersionApiHeaders(). All three YouVersion requests in src/features/resources/hooks/useYouVersion.ts send it from the visitor's browser, so anyone can extract it from the deployed bundle. See the epic for full background.

Unlike Aquifer, this is greenfield

fluent-api has no YouVersion presence at all — no client, no env var, no routes. The whole server side has to be built. The Aquifer integration is the pattern to copy:

  • src/lib/services/aquifer/aquifer.client.ts — client, timeouts, response validation
  • src/lib/services/aquifer/aquifer.errors.ts — upstream failure → 502 mapping
  • src/env.ts — optional server-held key; routes degrade to a service-unavailable response when unset rather than blocking boot

Endpoints to cover

Everything src/features/resources/hooks/useYouVersion.ts calls today:

fluent-web call Purpose
/bibles?language_tag=…&language_ranges[]=… bible picker options for a language
/bibles/{bibleId}/books/{bookId}/chapters/{chapterId} chapter metadata → verse list
passage fetch (fanned out per verse) verse text for the reference column

Note the per-verse fan-out in src/features/resources/hooks/hooks.ts — a chapter produces one request per verse. Proxying puts all of that on a single server-held key, so caching and/or a chapter-level batch route should be considered rather than a naive 1:1 passthrough.

Work

fluent-api

  • Add YOUVERSION_API_URL / YOUVERSION_API_KEY to src/env.ts (optional key, same degrade-don't-crash treatment as AQUIFER_API_KEY)
  • Build src/lib/services/youversion/ client + error mapping, modelled on the Aquifer service
  • Add routes for bibles-by-language, chapter metadata, and passage text
  • Decide project-scoped vs. authenticated-only route shape — should match whatever the Aquifer sub-ticket settles on, since the bible picker mixes both providers in one UI
  • Caching / batching for the per-verse fan-out
  • Tests + OpenAPI docs

fluent-web

  • Repoint the three fetch sites in src/features/resources/hooks/useYouVersion.ts at fluent-api
  • Delete YOUVERSION_API_KEY / youversion_key and getYouVersionApiHeaders() from src/lib/config.ts (including the envSchema entry that currently makes it required to boot)
  • Remove VITE_YOUVERSION_API_KEY (and VITE_YOUVERSION_API_URL, once unused) from .env.example

Decommission

  • Remove VITE_YOUVERSION_API_KEY from the env block in .github/workflows/deploy.yml
  • Delete the VITE_YOUVERSION_API_KEY GitHub secret
  • Rotate the YouVersion key — the current one has shipped in deployed bundles and must be treated as compromised

Check before building

  • Terms of use. Confirm YouVersion's API terms permit server-side proxying and any response caching we add, and that attribution/copyright fields returned by the API (copyright, publisher_url, promotional_content, youversion_deep_link) keep being surfaced as required.
  • Key scope. Document the current scope/permissions on the key. If YouVersion offers a tightly-scoped publishable key, that is worth knowing — but it is a mitigation, not a substitute for this work, since a client-side key stays extractable either way.

Landing constraint

The fluent-api and fluent-web changes must land together: fluent-web won't boot without the key until config.ts stops requiring it, and it can't stop requiring it until the API routes exist. Ship the API routes first (additive, harmless on their own), then the web migration, then the workflow/secret removal and rotation.

This ticket is independent of the Aquifer sub-ticket — the two services can land in either order. Note that the rotation/decommission benefit is only fully realized once both keys are out of the bundle.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

DevQAEngineering must QA the ticket presumably because it is a backend changeSP16serverweb-app

Type

No type

Projects

  • Status
    In PR Review

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions