Skip to content

STRAVA-001 — Harden and modernize the existing Strava OAuth connection #88

Description

@daliu

Problem

The repository has a functional Strava prototype, but OAuth state is browser-local, provider error bodies can leak, scopes are broader than club-link needs, token refresh is not concurrency safe, and provider capacity/configuration is unverified.

Scope

  • Use server-issued, UID/session-bound, one-use OAuth state with TTL.
  • Bound callback/code inputs and return generic client errors without provider bodies.
  • Request only read for club-link use; make activity:read a separate explicit feature consent and persist actual granted scopes.
  • Enforce one athlete ID owner; keep tokens server-only; make refresh rotation transactional/idempotent.
  • Adopt the current OAuth revoke path and retry-safe deletion behavior.
  • Verify provider athlete capacity and use non-production credentials/accounts for tests.

Acceptance criteria

  • CSRF/state replay, wrong/missing scope, duplicate athlete, concurrent refresh, revoke retry, rate limit, and redaction tests pass.
  • Disconnect/deauthorization removes local tokens and connection data according to policy.
  • No Strava token/provider body is exposed to clients, logs, custom claims, or issues.
  • Local/CI cannot call the production Strava host.
  • The integration never grants website membership or discounts.

Dependencies and sequence

  • SAFETY-001/SAFETY-001 — Preserve callbacks and fail closed on local Firebase isolation #99 is the callback/privacy foundation and is complete in source. OAUTH-001C depends on that guard.
  • OAUTH-001A follows SEC-001 and the AUTH-003 capability boundary. Production cutover still requires the exact Firebase deployment evidence owned by CI-001 — Establish trustworthy quality gates and protected deployment #105.
  • AUTH-001 remains a live-rollout gate for associating Strava with a verified website account; it does not block isolated synthetic A/B/C implementation and tests.
  • ABUSE-001A is not a blanket prerequisite. It may enforce App Check on its agreed callable group while explicitly deferring stravaExchangeCode. OAUTH-001C then proves the safe handoff before that one callable moves into enforcement.
  • OAUTH-001B follows A and requires the named provider/IAM/encryption owner decisions before hosted closure.

Official references

Coordination

Parent: #79

Read the slice-specific sequence below before claiming. Do not claim the whole tracker unless one reviewable outcome truly completes A, B, and C. A or C may be assigned and claimed independently after only that slice's dependencies are complete; C follows merged #99 and the recorded ABUSE-001A deferral, not completion of all ABUSE work. B is owner action for provider/IAM/encryption decisions and follows A. Before editing, assign the exact slice and post a timestamped CLAIMED comment naming the slice, agent, and branch. Creation of this tracker is not a claim. Preserve parallel work tracked by stable IDs in GITHUB_ISSUES.md.

Canonical OAUTH-001 map — 2026-07-13

This issue is the canonical live tracker for repository outcome OAUTH-001. The bounded OAUTH-001A/B/C rows in GITHUB_ISSUE_SLICES.md are parts of this issue, not separate tickets to publish by default.

  • OAUTH-001A — refresh concurrency: implement server-only transaction/version-safe refresh so a retry or concurrent call cannot overwrite a newly rotated refresh token.
  • OAUTH-001B — scope, revoke, storage, and audit: minimize and verify scopes/account binding; implement retry-safe disconnect/provider revocation; record the named IAM/application-encryption decision; add redacted durable access/refresh/failure/revoke audit.
  • OAUTH-001C — protected callback handoff: preserve SAFETY-001 — Preserve callbacks and fail closed on local Firebase isolation #99's initial capability guard; keep OAuth code/state out of third-party startup; retain one-use UID/session-bound state verification and server-only exchange; keep stravaExchangeCode excluded from App Check enforcement until the handoff is proven; then test missing/invalid/valid App Check plus encoded, case, and trailing-slash callback variants.

Dependencies and gates:

  • A follows SEC-001 and the AUTH-003 capability boundary.
  • B follows A and requires named owner review for provider configuration plus IAM/encryption policy.
  • C follows SAFETY-001 — Preserve callbacks and fail closed on local Firebase isolation #99. ABUSE-001A must defer stravaExchangeCode until C's safe handoff and callback regression evidence merge.
  • No test may use a real member token or the production Strava host.
  • None of these outcomes grants website membership, dues status, discounts, or admin access.

Split/claim rule: do not publish a duplicate OAUTH/Strava ticket. A and C are proposed implementation slices; B remains owner action because it contains provider/IAM/encryption decisions. If one pull request cannot safely review all three outcomes, keep #88 as the tracker, create and cross-link one atomic child first, then assign and post a timestamped CLAIMED marker for that child before editing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:authAuthentication and authorizationarea:stravaStrava integrationneeds-external-configRequires provider console or external configurationpriority:P0Launch blocker or urgent security risksize:MMedium multi-file issuestatus:proposedDesigned but dependencies or decisions remaintype:securitySecurity or privacy boundary

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions