3.7 KiB
Authentication Pattern Alignment
Review Summary
After reviewing BlogWriter, StoryWriter, and PodcastDashboard components, we've aligned content-planning authentication with the established pattern.
Established Pattern (BlogWriter/StoryWriter/PodcastDashboard)
-
ProtectedRoute handles authentication at route level
- Waits for Clerk to load (
isLoaded) - Checks if user is signed in (
isSignedIn) - Only renders children when authenticated
- Waits for Clerk to load (
-
Components don't check authentication
- Assume they're authenticated (ProtectedRoute ensures this)
- Make API calls directly without auth checks
- Rely on API client interceptors for token injection
-
API Client Interceptors handle token injection
- Automatically add
Authorization: Bearer <token>header - Use
authTokenGetterfunction set by TokenInstaller
- Automatically add
Changes Applied to Content Planning
1. Removed Component-Level Auth Checks ✅
Files Updated:
ContentStrategyTab.tsxContentPlanningDashboard.tsx
Before:
const { isLoaded, isSignedIn } = useAuth();
useEffect(() => {
if (!isLoaded) return;
if (!isSignedIn) return;
loadInitialData();
}, [isLoaded, isSignedIn]);
After:
// ProtectedRoute ensures user is authenticated before component renders
useEffect(() => {
loadInitialData();
}, []);
2. Enhanced API Client Interceptor ✅
File Updated:
client.ts
Changes:
- Reject requests if
authTokenGetteris not set (instead of just warning) - This prevents 401 errors from requests made before authentication is ready
- Matches the pattern where ProtectedRoute ensures auth is ready before components render
Before:
if (!authTokenGetter) {
console.warn('⚠️ authTokenGetter not set - request may fail');
// Request proceeds anyway → 401 error
}
After:
if (!authTokenGetter) {
console.error('❌ authTokenGetter not set - rejecting request');
return Promise.reject(new Error('Authentication not ready...'));
}
3. Removed Redundant API Service Checks ✅
File Updated:
contentPlanningApi.ts
Changes:
- Removed manual auth checks from
getStrategies()method - Rely on API client interceptor to handle authentication
- Matches pattern used by
blogWriterApiandstoryWriterApi
4. EventSource Authentication Support ✅
Files Updated:
contentPlanningApi.ts(frontend)streaming_endpoints.py(backend)
Changes:
- EventSource doesn't support custom headers, so tokens are passed as query parameters
- Backend uses
get_current_user_with_query_tokento accept tokens from query params - This is the standard pattern for SSE endpoints that require authentication
Authentication Flow (Aligned Pattern)
- User navigates to
/content-planning - ProtectedRoute checks:
- Waits for Clerk to load (
isLoaded) - Checks if user is signed in (
isSignedIn) - Only renders
ContentPlanningDashboardwhen authenticated
- Waits for Clerk to load (
- Component renders and makes API calls
- API Client Interceptor:
- Checks if
authTokenGetteris set (should be, since ProtectedRoute passed) - Gets token from Clerk
- Adds
Authorization: Bearer <token>header
- Checks if
- Backend validates token and processes request
Benefits
✅ Consistent Pattern - Matches BlogWriter/StoryWriter/PodcastDashboard ✅ Simpler Components - No redundant auth checks ✅ Better Error Handling - Interceptor rejects requests if auth isn't ready ✅ ProtectedRoute Guarantee - Components can assume authentication is ready ✅ EventSource Support - Streaming endpoints work with query parameter tokens
Status: ✅ ALIGNED
Content planning now follows the same authentication pattern as other components in the codebase.