Spaces:
Sleeping
Sleeping
| # JWT Token Expiration Fix | |
| ## Problem | |
| Users are getting logged out too quickly. Token expired after ~9 hours instead of the expected 24 hours. | |
| **Error from logs:** | |
| ``` | |
| ERROR: 2025-11-18T05:38:46 - app.core.supabase_auth: Get user error: invalid JWT: unable to parse or verify signature, token has invalid claims: token is expired | |
| ``` | |
| ## Root Cause | |
| The JWT tokens are managed by **Supabase Auth**, not the backend `ACCESS_TOKEN_EXPIRE_MINUTES` setting. Supabase has its own JWT expiry configuration that overrides your backend setting. | |
| --- | |
| ## β WORKING SOLUTION: Automatic Token Refresh | |
| **Status:** β Implemented and tested | |
| **Requirements:** Supabase Free tier (no upgrade needed) | |
| **User Experience:** Users stay logged in for 30 days | |
| ### What Was Implemented | |
| 1. **Backend Changes:** | |
| - Modified `/api/v1/auth/login` to return `refresh_token` and `expires_in` | |
| - Created new `/api/v1/auth/refresh-token` endpoint with automatic token rotation | |
| - Added `refresh_session()` method to SupabaseAuthService | |
| 2. **How It Works:** | |
| - User logs in β receives access token (1 hour) + refresh token (30 days) | |
| - Frontend schedules auto-refresh 5 minutes before expiration | |
| - Token refreshes automatically in background | |
| - Users stay logged in seamlessly for up to 30 days | |
| 3. **Implementation Guide:** | |
| - See: [`docs/FRONTEND_TOKEN_REFRESH_GUIDE.md`](./FRONTEND_TOKEN_REFRESH_GUIDE.md) | |
| - Complete TypeScript/JavaScript code examples | |
| - React and Vue integration examples | |
| - Testing procedures | |
| **Why This Solution:** | |
| - β Works with Supabase Free tier | |
| - β No Pro plan upgrade required | |
| - β Better security (token rotation) | |
| - β Seamless user experience | |
| - β Industry best practice | |
| --- | |
| ## β Option 1: Configure Supabase JWT Expiry | |
| **Status:** β Not available on Supabase Free tier | |
| **Requirements:** Supabase Pro plan ($25/month) | |
| β οΈ **This option requires upgrading to Supabase Pro plan** | |
| **In your Supabase Dashboard:** | |
| 1. Go to **Settings** > **Auth** | |
| 2. Find **JWT Expiry** | |
| 3. Change from default (3600 seconds / 1 hour) to **86400 seconds (24 hours)** or longer | |
| 4. Save changes | |
| **Or via Supabase SQL:** | |
| ```sql | |
| -- Update JWT expiry to 7 days (604800 seconds) | |
| ALTER DATABASE postgres | |
| SET app.settings.jwt_exp = '604800'; | |
| ``` | |
| --- | |
| ## π Alternative Options (Reference Only) | |
| ### Option 2: Backend Token Configuration | |
| **Status:** β οΈ Limited effect (Supabase controls JWT expiry) | |
| **File: `src/app/config_settings.py`** | |
| You can extend the backend token setting, but this won't affect Supabase-managed JWTs: | |
| ```python | |
| # Change from: | |
| ACCESS_TOKEN_EXPIRE_MINUTES: int = 1440 # 24 hours | |
| # To: | |
| ACCESS_TOKEN_EXPIRE_MINUTES: int = 10080 # 7 days | |
| # Or: | |
| ACCESS_TOKEN_EXPIRE_MINUTES: int = 43200 # 30 days | |
| ``` | |
| **Note:** This only affects custom JWT tokens if you create them outside Supabase. Supabase tokens are controlled by Supabase Auth settings. | |
| --- | |
| ## π Additional Resources | |
| - **Implementation Guide:** [`docs/FRONTEND_TOKEN_REFRESH_GUIDE.md`](./FRONTEND_TOKEN_REFRESH_GUIDE.md) | |
| - **Supabase Auth Docs:** https://supabase.com/docs/guides/auth | |
| - **JWT Best Practices:** https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/ | |
| --- | |
| ## β Recommended Solution | |
| **Use the automatic token refresh implementation** (already complete): | |
| 1. β Backend changes pushed to production | |
| 2. π Follow frontend guide: [`FRONTEND_TOKEN_REFRESH_GUIDE.md`](./FRONTEND_TOKEN_REFRESH_GUIDE.md) | |
| 3. π§ͺ Test the complete flow | |
| 4. π Users stay logged in for 30 days seamlessly! | |
| **Step 3: Add refresh endpoint to backend** | |
| - Add `/api/v1/auth/refresh-token` endpoint | |
| - Implement `refresh_session()` in SupabaseAuthService | |
| ## Testing | |
| **Test token expiration:** | |
| ```bash | |
| # Login | |
| curl -X POST http://localhost:8000/api/v1/auth/login \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"email":"admin@swiftops.com","password":"yourpassword"}' | |
| # Get access_token and refresh_token from response | |
| # Wait for token to expire (or manually expire it) | |
| # Test refresh | |
| curl -X POST http://localhost:8000/api/v1/auth/refresh-token \ | |
| -H "Content-Type: application/json" \ | |
| -d '{"refresh_token":"YOUR_REFRESH_TOKEN"}' | |
| ``` | |
| **Frontend test:** | |
| ```javascript | |
| // Force token refresh | |
| await refreshAccessToken(); | |
| // Check if it works | |
| const response = await api.get('/api/v1/auth/me'); | |
| console.log(response.data); // Should return user data | |
| ``` | |
| ## Security Considerations | |
| 1. **Never store tokens in localStorage for sensitive apps** - Use httpOnly cookies instead | |
| 2. **Always use HTTPS** in production | |
| 3. **Rotate refresh tokens** after each use (Supabase does this automatically) | |
| 4. **Set appropriate expiry times:** | |
| - Access token: 1-24 hours | |
| - Refresh token: 7-30 days | |
| 5. **Implement token revocation** for logout | |
| ## Environment Variables | |
| Add to `.env`: | |
| ```bash | |
| # JWT Settings | |
| ACCESS_TOKEN_EXPIRE_MINUTES=10080 # 7 days | |
| REFRESH_TOKEN_EXPIRE_DAYS=30 | |
| # Supabase JWT Expiry (configure in Supabase Dashboard) | |
| # JWT_EXP=604800 # 7 days | |
| ``` | |
| ## Summary | |
| **Immediate Fix:** | |
| 1. Go to Supabase Dashboard | |
| 2. Settings > Auth > JWT Expiry | |
| 3. Change to 604800 seconds (7 days) | |
| **Long-term Solution:** | |
| 1. Implement token refresh endpoint in backend | |
| 2. Add auto-refresh logic to frontend | |
| 3. Handle 401 errors gracefully | |
| 4. Test thoroughly | |
| **Result:** | |
| - Users stay logged in for 7 days | |
| - Tokens refresh automatically before expiration | |
| - Smooth user experience without unexpected logouts | |
| - Proper security with shorter-lived access tokens | |
| ## Additional Resources | |
| - [Supabase Auth Documentation](https://supabase.com/docs/guides/auth) | |
| - [JWT Best Practices](https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/) | |
| - [Token Refresh Strategies](https://www.rfc-editor.org/rfc/rfc6749#section-6) | |