|
from flask import Flask, request, jsonify |
|
from flask_jwt_extended import JWTManager, create_access_token, get_jwt_identity, get_jwt |
|
from datetime import datetime, timedelta |
|
import hashlib |
|
import secrets |
|
|
|
def setup_secure_cookies(app: Flask): |
|
"""Setup secure cookie configuration for the Flask app.""" |
|
|
|
is_development = app.config.get('DEBUG', False) or app.config.get('ENV') == 'development' |
|
|
|
@app.after_request |
|
def set_secure_cookies(response): |
|
"""Set secure cookies for all responses.""" |
|
|
|
if request.method in ['POST', 'PUT']: |
|
|
|
token = request.headers.get('Authorization') |
|
if token and token.startswith('Bearer '): |
|
token = token[7:] |
|
|
|
|
|
response.set_cookie( |
|
'access_token', |
|
token, |
|
httponly=True, |
|
secure=not is_development, |
|
samesite='Strict', |
|
max_age=3600 |
|
) |
|
|
|
|
|
remember_me = False |
|
try: |
|
if request.is_json: |
|
json_data = request.get_json(silent=True) |
|
if json_data and isinstance(json_data, dict): |
|
remember_me = json_data.get('rememberMe', False) |
|
except: |
|
|
|
remember_me = False |
|
|
|
|
|
if remember_me: |
|
response.set_cookie( |
|
'refresh_token', |
|
secrets.token_urlsafe(32), |
|
httponly=True, |
|
secure=not is_development, |
|
samesite='Strict', |
|
max_age=7*24*60*60 |
|
) |
|
|
|
return response |
|
|
|
return app |
|
|
|
def configure_jwt_with_cookies(app: Flask): |
|
"""Configure JWT to work with cookies.""" |
|
jwt = JWTManager(app) |
|
|
|
@jwt.token_verification_loader |
|
def verify_token_on_refresh_callback(jwt_header, jwt_payload): |
|
"""Verify token and refresh if needed.""" |
|
|
|
return True |
|
|
|
@jwt.expired_token_loader |
|
def expired_token_callback(jwt_header, jwt_payload): |
|
"""Handle expired tokens.""" |
|
|
|
response = jsonify({'success': False, 'message': 'Token has expired'}) |
|
response.set_cookie('access_token', '', expires=0) |
|
response.set_cookie('refresh_token', '', expires=0) |
|
|
|
response.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response, 401 |
|
|
|
@jwt.invalid_token_loader |
|
def invalid_token_callback(error): |
|
"""Handle invalid tokens.""" |
|
response = jsonify({'success': False, 'message': 'Invalid token'}) |
|
response.set_cookie('access_token', '', expires=0) |
|
response.set_cookie('refresh_token', '', expires=0) |
|
|
|
response.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response, 401 |
|
|
|
@jwt.unauthorized_loader |
|
def missing_token_callback(error): |
|
"""Handle missing tokens.""" |
|
|
|
token = request.cookies.get('access_token') |
|
if token: |
|
|
|
request.headers['Authorization'] = f'Bearer {token}' |
|
return None |
|
response = jsonify({'success': False, 'message': 'Missing token'}) |
|
|
|
response.headers.add('Access-Control-Allow-Origin', 'http://localhost:3000') |
|
response.headers.add('Access-Control-Allow-Credentials', 'true') |
|
return response, 401 |
|
|
|
return jwt |