feat: implement long-term user login with refresh tokens
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m23s
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m23s
- Introduced a dual-token system for user authentication: a short-lived access token and a long-lived rotating refresh token. - Created a new RefreshToken model to manage refresh tokens securely. - Updated auth_api.py to handle login, refresh, and logout processes with the new token system. - Enhanced security measures including token rotation and theft detection. - Updated frontend to handle token refresh on 401 errors and adjusted SSE authentication. - Removed CORS middleware as it's unnecessary behind the nginx proxy. - Added tests to ensure functionality and security of the new token system.
This commit is contained in:
@@ -7,6 +7,7 @@ from db.db import users_db
|
||||
from tinydb import Query
|
||||
import jwt
|
||||
from werkzeug.security import generate_password_hash
|
||||
from tests.conftest import TEST_SECRET_KEY, TEST_REFRESH_TOKEN_EXPIRY_DAYS
|
||||
|
||||
# Test user credentials
|
||||
TEST_EMAIL = "usertest@example.com"
|
||||
@@ -50,9 +51,10 @@ def login_and_get_token(client, email, password):
|
||||
"""Login and extract JWT token from response."""
|
||||
resp = client.post('/auth/login', json={"email": email, "password": password})
|
||||
assert resp.status_code == 200
|
||||
# Extract token from Set-Cookie header
|
||||
set_cookie = resp.headers.get("Set-Cookie")
|
||||
assert set_cookie and "token=" in set_cookie
|
||||
# Verify auth cookies are set
|
||||
cookies = resp.headers.getlist('Set-Cookie')
|
||||
cookie_str = ' '.join(cookies)
|
||||
assert 'access_token=' in cookie_str
|
||||
# Flask test client automatically handles cookies
|
||||
return resp
|
||||
|
||||
@@ -63,7 +65,8 @@ def client():
|
||||
app.register_blueprint(user_api)
|
||||
app.register_blueprint(auth_api, url_prefix='/auth')
|
||||
app.config['TESTING'] = True
|
||||
app.config['SECRET_KEY'] = 'supersecretkey'
|
||||
app.config['SECRET_KEY'] = TEST_SECRET_KEY
|
||||
app.config['REFRESH_TOKEN_EXPIRY_DAYS'] = TEST_REFRESH_TOKEN_EXPIRY_DAYS
|
||||
app.config['FRONTEND_URL'] = 'http://localhost:5173' # Needed for email_sender
|
||||
with app.test_client() as client:
|
||||
add_test_users()
|
||||
@@ -200,7 +203,7 @@ def test_mark_for_deletion_clears_tokens(authenticated_client):
|
||||
def test_mark_for_deletion_with_invalid_jwt(client):
|
||||
"""Test marking for deletion with invalid JWT token."""
|
||||
# Set invalid cookie manually
|
||||
client.set_cookie('token', 'invalid.jwt.token')
|
||||
client.set_cookie('access_token', 'invalid.jwt.token')
|
||||
|
||||
response = client.post('/user/mark-for-deletion', json={})
|
||||
assert response.status_code == 401
|
||||
|
||||
Reference in New Issue
Block a user