# Implementation Guide: Auth Redirect Loop Fix

**Date**: 2025-11-18
**Related**: auth-redirect-loop-diagnosis.md
**Assignee**: Developer Agent
**Priority**: CRITICAL

## Quick Summary

Change all authentication cookie references from `"session"` to `"starpunk_session"` to avoid collision with Flask's server-side session mechanism.

**Estimated Time**: 30 minutes
**Files to Change**: 5 production files + test files

## Root Cause (Brief)

Flask's `session` object (used by `flash()` and `session["next"]`) writes to a cookie named `session`. StarPunk's auth also uses a cookie named `session`. This creates a collision where Flask overwrites the auth token, causing the redirect loop.

**Solution**: Rename StarPunk's auth cookie to `starpunk_session`.

## Implementation Checklist

### Phase 1: Production Code Changes

#### 1. `/home/phil/Projects/starpunk/starpunk/routes/dev_auth.py`

**Line 75** - Change cookie name when setting:

```python
# OLD (Line 74-81):
response.set_cookie(
    "session",
    session_token,
    httponly=True,
    secure=False,
    samesite="Lax",
    max_age=30 * 24 * 60 * 60,
)

# NEW:
response.set_cookie(
    "starpunk_session",  # ← CHANGED
    session_token,
    httponly=True,
    secure=False,
    samesite="Lax",
    max_age=30 * 24 * 60 * 60,
)
```

#### 2. `/home/phil/Projects/starpunk/starpunk/routes/auth.py`

**Line 47** - Change cookie read in login form check:

```python
# OLD:
session_token = request.cookies.get("session")

# NEW:
session_token = request.cookies.get("starpunk_session")
```

**Line 121** - Change cookie name when setting after IndieAuth callback:

```python
# OLD (Lines 120-127):
response.set_cookie(
    "session",
    session_token,
    httponly=True,
    secure=secure,
    samesite="Lax",
    max_age=30 * 24 * 60 * 60,
)

# NEW:
response.set_cookie(
    "starpunk_session",  # ← CHANGED
    session_token,
    httponly=True,
    secure=secure,
    samesite="Lax",
    max_age=30 * 24 * 60 * 60,
)
```

**Line 167** - Change cookie read in logout:

```python
# OLD:
session_token = request.cookies.get("session")

# NEW:
session_token = request.cookies.get("starpunk_session")
```

**Line 178** - Change cookie delete in logout:

```python
# OLD:
response.delete_cookie("session")

# NEW:
response.delete_cookie("starpunk_session")
```

#### 3. `/home/phil/Projects/starpunk/starpunk/auth.py`

**Line 390** - Change cookie read in `@require_auth` decorator:

```python
# OLD:
session_token = request.cookies.get("session")

# NEW:
session_token = request.cookies.get("starpunk_session")
```

### Phase 2: Test Code Changes

#### 4. `/home/phil/Projects/starpunk/tests/test_routes_admin.py`

**Line 54** - Change test cookie name:

```python
# OLD:
client.set_cookie("session", session_token)

# NEW:
client.set_cookie("starpunk_session", session_token)
```

#### 5. `/home/phil/Projects/starpunk/tests/test_templates.py`

**Lines 234, 247, 259, 272** - Change all test cookie names:

```python
# OLD (appears 4 times):
client.set_cookie("session", token)

# NEW (all 4 instances):
client.set_cookie("starpunk_session", token)
```

### Phase 3: Documentation Updates

Update the following documentation files to reflect the new cookie name:

1. `/home/phil/Projects/starpunk/docs/decisions/ADR-011-development-authentication-mechanism.md` (Line 112)
2. `/home/phil/Projects/starpunk/docs/decisions/ADR-005-indielogin-authentication.md` (Line 204)
3. `/home/phil/Projects/starpunk/docs/design/phase-4-quick-reference.md` (Line 460)
4. `/home/phil/Projects/starpunk/docs/design/phase-4-web-interface.md` (Lines 298, 522)
5. `/home/phil/Projects/starpunk/docs/design/phase-3-authentication-implementation.md` (Line 313)

**Note**: These are documentation files, so changes are for accuracy but not critical for functionality.

## Complete File Change Summary

### Production Code (5 changes across 3 files)

| File | Line | Change Type | Old Value | New Value |
|------|------|-------------|-----------|-----------|
| `starpunk/routes/dev_auth.py` | 75 | set_cookie name | `"session"` | `"starpunk_session"` |
| `starpunk/routes/auth.py` | 47 | cookies.get | `"session"` | `"starpunk_session"` |
| `starpunk/routes/auth.py` | 121 | set_cookie name | `"session"` | `"starpunk_session"` |
| `starpunk/routes/auth.py` | 167 | cookies.get | `"session"` | `"starpunk_session"` |
| `starpunk/routes/auth.py` | 178 | delete_cookie | `"session"` | `"starpunk_session"` |
| `starpunk/auth.py` | 390 | cookies.get | `"session"` | `"starpunk_session"` |

