# Quick Start: Refresh Token Rotation & Remember Me ## Setup ### 1. Update Environment Variables Add to your `.env` file: ```bash JWT_REMEMBER_ME_EXPIRE_DAYS=30 ``` ### 2. Create Database Indexes Run the index creation script: ```bash cd bookmyservice-ums python scripts/create_indexes.py ``` ### 3. Restart Your Service ```bash # If using uvicorn directly uvicorn app.app:app --reload # If using docker docker-compose restart ums ``` ## Testing ### Test 1: Login with Remember Me ```bash # Step 1: Send OTP curl -X POST http://localhost:8000/send-otp-login \ -H "Content-Type: application/json" \ -d '{ "login_input": "+1234567890" }' # Response includes temp_token # {"message": "OTP sent", "temp_token": "...", "user_exists": true} # Step 2: Login with OTP and remember_me curl -X POST http://localhost:8000/otp-login \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "login_input": "+1234567890", "otp": "777777", "remember_me": true, "device_info": "Chrome 120 on macOS" }' # Response includes access_token and refresh_token ``` ### Test 2: Refresh Token (with Rotation) ```bash curl -X POST http://localhost:8000/refresh-token \ -H "Authorization: Bearer " # Response includes NEW access_token and NEW refresh_token # Old refresh_token is now invalid ``` ### Test 3: View Active Sessions ```bash curl -X GET http://localhost:8000/sessions \ -H "Authorization: Bearer " # Response shows all active sessions with device info ``` ### Test 4: Logout from Specific Device ```bash curl -X DELETE http://localhost:8000/sessions/ \ -H "Authorization: Bearer " ``` ### Test 5: Logout from All Devices ```bash curl -X POST http://localhost:8000/logout-all \ -H "Authorization: Bearer " ``` ## Verify Token Rotation ### Check Token is Marked as Used ```python from app.models.refresh_token_model import RefreshTokenModel import asyncio async def check_token(): # After using a refresh token token_id = "your-token-id" metadata = await RefreshTokenModel.get_token_metadata(token_id) print(f"Used: {metadata.get('used')}") print(f"Used at: {metadata.get('used_at')}") asyncio.run(check_token()) ``` ### Test Replay Attack Detection ```bash # Use a refresh token curl -X POST http://localhost:8000/refresh-token \ -H "Authorization: Bearer " # Try to use the SAME refresh token again curl -X POST http://localhost:8000/refresh-token \ -H "Authorization: Bearer " # Should return 401 error and revoke entire token family ``` ## Maintenance ### Daily Cleanup (Cron Job) Add to your crontab: ```bash # Run cleanup daily at 2 AM 0 2 * * * cd /path/to/bookmyservice-ums && python scripts/cleanup_tokens.py >> /var/log/token_cleanup.log 2>&1 ``` Or use a scheduler in your application: ```python from apscheduler.schedulers.asyncio import AsyncIOScheduler from app.models.refresh_token_model import RefreshTokenModel scheduler = AsyncIOScheduler() @scheduler.scheduled_job('cron', hour=2) async def cleanup_job(): await RefreshTokenModel.cleanup_expired_tokens() scheduler.start() ``` ## Monitoring ### Check Token Statistics ```bash python scripts/cleanup_tokens.py ``` Output: ``` 📊 Token Statistics: Total tokens: 150 Active tokens: 120 Revoked tokens: 20 Expired tokens: 10 Used tokens: 80 Remember me tokens: 45 ``` ### Monitor Suspicious Activity The cleanup script automatically checks for: - Token families with >100 rotations - Unusual rotation patterns - Potential security breaches ## Frontend Integration Example ### React Hook for Token Management ```javascript import { useState, useEffect } from 'react'; export function useAuth() { const [accessToken, setAccessToken] = useState( localStorage.getItem('access_token') ); const [refreshToken, setRefreshToken] = useState( localStorage.getItem('refresh_token') ); // Auto-refresh before expiry useEffect(() => { const interval = setInterval(async () => { if (refreshToken) { try { const response = await fetch('/refresh-token', { method: 'POST', headers: { 'Authorization': `Bearer ${refreshToken}` } }); if (response.ok) { const data = await response.json(); setAccessToken(data.access_token); setRefreshToken(data.refresh_token); localStorage.setItem('access_token', data.access_token); localStorage.setItem('refresh_token', data.refresh_token); } } catch (error) { console.error('Token refresh failed:', error); } } }, 7 * 60 * 1000); // Refresh every 7 minutes return () => clearInterval(interval); }, [refreshToken]); const login = async (loginInput, otp, rememberMe = false) => { const response = await fetch('/otp-login', { method: 'POST', headers: { 'Authorization': `Bearer ${tempToken}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ login_input: loginInput, otp: otp, remember_me: rememberMe, device_info: navigator.userAgent }) }); const data = await response.json(); setAccessToken(data.access_token); setRefreshToken(data.refresh_token); localStorage.setItem('access_token', data.access_token); localStorage.setItem('refresh_token', data.refresh_token); }; const logout = async () => { await fetch('/logout', { method: 'POST', headers: { 'Authorization': `Bearer ${refreshToken}` } }); setAccessToken(null); setRefreshToken(null); localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); }; return { accessToken, refreshToken, login, logout }; } ``` ## Troubleshooting ### Issue: "Invalid refresh token" after first use **Solution**: This is expected behavior with rotation. Always use the NEW refresh token from the response. ### Issue: All sessions revoked unexpectedly **Cause**: Token reuse detected (replay attack prevention) **Solution**: User must login again. Check for client-side bugs causing token reuse. ### Issue: Remember me not working **Check**: 1. `JWT_REMEMBER_ME_EXPIRE_DAYS` is set in .env 2. `remember_me: true` is sent in login request 3. Token metadata shows `remember_me: true` ### Issue: Sessions not showing up **Check**: 1. Database indexes are created 2. MongoDB connection is working 3. Token hasn't expired ## Security Checklist - [ ] HTTPS enabled in production - [ ] Refresh tokens stored securely (httpOnly cookies recommended) - [ ] Access tokens have short expiry (8 hours or less) - [ ] Remember me tokens have reasonable expiry (30 days max) - [ ] Cleanup script runs daily - [ ] Monitoring alerts set up for suspicious activity - [ ] Database indexes created - [ ] Rate limiting enabled on refresh endpoint ## Next Steps 1. Implement httpOnly cookies for refresh tokens (more secure than localStorage) 2. Add device fingerprinting for additional security 3. Set up monitoring and alerting 4. Implement push notifications for new logins 5. Add geolocation-based anomaly detection ## Support For issues or questions: 1. Check the logs: `tail -f app.log` 2. Run diagnostics: `python scripts/cleanup_tokens.py` 3. Review the full documentation: `REFRESH_TOKEN_ROTATION.md`