61 lines
1.8 KiB
Python
61 lines
1.8 KiB
Python
from dataclasses import dataclass
|
|
from typing import Optional
|
|
from datetime import datetime
|
|
from flask_jwt_extended import decode_token, verify_jwt_in_request
|
|
from flask import current_app
|
|
|
|
|
|
@dataclass
|
|
class TokenValidationResult:
|
|
"""Clean, simple validation result"""
|
|
is_valid: bool
|
|
tenant_id: Optional[int] = None
|
|
error_message: Optional[str] = None
|
|
|
|
|
|
class TokenValidator:
|
|
"""Simplified token validator focused on JWT validation"""
|
|
|
|
def validate_token(self, token: str) -> TokenValidationResult:
|
|
"""
|
|
Validate JWT token
|
|
|
|
Args:
|
|
token: The JWT token to validate
|
|
|
|
Returns:
|
|
TokenValidationResult with validation status and tenant_id if valid
|
|
"""
|
|
try:
|
|
# Decode and validate token
|
|
decoded_token = decode_token(token)
|
|
|
|
# Extract tenant_id from token subject
|
|
tenant_id = decoded_token.get('sub')
|
|
if not tenant_id:
|
|
return TokenValidationResult(
|
|
is_valid=False,
|
|
error_message="Missing tenant ID in token"
|
|
)
|
|
|
|
# Verify token timestamps
|
|
now = datetime.utcnow().timestamp()
|
|
if not (decoded_token.get('exp', 0) > now >= decoded_token.get('nbf', 0)):
|
|
return TokenValidationResult(
|
|
is_valid=False,
|
|
error_message="Token expired or not yet valid"
|
|
)
|
|
|
|
# Token is valid
|
|
return TokenValidationResult(
|
|
is_valid=True,
|
|
tenant_id=tenant_id
|
|
)
|
|
|
|
except Exception as e:
|
|
current_app.logger.error(f"Token validation error: {str(e)}")
|
|
return TokenValidationResult(
|
|
is_valid=False,
|
|
error_message=str(e)
|
|
)
|