### Test Code (5 changes across 2 files)

| File | Line(s) | Change Type |
|------|---------|-------------|
| `tests/test_routes_admin.py` | 54 | client.set_cookie |
| `tests/test_templates.py` | 234, 247, 259, 272 | client.set_cookie (4 instances) |

## Search and Replace Strategy

**IMPORTANT**: Do NOT use global search and replace. Many documentation files reference the word "session" legitimately.

### Recommended Approach

Use targeted search patterns:

```bash
# Find all set_cookie calls with "session"
grep -n 'set_cookie.*"session"' starpunk/**/*.py tests/**/*.py

# Find all cookies.get calls with "session"
grep -n 'cookies\.get.*"session"' starpunk/**/*.py tests/**/*.py

# Find all delete_cookie calls with "session"
grep -n 'delete_cookie.*"session"' starpunk/**/*.py tests/**/*.py
```

Then manually review and update each instance.

## Testing Plan

### Automated Tests

After making changes, run the test suite:

```bash
uv run pytest tests/ -v
```

**Expected**: All existing tests should pass with the new cookie name.

### Manual Testing (CRITICAL)

#### Test 1: Dev Login Flow

```
1. Start server: uv run flask run
2. Open browser: http://localhost:5000/admin/
3. Expected: Redirect to /admin/login
4. Click "Dev Login" link (or visit http://localhost:5000/dev/login)
5. Expected: Redirect to /admin/ dashboard
6. Expected: See flash message "DEV MODE: Logged in without authentication"
7. Expected: Dashboard loads successfully (NO redirect loop)
```

**Success Criteria**:
- No redirect loop
- Flash message appears
- Dashboard displays

**Browser DevTools Check**:
```
Application → Cookies → http://localhost:5000
Should see:
- starpunk_session: {long-token-string}
- session: {flask-session-data} (for flash messages)
```

#### Test 2: Session Persistence

```
1. After successful login from Test 1
2. Click "New Note" in navigation
3. Expected: Form loads (no redirect to login)
4. Refresh page (F5)
5. Expected: Still authenticated, form still loads
```

**Success Criteria**:
- No authentication loss on navigation
- No authentication loss on refresh

#### Test 3: Logout

```
1. While authenticated, click "Logout" button
2. Expected: Redirect to homepage
3. Expected: Flash message "Logged out successfully"
4. Try to visit http://localhost:5000/admin/
5. Expected: Redirect to /admin/login
```

**Browser DevTools Check**:
```
Application → Cookies → http://localhost:5000
Should see:
- starpunk_session: (should be deleted)
- session: {may still exist for flash message}
```

**Success Criteria**:
- Cookie properly cleared
- Cannot access admin routes after logout
- Must login again to access admin

#### Test 4: IndieAuth Flow (if configured)

```
1. Logout if logged in
2. Visit /admin/login
3. Enter valid ADMIN_ME URL
4. Complete IndieAuth flow on indielogin.com
5. Expected: Redirect back to dashboard
6. Expected: starpunk_session cookie set
7. Expected: No redirect loop
```

**Success Criteria**:
- Full IndieAuth flow works
- Session persists after callback
- Flash message shows

## Post-Implementation

### 1. Version Bump

Update version to `0.5.1` (bugfix release):

```python
# In starpunk/config.py or wherever VERSION is defined
app.config["VERSION"] = "0.5.1"
```

Also update in:
- `pyproject.toml` (if version is defined there)
- `docs/CHANGELOG.md`

### 2. Changelog Entry

Add to `/home/phil/Projects/starpunk/docs/CHANGELOG.md`:

```markdown
## [0.5.1] - 2025-11-18

### Fixed
- **CRITICAL**: Fixed authentication redirect loop caused by cookie name collision between Flask's session and StarPunk's auth token
- Renamed authentication cookie from `session` to `starpunk_session` to avoid conflict with Flask's server-side session mechanism
- All authentication flows (dev login, IndieAuth, logout) now work correctly without redirect loops

### Changed
- Authentication cookie name changed from `session` to `starpunk_session` (breaking change for existing sessions - users will need to re-login)
```

### 3. Update Standards Document

Create or update `/home/phil/Projects/starpunk/docs/standards/cookie-naming-convention.md`:

