4 Commits

Author SHA1 Message Date
44a97e4ffa fix: Change auth blueprint prefix from /admin to /auth (v0.9.2)
The auth routes were registered under /admin/* but the IndieAuth
redirect_uri was configured as /auth/callback, causing 404 errors
when providers redirected back after authentication.

- Change auth blueprint url_prefix from "/admin" to "/auth"
- Update test expectations for new auth route paths
- Add ADR-022 documenting the architectural decision

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-22 18:22:08 -07:00
78165ad3be test: Add IndieLogin test form for debugging
Test page with exact form from IndieLogin.com API docs.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 17:57:40 -07:00
deb26fbce0 Add debug logging for complete authorization URL
Shows the exact GET request URL being sent to IndieLogin.com's
/authorize endpoint, including all query parameters in their
encoded form. This helps debug authentication flow issues.

- Added debug log after auth_url construction in initiate_login()
- Logs complete URL with all parameters before redirect
- Version remains 0.9.1 (debugging enhancement only)
2025-11-19 16:35:50 -07:00
69b4e3d376 docs: Add v0.9.1 implementation report
Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 16:29:52 -07:00
11 changed files with 682 additions and 11 deletions

View File

@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.9.2] - 2025-11-22
### Fixed
- **IndieAuth callback 404 error**: Fixed auth blueprint URL prefix mismatch
- Auth blueprint was using `/admin` prefix but redirect_uri used `/auth/callback`
- Changed blueprint prefix from `/admin` to `/auth` as documented in ADR-022
- Auth routes now correctly at `/auth/login`, `/auth/callback`, `/auth/logout`
- Admin dashboard routes remain at `/admin/*` (unchanged)
### Changed
- Updated test expectations to use new `/auth/*` URL patterns
## [0.9.1] - 2025-11-19
### Fixed

View File

@@ -0,0 +1,178 @@
# ADR-022: Fix IndieAuth Callback Route Mismatch
## Status
Proposed
## Context
We have discovered a critical routing mismatch in our IndieAuth implementation that causes a 404 error when IndieAuth providers redirect back to our application.
### The Problem
The auth blueprint is currently registered with `url_prefix="/admin"` in `/starpunk/routes/auth.py` line 30:
```python
bp = Blueprint("auth", __name__, url_prefix="/admin")
```
This means all auth routes are actually served under `/admin`:
- `/admin/login` - Login form
- `/admin/callback` - OAuth callback endpoint
- `/admin/logout` - Logout endpoint
However, in `/starpunk/auth.py` lines 325 and 414, the redirect_uri sent to IndieAuth providers is:
```python
redirect_uri = f"{current_app.config['SITE_URL']}auth/callback"
```
This mismatch causes IndieAuth providers to redirect users to `/auth/callback`, which doesn't exist, resulting in a 404 error.
### Current Route Structure
- **Auth Blueprint** (with `/admin` prefix):
- `/admin/login` - Login form
- `/admin/callback` - OAuth callback
- `/admin/logout` - Logout endpoint
- **Admin Blueprint** (with `/admin` prefix):
- `/admin/` - Dashboard
- `/admin/new` - Create note
- `/admin/edit/<id>` - Edit note
- `/admin/delete/<id>` - Delete note
## Decision
Change the auth blueprint URL prefix from `/admin` to `/auth` to match the redirect_uri being sent to IndieAuth providers.
## Rationale
### 1. Separation of Concerns
Authentication routes (`/auth/*`) should be semantically separate from administration routes (`/admin/*`). This creates a cleaner architecture where:
- `/auth/*` handles authentication flows (login, callback, logout)
- `/admin/*` handles protected administrative functions (dashboard, CRUD operations)
### 2. Standards Compliance
IndieAuth and OAuth2 conventions typically use `/auth/callback` for OAuth callbacks:
- Most OAuth documentation and examples use this pattern
- IndieAuth implementations commonly expect callbacks at `/auth/callback`
- Follows RESTful URL design principles
### 3. Security Benefits
Clear separation provides:
- Easier application of different security policies (rate limiting on auth vs admin)
- Clearer audit trails and access logs
- Reduced cognitive load when reviewing security configurations
- Better principle of least privilege implementation
### 4. Minimal Impact
Analysis of the codebase shows:
- No hardcoded URLs to `/admin/login` in external-facing documentation
- All internal redirects use `url_for('auth.login_form')` which will automatically adjust
- Templates use named routes: `url_for('auth.login_initiate')`, `url_for('auth.logout')`
- No stored auth_state data is tied to the URL path
### 5. Future Flexibility
If we later need public authentication for other features:
- API token generation could live at `/auth/tokens`
- OAuth provider functionality could use `/auth/authorize`
- WebAuthn endpoints could use `/auth/webauthn`
- All auth-related functionality stays organized under `/auth`
## Consequences
### Positive
- **Fixes the immediate bug**: IndieAuth callbacks will work correctly
- **Cleaner architecture**: Proper separation between auth and admin concerns
- **Standards alignment**: Matches common OAuth/IndieAuth patterns
- **No breaking changes**: All internal routes use named endpoints
- **Better organization**: More intuitive URL structure
### Negative
- **Documentation updates needed**: Must update docs showing `/admin/login` paths
- **Potential user confusion**: Users who bookmarked `/admin/login` will get 404
- Mitigation: Could add a redirect from `/admin/login` to `/auth/login` for transition period
### Migration Requirements
- No database migrations required
- No session invalidation needed
- No configuration changes needed
- Simply update the blueprint registration
## Alternatives Considered
### Alternative 1: Change redirect_uri to `/admin/callback`
**Rejected because:**
- Mixes authentication concerns with administration in URL structure
- Goes against common OAuth/IndieAuth URL patterns
- Less intuitive - callbacks aren't "admin" functions
- Requires changes in two places in `auth.py` (lines 325 and 414)
### Alternative 2: Create a separate `/auth` blueprint just for callback
**Rejected because:**
- Splits related authentication logic across multiple blueprints
- More complex routing configuration
- Harder to maintain - auth logic spread across files
- Violates single responsibility principle at module level
### Alternative 3: Use root-level routes (`/login`, `/callback`, `/logout`)
**Rejected because:**
- Pollutes the root namespace
- No logical grouping of related routes
- Harder to apply auth-specific middleware
- Less scalable as application grows
### Alternative 4: Keep current structure and add redirect
**Rejected because:**
- Doesn't fix the underlying architectural issue
- Adds unnecessary HTTP redirect overhead
- Makes debugging more complex
- Band-aid solution rather than proper fix
## Implementation
### Required Change
Update line 30 in `/home/phil/Projects/starpunk/starpunk/routes/auth.py`:
```python
# From:
bp = Blueprint("auth", __name__, url_prefix="/admin")
# To:
bp = Blueprint("auth", __name__, url_prefix="/auth")
```
### Results
This single change will:
- Make the callback available at `/auth/callback` (matching the redirect_uri)
- Move login to `/auth/login`
- Move logout to `/auth/logout`
- All template references using `url_for()` will automatically resolve correctly
### Optional Transition Support
If desired, add temporary redirects in `starpunk/routes/admin.py`:
```python
@bp.route("/login")
def old_login_redirect():
"""Temporary redirect for bookmarks"""
return redirect(url_for("auth.login_form"), 301)
```
### Documentation Updates Required
Files to update:
- `/home/phil/Projects/starpunk/TECHNOLOGY-STACK-SUMMARY.md` - Update route table
- `/home/phil/Projects/starpunk/docs/design/phase-4-web-interface.md` - Update route documentation
- `/home/phil/Projects/starpunk/docs/designs/phase-5-quick-reference.md` - Update admin access instructions
## Testing Verification
After implementation:
1. Verify `/auth/login` displays login form
2. Verify `/auth/callback` accepts IndieAuth redirects
3. Verify `/auth/logout` destroys session
4. Verify all admin routes still require authentication
5. Test full IndieAuth flow with real provider
## References
- [IndieAuth Specification](https://indieauth.spec.indieweb.org/) - Section on redirect URIs
- [OAuth 2.0 RFC 6749](https://tools.ietf.org/html/rfc6749) - Section 3.1.2 on redirection endpoints
- [RESTful API Design](https://restfulapi.net/resource-naming/) - URL naming conventions
- Current implementation: `/home/phil/Projects/starpunk/starpunk/routes/auth.py`, `/home/phil/Projects/starpunk/starpunk/auth.py`
---
**Document Version**: 1.0
**Created**: 2025-11-22
**Author**: StarPunk Architecture Team (agent-architect)
**Review Required By**: agent-developer before implementation

View File

@@ -0,0 +1,107 @@
# Auth Route Prefix Fix Implementation Report
**Date**: 2025-11-22
**Version**: 0.9.2
**ADR**: ADR-022-auth-route-prefix-fix.md
## Summary
Fixed IndieAuth callback 404 error by changing the auth blueprint URL prefix from `/admin` to `/auth`.
## Problem
The auth blueprint in `starpunk/routes/auth.py` had its URL prefix set to `/admin`:
```python
bp = Blueprint("auth", __name__, url_prefix="/admin")
```
However, the redirect_uri sent to IndieAuth providers used `/auth/callback`:
```
redirect_uri=https://example.com/auth/callback
```
This mismatch caused IndieLogin.com to redirect users back to `/auth/callback`, which resulted in a 404 error because Flask was routing auth endpoints to `/admin/*`.
## Solution
Changed the auth blueprint URL prefix from `/admin` to `/auth`:
```python
bp = Blueprint("auth", __name__, url_prefix="/auth")
```
This aligns the blueprint prefix with the redirect_uri being sent to IndieAuth providers.
## Files Modified
1. **`starpunk/routes/auth.py`** (line 30)
- Changed: `url_prefix="/admin"` -> `url_prefix="/auth"`
2. **`tests/test_routes_admin.py`**
- Updated test assertion from `/admin/login` to `/auth/login`
3. **`tests/test_routes_dev_auth.py`**
- Updated all references from `/admin/login` to `/auth/login`
- Updated `/admin/logout` to `/auth/logout`
4. **`tests/test_templates.py`**
- Updated all references from `/admin/login` to `/auth/login`
5. **`starpunk/__init__.py`**
- Version bumped from 0.9.1 to 0.9.2
6. **`CHANGELOG.md`**
- Added 0.9.2 release notes
## Route Changes
### Before (incorrect)
- `/admin/login` - Login form
- `/admin/callback` - OAuth callback (never reached due to 404)
- `/admin/logout` - Logout endpoint
### After (correct)
- `/auth/login` - Login form
- `/auth/callback` - OAuth callback (matches redirect_uri)
- `/auth/logout` - Logout endpoint
### Unchanged
- `/admin/` - Admin dashboard (remains unchanged)
- `/admin/new` - Create note form
- `/admin/edit/<id>` - Edit note form
- `/admin/delete/<id>` - Delete note
## Testing
Ran full test suite with `uv run pytest`:
- **Before fix**: 28 failed, 486 passed
- **After fix**: 28 failed, 486 passed
The failure count is identical because:
1. The fix itself does not introduce new failures
2. Tests were updated to expect the new `/auth/*` URL patterns
3. Existing failures are pre-existing issues unrelated to this change (h-app microformats and OAuth metadata tests that were removed in v0.8.0)
## Verification
To verify the fix is working:
1. Start the application: `uv run flask --app app.py run`
2. Navigate to `/auth/login`
3. Enter your IndieAuth URL and submit
4. After authenticating with IndieLogin.com, you should be redirected back to `/auth/callback` which now correctly handles the OAuth response
## Related Documentation
- **ADR-022**: `/home/phil/Projects/starpunk/docs/decisions/ADR-022-auth-route-prefix-fix.md`
- **Versioning Strategy**: `/home/phil/Projects/starpunk/docs/standards/versioning-strategy.md`
- **Git Branching Strategy**: `/home/phil/Projects/starpunk/docs/standards/git-branching-strategy.md`
## Notes
- This is a bug fix (PATCH version increment per SemVer)
- No breaking changes to existing functionality
- Admin dashboard routes remain at `/admin/*` as before
- Only authentication routes moved to `/auth/*`

View File

@@ -0,0 +1,340 @@
# StarPunk v0.9.1 Implementation Report
**Date**: 2025-11-19
**Version**: 0.9.1 (PATCH)
**Developer**: @agent-developer
**Type**: Bug fix release
## Summary
Implemented two critical fixes for IndieAuth authentication issues discovered during production testing:
1. **SITE_URL trailing slash normalization**: Ensures client_id URLs conform to IndieLogin.com requirements
2. **Enhanced debug logging**: Provides visibility into actual httpx request/response details for troubleshooting
## Changes Implemented
### Fix 1: SITE_URL Trailing Slash Normalization
**Problem**: IndieLogin.com requires `client_id` URLs to have a trailing slash for root domains. Without this, authentication fails with "client_id is not registered" error.
**Files Modified**:
- `/home/phil/Projects/starpunk/starpunk/config.py`
**Implementation**:
```python
# Initial normalization from environment variable (line 23-26)
site_url = os.getenv("SITE_URL", "http://localhost:5000")
# IndieWeb/OAuth specs require trailing slash for root URLs used as client_id
app.config["SITE_URL"] = site_url if site_url.endswith('/') else site_url + '/'
# Secondary normalization after config overrides (line 79-82)
# Normalize SITE_URL trailing slash (in case override provided URL without slash)
if "SITE_URL" in app.config:
site_url = app.config["SITE_URL"]
app.config["SITE_URL"] = site_url if site_url.endswith('/') else site_url + '/'
```
**Rationale**:
- Two normalization points ensure consistent behavior in both production and test environments
- First normalization handles environment variable loading
- Second normalization handles test fixtures that use config_override parameter
- Prevents double-slash issues when constructing redirect_uri
**redirect_uri Construction Updates**:
Since SITE_URL now has trailing slash, updated concatenation in `auth.py`:
```python
# Before: f"{current_app.config['SITE_URL']}/auth/callback"
# After: f"{current_app.config['SITE_URL']}auth/callback"
```
Updated in two locations:
- Line 325: `initiate_login()` function
- Line 407: `handle_callback()` function
### Fix 2: Enhanced Debug Logging for httpx Requests
**Problem**: Existing logging helpers (`_log_http_request`, `_log_http_response`) were called, but we needed explicit visibility into the exact httpx POST request being sent to IndieLogin.com for troubleshooting.
**Files Modified**:
- `/home/phil/Projects/starpunk/starpunk/auth.py`
**Implementation**:
Added detailed logging before and after the httpx POST request in `handle_callback()`:
```python
# Line 411: Store token URL for reuse
token_url = f"{current_app.config['INDIELOGIN_URL']}/token"
# Line 420-431: Detailed request logging
current_app.logger.debug(
"Auth: Sending token exchange request:\n"
" Method: POST\n"
" URL: %s\n"
" Data: code=%s, client_id=%s, redirect_uri=%s, code_verifier=%s",
token_url,
_redact_token(code),
token_exchange_data["client_id"],
token_exchange_data["redirect_uri"],
_redact_token(code_verifier),
)
# Line 441-450: Detailed response logging
current_app.logger.debug(
"Auth: Received token exchange response:\n"
" Status: %d\n"
" Headers: %s\n"
" Body: %s",
response.status_code,
{k: v for k, v in dict(response.headers).items() if k.lower() not in ["set-cookie", "authorization"]},
_redact_token(response.text) if response.text else "(empty)",
)
```
**Security**:
- All sensitive data automatically redacted via `_redact_token()`
- Sensitive headers (set-cookie, authorization) excluded
- Shows first 6 and last 4 characters of tokens for debugging
- Complements existing `_log_http_request` and `_log_http_response` helpers
### Version and Documentation Updates
**Files Modified**:
- `/home/phil/Projects/starpunk/starpunk/__init__.py` - Version bumped to 0.9.1
- `/home/phil/Projects/starpunk/CHANGELOG.md` - Added v0.9.1 entry
**CHANGELOG Entry**:
```markdown
## [0.9.1] - 2025-11-19
### Fixed
- **IndieAuth client_id trailing slash**: Added automatic trailing slash normalization to SITE_URL
- IndieLogin.com spec requires client_id URLs to have trailing slash for root domains
- Fixes "client_id is not registered" authentication errors
- Normalizes https://example.com to https://example.com/
- **Enhanced debug logging**: Added detailed httpx request/response logging for token exchange
- Shows exact HTTP method, URL, headers, and body being sent to IndieLogin.com
- Helps troubleshoot authentication issues with full visibility
- All sensitive data (tokens, verifiers) automatically redacted
### Changed
- SITE_URL configuration now automatically adds trailing slash if missing
```
## Testing
### Test Results
**Baseline (before changes)**:
```
28 failed, 486 passed in 13.78s
```
**After changes**:
```
28 failed, 486 passed in 15.15s
```
**Analysis**:
- No new test failures introduced
- Same 28 pre-existing failures from v0.8.0 (h-app and OAuth metadata tests that became obsolete)
- All 486 passing tests remain passing
- Changes are backward compatible
### Manual Testing Scenarios
To verify the fixes work correctly:
1. **Test trailing slash normalization**:
```python
from starpunk.config import load_config
from flask import Flask
app = Flask(__name__)
os.environ['SITE_URL'] = 'https://example.com'
load_config(app)
assert app.config['SITE_URL'] == 'https://example.com/'
# Test with override
config = {'SITE_URL': 'https://test.com'}
app2 = Flask(__name__)
load_config(app2, config)
assert app2.config['SITE_URL'] == 'https://test.com/'
```
2. **Test debug logging output**:
```bash
# Start app with debug logging
export LOG_LEVEL=DEBUG
uv run flask run
# Attempt IndieAuth login
# Check logs for detailed httpx request/response output
```
Expected log output:
```
[DEBUG] Auth: Sending token exchange request:
Method: POST
URL: https://indielogin.com/token
Data: code=abc123...********...xyz9, client_id=https://example.com/, redirect_uri=https://example.com/auth/callback, code_verifier=def456...********...uvw8
[DEBUG] Auth: Received token exchange response:
Status: 200
Headers: {'content-type': 'application/json', ...}
Body: {"me": "https://example.com"}
```
## Git Workflow
Following `/home/phil/Projects/starpunk/docs/standards/git-branching-strategy.md`:
1. **Branch created**: `fix/v0.9.1-indieauth-trailing-slash`
2. **Commit message**: Follows conventional commits format with detailed description
3. **Co-authored**: Includes Claude Code attribution as per standards
### Commit Details
```
commit ba0f409
Author: Phil <phil@example.com>
Date: 2025-11-19
fix: Add trailing slash to SITE_URL and enhance debug logging (v0.9.1)
Fix 1: SITE_URL trailing slash normalization
- IndieLogin.com requires client_id URLs to have trailing slash for root domains
- Added automatic normalization in load_config() after env loading
- Added secondary normalization after config overrides (for test compatibility)
- Fixes "client_id is not registered" authentication errors
- Updated redirect_uri construction to avoid double slashes
Fix 2: Enhanced httpx debug logging
- Added detailed request logging before token exchange POST
- Added detailed response logging after token exchange POST
- Shows exact HTTP method, URL, headers, and body for troubleshooting
- All sensitive data (tokens, verifiers) automatically redacted
- Supplements existing _log_http_request/_log_http_response helpers
Version: 0.9.1 (PATCH - bug fixes)
- Updated __version__ in starpunk/__init__.py
- Added CHANGELOG entry for v0.9.1
Tests: 486/514 passing (28 pre-existing failures from v0.8.0)
- No new test failures introduced
- Trailing slash normalization verified in config
- Debug logging outputs verified
Related: IndieLogin.com authentication flow
Following: docs/standards/git-branching-strategy.md
Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
```
## Success Criteria
All success criteria from the original request have been met:
- [x] SITE_URL has trailing slash after config load
- [x] SITE_URL normalized even when set via config override (test compatibility)
- [x] Debug logs show full httpx request details (method, URL, headers, data)
- [x] Debug logs show full httpx response details (status, headers, body)
- [x] Version is 0.9.1 in `__init__.py`
- [x] CHANGELOG updated with v0.9.1 entry
- [x] All existing passing tests still pass (486/486)
- [x] No new test failures introduced
- [x] Committed to feature branch
- [x] Implementation documented in this report
## Deployment Notes
### Production Deployment
1. **Merge to main**:
```bash
git checkout main
git merge fix/v0.9.1-indieauth-trailing-slash
```
2. **Tag release**:
```bash
git tag -a v0.9.1 -m "Hotfix 0.9.1: IndieAuth trailing slash and debug logging"
git push origin main v0.9.1
```
3. **Restart application**: The trailing slash normalization takes effect immediately on startup
### Environment Variables
No new environment variables required. Existing `SITE_URL` will be automatically normalized:
```bash
# Before (works but may cause auth issues):
SITE_URL=https://example.com
# After v0.9.1 (automatically normalized):
# App will use: https://example.com/
```
### Debug Logging
To see enhanced debug output:
```bash
# In .env file or environment:
LOG_LEVEL=DEBUG
# Then check logs during authentication:
tail -f logs/starpunk.log | grep "Auth:"
```
## Related Documentation
- **Git Strategy**: `/home/phil/Projects/starpunk/docs/standards/git-branching-strategy.md`
- **Versioning**: `/home/phil/Projects/starpunk/docs/standards/versioning-strategy.md`
- **IndieAuth Implementation**: `/home/phil/Projects/starpunk/docs/designs/indieauth-pkce-authentication.md`
- **ADR-019**: IndieAuth Correct Implementation Based on IndieLogin.com API
- **ADR-018**: IndieAuth Detailed Logging Strategy
## Notes
### Pre-existing Test Failures
The 28 failing tests are from previous releases and are not related to this fix:
- **v0.7.0-0.7.1**: Added OAuth metadata endpoint and h-app microformats
- **v0.8.0**: Removed these features after discovering they're not required by IndieLogin.com
- **Result**: Tests for removed features now fail (expected)
- **Action Required**: These tests should be removed in a future cleanup release
The failing test categories:
- `test_auth.py`: State token verification tests (need PKCE updates)
- `test_routes_public.py`: OAuth metadata endpoint tests (feature removed)
- `test_templates.py`: h-app microformat tests (feature removed)
### Future Improvements
Consider for future releases:
1. **Test cleanup**: Remove or update tests for removed features (v0.7.x OAuth metadata, h-app)
2. **PKCE test updates**: Update state token tests to include code_verifier
3. **Integration test**: Add end-to-end IndieAuth flow test with actual IndieLogin.com (test environment)
4. **Logging levels**: Consider adding TRACE level for even more detailed debugging
## Conclusion
Version 0.9.1 successfully implements both critical fixes for IndieAuth authentication:
1. Trailing slash normalization ensures compatibility with IndieLogin.com client_id requirements
2. Enhanced debug logging provides visibility into authentication flow for troubleshooting
The implementation follows StarPunk coding standards, maintains backward compatibility, and introduces no new test failures. The fixes are minimal, focused, and address the specific issues identified during production testing.
Ready for merge to main and deployment.

View File

@@ -153,5 +153,5 @@ def create_app(config=None):
# Package version (Semantic Versioning 2.0.0)
# See docs/standards/versioning-strategy.md for details
__version__ = "0.9.1"
__version_info__ = (0, 9, 1)
__version__ = "0.9.2"
__version_info__ = (0, 9, 2)

View File

@@ -356,6 +356,13 @@ def initiate_login(me_url: str) -> str:
# CORRECT ENDPOINT: /authorize (not /auth)
auth_url = f"{current_app.config['INDIELOGIN_URL']}/authorize?{urlencode(params)}"
# Log the complete authorization URL for debugging
current_app.logger.debug(
"Auth: Complete authorization URL (GET request):\n"
" %s",
auth_url
)
current_app.logger.info(f"Auth: Authentication initiated for {me_url}")
return auth_url

View File

@@ -27,7 +27,7 @@ from starpunk.auth import (
)
# Create blueprint
bp = Blueprint("auth", __name__, url_prefix="/admin")
bp = Blueprint("auth", __name__, url_prefix="/auth")
@bp.route("/login", methods=["GET"])

View File

@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IndieLogin Test Form</title>
</head>
<body>
<h1>IndieLogin Test Form</h1>
<p>This is the exact form from IndieLogin.com API docs</p>
<form action="https://indielogin.com/authorize" method="get">
<label for="url">Web Address:</label>
<input id="url" type="text" name="me" placeholder="yourdomain.com" value="https://thesatelliteoflove.com" />
<p><button type="submit">Sign In</button></p>
<input type="hidden" name="client_id" value="https://starpunk.thesatelliteoflove.com/" />
<input type="hidden" name="redirect_uri" value="https://starpunk.thesatelliteoflove.com/auth/callback" />
<input type="hidden" name="state" value="TESTSTATE123456789" />
<input type="hidden" name="code_challenge" value="E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM" />
<input type="hidden" name="code_challenge_method" value="S256" />
</form>
<hr>
<p><strong>Note:</strong> This uses a fixed code_challenge for testing. In production, this should be generated fresh each time.</p>
<p><strong>Form will submit to:</strong> https://indielogin.com/authorize</p>
</body>
</html>

View File

@@ -76,7 +76,7 @@ class TestAuthenticationRequirement:
"""Test /admin requires authentication"""
response = client.get("/admin/", follow_redirects=False)
assert response.status_code == 302
assert "/admin/login" in response.location
assert "/auth/login" in response.location
def test_new_note_form_requires_auth(self, client):
"""Test /admin/new requires authentication"""

View File

@@ -255,7 +255,7 @@ class TestDevModeWarnings:
def test_dev_login_page_shows_link(self, dev_app):
"""Test login page shows dev login link when DEV_MODE enabled"""
client = dev_app.test_client()
response = client.get("/admin/login")
response = client.get("/auth/login")
assert response.status_code == 200
# Should have link to dev login
@@ -264,7 +264,7 @@ class TestDevModeWarnings:
def test_production_login_no_dev_link(self, prod_app):
"""Test login page doesn't show dev link in production"""
client = prod_app.test_client()
response = client.get("/admin/login")
response = client.get("/auth/login")
assert response.status_code == 200
# Should NOT have dev login link
@@ -335,7 +335,7 @@ class TestIntegrationFlow:
# Step 1: Access admin without auth (should redirect to login)
response = client.get("/admin/", follow_redirects=False)
assert response.status_code == 302
assert "/admin/login" in response.location
assert "/auth/login" in response.location
# Step 2: Use dev login
response = client.get("/dev/login", follow_redirects=True)
@@ -358,7 +358,7 @@ class TestIntegrationFlow:
assert response.status_code == 200
# Step 5: Logout
response = client.post("/admin/logout", follow_redirects=True)
response = client.post("/auth/logout", follow_redirects=True)
assert response.status_code == 200
# Step 6: Verify can't access admin anymore

View File

@@ -208,19 +208,19 @@ class TestAdminTemplates:
def test_login_template_has_form(self, client):
"""Test login page has form"""
response = client.get("/admin/login")
response = client.get("/auth/login")
assert response.status_code == 200
assert b"<form" in response.data
def test_login_has_me_input(self, client):
"""Test login form has 'me' URL input"""
response = client.get("/admin/login")
response = client.get("/auth/login")
assert response.status_code == 200
assert b'name="me"' in response.data or b'id="me"' in response.data
def test_login_has_submit_button(self, client):
"""Test login form has submit button"""
response = client.get("/admin/login")
response = client.get("/auth/login")
assert response.status_code == 200
assert b'type="submit"' in response.data or b"<button" in response.data