Skip to content

fix(auth): allow unauthenticated user_id on /feed/for-you#804

Merged
dylanjeffers merged 1 commit into
mainfrom
fix/for-you-feed-unauth
May 13, 2026
Merged

fix(auth): allow unauthenticated user_id on /feed/for-you#804
dylanjeffers merged 1 commit into
mainfrom
fix/for-you-feed-unauth

Conversation

@dylanjeffers
Copy link
Copy Markdown
Contributor

Summary

The For You handler (v1_users_feed_for_you.go) treats:

  • path :userId as the personalization target
  • query user_id as a viewer hint, used only to decorate response fields like has_current_user_reposted / has_current_user_saved

It already calls tryGetAuthedWallet (optional), so the handler is fine with an unauthenticated request — the path :userId controls the personalization SQL, and the access-gated track filter falls through to "ungated only" when authedWallet is empty.

But the global authMiddleware returns 403 whenever user_id is set and the request isn't signed:

// auth_middleware.go:351
if myId != 0 && !pkceAuthed && !app.isAuthorizedRequest(c.Context(), myId, wallet) {
    return fiber.NewError(fiber.StatusForbidden,
        fmt.Sprintf("You are not authorized to make this request authedWallet=%s myId=%d", wallet, myId))
}

…so the call dies before reaching the handler. Symptom on the web RC: For You tab silently empty / 403 in network tab.

Fix

Exempt the /feed/for-you route from that strict check via strings.HasSuffix(c.Path(), "/feed/for-you"). The myId is still resolved (so viewer-relative fields populate when a user_id is supplied) — it's just not gated behind a wallet match.

What stays the same

  • Path :userId still controls what content is returned — caller can't impersonate a different user for personalization.
  • Access-gated tracks still filtered out when authedWallet is empty (handler's existing t.access_authorities predicate).
  • All other routes still get the strict 403.

Test plan

  • ✅ New test TestV1FeedForYou_UnauthenticatedViewerIdAllowed exercises the exemption with skipAuthCheck OFF (so the real auth path runs). Passes locally against the test DB.
  • ✅ Existing For You tests still pass (TestV1FeedForYou_Basic, TestV1FeedForYou_RequiresValidUserId, TestV1FeedForYou_ExcludesAlreadySavedTracks, etc.).
  • go build ./api/... / go vet ./api/... clean.
  • After merge: web RC /v1/users/{id}/feed/for-you?user_id={id} should return 200 instead of 403 — verifiable directly with curl.

🤖 Generated with Claude Code

The For You handler treats the path :userId as the personalization
target and the user_id query param as a viewer hint used only for
response decoration (has_current_user_reposted, etc.). It already calls
tryGetAuthedWallet (optional), so the handler is happy with an
unauthenticated request — but the global authMiddleware returns 403
whenever user_id is set and the request isn't signed, blocking the call
before it reaches the handler.

Exempt the /feed/for-you route from that strict check. The path :userId
still controls what content is returned and access-gated tracks are
still filtered out when authedWallet is empty, so the security shape is
unchanged for this read endpoint.

Adds TestV1FeedForYou_UnauthenticatedViewerIdAllowed which exercises
the exemption with skipAuthCheck OFF (so the real auth path runs).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dylanjeffers dylanjeffers merged commit e8194b7 into main May 13, 2026
4 checks passed
@dylanjeffers dylanjeffers deleted the fix/for-you-feed-unauth branch May 13, 2026 01:22
dylanjeffers added a commit that referenced this pull request May 13, 2026
## Summary

Retiring the dedicated For You feed endpoint. The clients are being
switched to use \`/v1/users/{id}/recommended-tracks\` instead — the same
endpoint that already powers the Explore page's For You section and
works fine in production. See companion PR: AudiusProject/apps#14301.

## Why

The custom \`/feed/for-you\` endpoint had repeated issues since it
shipped:

* **Auth gate bug** (fixed in #804) — global authMiddleware rejected
unsigned \`user_id\` requests, making the endpoint unreachable from the
web RC.
* **Perf** — even after #805 and #806 capped the \`my_saved_artists\`,
\`my_artist_affinity\`, and \`follow_set\` CTEs, EXPLAIN on prod showed
the \`similar_artists\` self-join still produced a 301M-row merge for
power users (and a fixed ~12s \`track_trending_scores\` scan for *every*
user due to a missing partial index). The endpoint never reliably
completed within Cloudflare's 100s upstream limit for power users.
* **Duplication** — the response shape (ranked track list for the
signed-in user) is already what \`/recommended-tracks\` returns. Two
endpoints solving the same problem isn't worth maintaining.

Consolidating on the working endpoint is simpler than continuing to
optimize the custom one.

## Removed

| File | What |
|---|---|
| \`api/v1_users_feed_for_you.go\` | Handler + the 200-row
candidate-pool SQL (4 candidate sources, similar_artists CF, diversity
pass) |
| \`api/v1_users_feed_for_you_test.go\` | 9 unit tests |
| \`api/server.go\` (1 line) | Route registration |
| \`api/auth_middleware.go\` (~10 lines) | The \`/feed/for-you\`
exemption from #804 — no longer needed |
| \`api/swagger/swagger-v1.yaml\` (~70 lines) | The endpoint's swagger
entry |

## Test plan

- ✅ \`go build ./api/...\` clean
- ✅ \`go vet ./api/...\` clean
- ✅ All remaining \`TestV1UsersFeed*\` / \`TestAuth*\` tests pass
locally
- After merge + deploy + AudiusProject/apps#14301 deploy: Feed → For You
tab on the web RC should show the same recommended tracks as Explore's
For You section.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant