File size: 5,764 Bytes
f9637ae
 
 
 
 
 
 
 
 
 
 
 
 
b23f5d7
f9637ae
b23f5d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f9637ae
 
 
 
 
 
 
 
 
 
 
 
 
 
b23f5d7
f9637ae
b23f5d7
f9637ae
b23f5d7
f9637ae
b23f5d7
f9637ae
 
 
b23f5d7
 
f9637ae
b23f5d7
f9637ae
 
b23f5d7
f9637ae
b23f5d7
f9637ae
 
 
b23f5d7
 
 
 
 
 
 
 
 
 
 
f9637ae
b23f5d7
f9637ae
b23f5d7
f9637ae
b23f5d7
 
 
 
f9637ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# 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)