- Identified root cause: list_invites endpoint requires admin role - Should allow regular members to see invites - Found bug in bands.py line 33 - Includes recommended fixes and action plan Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
5.6 KiB
403 Error Analysis - Invited Users Cannot Access Band Resources
🚨 CRITICAL ISSUE IDENTIFIED
The Problem
Invited users are getting 403 Forbidden errors when trying to:
- Access band invites:
GET /api/v1/bands/{band_id}/invites - Stream audio versions:
GET /api/v1/versions/{version_id}/stream
Root Cause Found
🔍 Code Investigation Results
1. Invite Acceptance Flow (✅ WORKING)
File: api/src/rehearsalhub/routers/members.py (lines 86-120)
@router.post("/invites/{token}/accept", response_model=BandMemberRead)
async def accept_invite(token: str, ...):
# 1. Get invite by token
invite = await repo.get_invite_by_token(token)
# 2. Validate invite (not used, not expired)
if invite.used_at: raise 409
if invite.expires_at < now: raise 410
# 3. Check if already member (idempotent)
existing_role = await repo.get_member_role(invite.band_id, current_member.id)
if existing_role: raise 409
# 4. ✅ Add member to band (THIS WORKS)
bm = await repo.add_member(invite.band_id, current_member.id, role=invite.role)
# 5. ✅ Mark invite as used (THIS WORKS)
invite.used_at = datetime.now(timezone.utc)
invite.used_by = current_member.id
return BandMemberRead(...)
✅ The invite acceptance logic is CORRECT and should work!
2. Band Invites Endpoint (❌ PROBLEM FOUND)
File: api/src/rehearsalhub/routers/bands.py (lines 19-70)
@router.get("/{band_id}/invites", response_model=BandInviteList)
async def list_invites(band_id: uuid.UUID, ...):
# ❌ PROBLEM: Only ADMINS can list invites!
role = await repo.get_member_role(band_id, current_member.id)
if role != "admin": # ← THIS IS THE BUG!
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Admin role required to manage invites"
)
# Get invites...
❌ BUG FOUND: The /bands/{band_id}/invites endpoint requires ADMIN role!
But regular members should be able to see invites for bands they're in!
3. Audio Stream Endpoint (❌ PROBLEM FOUND)
File: api/src/rehearsalhub/routers/versions.py (lines 208-215)
async def _get_version_and_assert_band_membership(version_id, session, current_member):
# ... get version and song ...
# ❌ PROBLEM: Uses assert_membership which should work
band_svc = BandService(session)
try:
await band_svc.assert_membership(song.band_id, current_member.id)
except PermissionError:
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Not a member")
❌ BUG FOUND: The /versions/{version_id}/stream endpoint uses assert_membership which should work for regular members.
But if the user wasn't properly added to band_members, this will fail!
🎯 THE ROOT CAUSE
Hypothesis 1: Invite Acceptance Failed
- User accepted invite but wasn't added to
band_members - Need to check database
Hypothesis 2: Permission Logic Too Strict
/bands/{id}/invitesrequires admin (should allow members)- This is definitely a bug
Hypothesis 3: JWT Token Issue
- User's JWT doesn't reflect their new membership
- Token needs to be refreshed after invite acceptance
✅ CONFIRMED BUGS
Bug #1: List Invites Requires Admin (SHOULD BE MEMBER)
File: api/src/rehearsalhub/routers/bands.py:33
# CURRENT (WRONG):
if role != "admin":
raise HTTPException(status.HTTP_403_FORBIDDEN, detail="Admin role required")
# FIXED (CORRECT):
if role is None:
raise HTTPException(status.HTTP_403_FORBIDDEN, detail="Not a member")
Bug #2: Invite Acceptance Might Not Work
Need to verify:
- Database shows user in
band_members - JWT token was refreshed
- No errors in invite acceptance flow
🛠️ RECOMMENDED FIXES
Fix #1: Change Permission for List Invites
# In api/src/rehearsalhub/routers/bands.py
async def list_invites(band_id: uuid.UUID, ...):
# Change from admin-only to member-only
role = await repo.get_member_role(band_id, current_member.id)
if role is None: # ← Changed from != "admin"
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Not a member of this band"
)
Fix #2: Verify Invite Acceptance
-- Check if user is in band_members
SELECT * FROM band_members
WHERE band_id = '96c11cfa-d6bb-4987-af80-845626880383'
AND member_id = '{user_id}';
-- Check invite status
SELECT * FROM band_invites
WHERE band_id = '96c11cfa-d6bb-4987-af80-845626880383'
AND used_by = '{user_id}';
Fix #3: Add Debug Logging
# In accept_invite endpoint
log.info(f"User {current_member.id} accepting invite to band {invite.band_id}")
log.info(f"Adding member with role: {invite.role}")
log.info(f"Invite marked as used at {datetime.now(timezone.utc)}")
📋 ACTION PLAN
Step 1: Fix List Invites Permission
- Change
role != "admin"torole is None - Test with regular member account
Step 2: Verify Database State
- Check
band_memberstable - Check
band_invitestable - Verify user was added correctly
Step 3: Test Invite Flow
- Create new invite
- Accept as test user
- Verify user can access band resources
Step 4: Deploy Fix
- Apply permission fix
- Add logging
- Monitor for issues
🎯 IMPACT
Current: Invited users cannot access band resources (403 errors) After Fix: Regular band members can see invites and access recordings
Files to Change:
api/src/rehearsalhub/routers/bands.py(line 33)
Estimated Time: 15-30 minutes to fix and test