TokenManager
The TokenManager class handles JSON Web Token (JWT) creation and validation for user authentication in Framefox applications. It provides stateless authentication suitable for APIs and single-page applications.
Source : framefox/core/security/token_manager.py:17
Constructor
The TokenManager automatically loads configuration from Settings:
Algorithm : HS256 (HMAC with SHA-256)
Secret Key : From session_secret_key in settings
Expiration : 3600 seconds (1 hour) by default
The session_secret_key must be set in your configuration or environment variables, otherwise TokenManager will raise a ValueError.
Methods
create_token()
Creates a JWT token for an authenticated user.
def create_token ( self , user , firewallname : str , roles : list = None ) -> str
The authenticated user object. Must have id and email attributes.
The name of the firewall that authenticated the user
List of role strings assigned to the user
The encoded JWT token string
Token Payload:
sub: User ID (as string)
email: User email address
roles: List of user roles
firewallname: Name of the firewall
iat: Issued at timestamp
exp: Expiration timestamp (iat + 3600 seconds)
Example:
from framefox.core.security.token_manager import TokenManager
token_manager = TokenManager()
# Create token for authenticated user
token = token_manager.create_token(
user = current_user,
firewallname = "api" ,
roles = [ "ROLE_USER" , "ROLE_EDITOR" ]
)
print (token) # eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
decode_token()
Decodes and validates a JWT token.
def decode_token ( self , token : str ) -> dict | None
The JWT token string to decode
The decoded token payload as a dictionary, or None if the token is invalid or expired
Returns None when:
Token signature is invalid
Token has expired
Token format is malformed
Example:
token_manager = TokenManager()
# Decode and validate token
payload = token_manager.decode_token(token)
if payload:
user_id = payload[ "sub" ]
email = payload[ "email" ]
roles = payload[ "roles" ]
print ( f "User: { email } , Roles: { roles } " )
else :
print ( "Invalid or expired token" )
Virtual OAuth Users
The TokenManager supports creating tokens for virtual OAuth users (users authenticated via OAuth providers who don’t exist in your database):
# User object has is_virtual attribute
if hasattr (user, "is_virtual" ) and user.is_virtual:
# Virtual user - ID is generated during OAuth flow
token = token_manager.create_token(user, "oauth" , roles = [ "ROLE_USER" ])
Complete Example: Login Endpoint
from framefox.core.controller.abstract_controller import AbstractController
from framefox.core.routing.decorator.route import Route
from framefox.core.security.token_manager import TokenManager
from framefox.core.security.password.password_hasher import PasswordHasher
from pydantic import BaseModel
class LoginRequest ( BaseModel ):
email: str
password: str
class LoginResponse ( BaseModel ):
token: str
user: dict
class AuthController ( AbstractController ):
def __init__ (
self ,
token_manager : TokenManager,
password_hasher : PasswordHasher,
user_repository
):
super (). __init__ ()
self .token_manager = token_manager
self .password_hasher = password_hasher
self .user_repository = user_repository
@Route ( "/api/login" , "api.login" , methods = [ "POST" ], response_model = LoginResponse)
async def login ( self , credentials : LoginRequest):
# Find user
user = await self .user_repository.find_one_by(
{ "email" : credentials.email}
)
if not user:
return self .json({ "error" : "Invalid credentials" }, status = 401 )
# Verify password
if not self .password_hasher.verify(credentials.password, user.password):
return self .json({ "error" : "Invalid credentials" }, status = 401 )
# Create token
token = self .token_manager.create_token(
user = user,
firewallname = "api" ,
roles = user.roles
)
return self .json({
"token" : token,
"user" : {
"id" : user.id,
"email" : user.email,
"roles" : user.roles
}
})
Token Verification in Middleware
from starlette.middleware.base import BaseHTTPMiddleware
from framefox.core.security.token_manager import TokenManager
class JWTMiddleware ( BaseHTTPMiddleware ):
def __init__ ( self , app , token_manager : TokenManager):
super (). __init__ (app)
self .token_manager = token_manager
async def dispatch ( self , request , call_next ):
# Skip authentication for public routes
if request.url.path in [ "/login" , "/register" ]:
return await call_next(request)
# Get token from header
auth_header = request.headers.get( "Authorization" )
if not auth_header or not auth_header.startswith( "Bearer " ):
return JSONResponse({ "error" : "Unauthorized" }, status_code = 401 )
token = auth_header[ 7 :]
# Validate token
payload = self .token_manager.decode_token(token)
if not payload:
return JSONResponse({ "error" : "Invalid token" }, status_code = 401 )
# Attach user info to request state
request.state.user_id = payload[ "sub" ]
request.state.email = payload[ "email" ]
request.state.roles = payload[ "roles" ]
return await call_next(request)
Token Refresh
Implement token refresh by checking the expiration time and issuing new tokens before they expire:
import time
@Route ( "/api/refresh" , "api.refresh" , methods = [ "POST" ])
async def refresh_token ( self , token_manager : TokenManager):
# Get current token
auth_header = request.headers.get( "Authorization" )
token = auth_header[ 7 :]
# Decode token
payload = token_manager.decode_token(token)
if not payload:
return self .json({ "error" : "Invalid token" }, status = 401 )
# Check if token is close to expiration (within 5 minutes)
time_until_expiry = payload[ "exp" ] - int (time.time())
if time_until_expiry > 300 : # More than 5 minutes left
return self .json({ "token" : token}) # Return same token
# Issue new token
user = await self .user_repository.find(payload[ "sub" ])
new_token = token_manager.create_token(
user = user,
firewallname = payload[ "firewallname" ],
roles = payload[ "roles" ]
)
return self .json({ "token" : new_token})
Security Best Practices
Keep your secret key secure
Never commit the secret key to version control
Use environment variables or secure configuration management
Rotate the secret key periodically
Use a strong, random secret key (at least 32 characters)
Use short expiration times (1 hour default)
Implement token refresh for better UX
Consider different expiration times for different use cases
Store tokens securely on the client (httpOnly cookies for web)
Never store tokens in localStorage for sensitive applications
Clear tokens on logout
Always use HTTPS in production
Tokens transmitted over HTTP can be intercepted
See Also
Authenticator Authentication implementation
Authentication Guide Complete authentication guide
Access Manager Role-based access control
Security Overview Security features overview