Aug 20 - Session tenant binding

This commit is contained in:
2026-08-20 14:24:41 -04:00
parent 8b2582705d
commit 54a4a44bae
10 changed files with 325 additions and 13 deletions
+15
View File
@@ -10,6 +10,7 @@ claims needed to identify the caller:
{
"sub": "42", # user.id as string
"role": "inspector", # user.role
"tid": 3, # issuing tenant id (multi-tenant mode only)
"iat": 1710000000, # issued-at (UTC epoch)
"exp": 1710003600, # expiry (UTC epoch, 60 min later)
}
@@ -33,6 +34,12 @@ def _secret():
return current_app.config['SECRET_KEY']
def _current_tenant_id():
"""Resolved tenant id, or None in single-tenant / unbound contexts."""
from app.tenancy.session_binding import current_tenant_id
return current_tenant_id()
def generate_access_token(user, lifetime_minutes: int = ACCESS_TOKEN_LIFETIME_MINUTES) -> str:
"""
Create and sign a new access token for the given user.
@@ -54,6 +61,14 @@ def generate_access_token(user, lifetime_minutes: int = ACCESS_TOKEN_LIFETIME_MI
'iat': now,
'exp': now + timedelta(minutes=lifetime_minutes),
}
# MT-21: bind the token to the issuing tenant. Every tenant is signed with
# the same SECRET_KEY, so without this claim a token minted at one tenant
# host verifies at another and 'sub' resolves against whichever database
# the middleware bound. Omitted in single-tenant mode so token shape is
# unchanged there.
tid = _current_tenant_id()
if tid is not None:
payload['tid'] = tid
return jwt.encode(payload, _secret(), algorithm='HS256')