```markdown
# Cookie Naming Convention

**Status**: ACTIVE
**Date**: 2025-11-18

## Standard

All StarPunk application cookies MUST use the `starpunk_` prefix to avoid conflicts with framework-reserved names.

## Reserved Names (DO NOT USE)

- `session` - Reserved for Flask server-side session
- `csrf_token` - Reserved for CSRF protection frameworks
- `remember_token` - Common auth framework name
- Any single-word generic names

## StarPunk Cookie Names

| Cookie Name | Purpose | Security Attributes |
|-------------|---------|---------------------|
| `starpunk_session` | Authentication session token | HttpOnly, Secure (prod), SameSite=Lax |

## Future Cookies

All future cookies must:
1. Use `starpunk_` prefix
2. Be documented in this table
3. Have explicit security attributes defined
4. Be reviewed for conflicts with framework conventions
```

### 4. Create Report

Create `/home/phil/Projects/starpunk/docs/reports/2025-11-18-auth-redirect-loop-fix.md`:

```markdown
# Auth Redirect Loop Fix - Implementation Report

**Date**: 2025-11-18
**Version**: 0.5.1
**Severity**: Critical Bug Fix

## Summary

Fixed authentication redirect loop in Phase 4 by renaming authentication cookie from `session` to `starpunk_session`.

## Root Cause

Cookie name collision between Flask's server-side session (used by flash messages) and StarPunk's authentication token.

## Implementation

- Changed 6 instances in production code
- Changed 5 instances in test code
- Updated 6 documentation files
- All tests passing
- Manual testing confirmed fix

## Testing

- Dev login flow: PASS
- Session persistence: PASS
- Logout flow: PASS
- IndieAuth flow: PASS (if applicable)

## Breaking Change

Existing authenticated users will be logged out and need to re-authenticate due to cookie name change.

## Prevention

Established cookie naming convention (starpunk_* prefix) to prevent future conflicts.

## Files Changed

[List all files modified]

## Commit

[Reference commit hash after git commit]
```

### 5. Git Commit

After all changes and testing:

```bash
# Stage all changes
git add starpunk/routes/dev_auth.py \
        starpunk/routes/auth.py \
        starpunk/auth.py \
        tests/test_routes_admin.py \
        tests/test_templates.py \
        docs/

# Commit with proper message
git commit -m "$(cat <<'EOF'
Fix critical auth redirect loop by renaming session cookie

BREAKING CHANGE: Authentication cookie renamed from 'session' to 'starpunk_session'

Root cause: Cookie name collision between Flask's server-side session
(used by flash messages) and StarPunk's authentication token caused
redirect loop between /dev/login and /admin/ routes.

Changes:
- Rename auth cookie to 'starpunk_session' in all routes
- Update all cookie read/write operations
- Update test suite with new cookie name
- Establish cookie naming convention (starpunk_* prefix)
- Update documentation to reflect changes

Impact:
- Existing authenticated users will be logged out
- Users must re-authenticate after upgrade

Testing:
- All automated tests passing
- Manual testing confirms fix:
  - Dev login flow works without redirect loop
  - Session persistence across requests
  - Logout properly clears cookie
  - Flash messages work correctly

Fixes: Phase 4 authentication redirect loop
Version: 0.5.1

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

Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)"
```

## Verification Checklist

Before marking this as complete:

- [ ] All 6 production code changes made
- [ ] All 5 test code changes made
- [ ] Test suite passes: `uv run pytest tests/ -v`
- [ ] Manual Test 1 (Dev Login) passes
- [ ] Manual Test 2 (Session Persistence) passes
- [ ] Manual Test 3 (Logout) passes
- [ ] Manual Test 4 (IndieAuth) passes or N/A
- [ ] Version bumped to 0.5.1
- [ ] CHANGELOG.md updated
- [ ] Cookie naming convention documented
- [ ] Implementation report created
- [ ] Git commit created with proper message
- [ ] No redirect loop observed in any test
- [ ] Flash messages still work

## Rollback Plan

If issues are discovered:

```bash
# Revert the commit
git revert HEAD

# Or reset if not pushed
git reset --hard HEAD~1
```

The old behavior will be restored, but the redirect loop will return.

## Support

If you encounter issues during implementation:

1. Check browser DevTools → Application → Cookies
2. Verify both `starpunk_session` and `session` cookies exist
3. Check Flask logs for session-related errors
4. Verify SECRET_KEY is set in config
5. Ensure all 6 production file changes were made correctly

## Architecture Notes

This fix establishes an important principle:

**Never use generic cookie names that conflict with framework conventions.**

Flask owns the `session` cookie namespace. We must respect framework boundaries and use our own namespace (`starpunk_*`).

This is now codified in `/docs/standards/cookie-naming-convention.md` for future reference.
