Files
meet/src/backend/core/services/transit_code.py
T
briquet f1ef84dc9c ✨(backend) audit transit code issuance and exchange
Trace the login flow of the embedded iframe frontend flow.
An application minting a transit code for its delegated user should
logs the transit_code issuance and it's exchange for a user access
token. The transit_code can be identified and with a
SHA-256 to audit eventual replay attacks.
2026-10-19 15:25:43 +02:00

82 lines
2.5 KiB
Python

"""Service handling the lifecycle of transit codes.
A transit code is an opaque, cryptographically random, single-use code
handed to an embedded frontend (through a URL fragment) so it can obtain a
user access token on the core API without a session cookie. The code
carries no information by itself: everything it references (user, client)
is stored server-side in the cache, and consumed atomically on exchange.
"""
import hashlib
import secrets
from django.conf import settings
from django.core.cache import cache
class TransitCodeService:
"""Create and consume single-use transit codes."""
@staticmethod
def digest(code):
"""Return the SHA-256 hex digest of a code.
It identifies a code, in the cache and in audit events
"""
return hashlib.sha256(code.encode("utf-8")).hexdigest()
@classmethod
def _cache_key(cls, code):
"""Build the cache key for a code.
The code is hashed so that a dump of the cache never reveals
directly usable codes.
"""
return f"{settings.TRANSIT_CODE_CACHE_PREFIX}:{cls.digest(code)}"
def create_code(self, user, client_id):
"""Generate a transit code for a user, and store it.
The code expires after TRANSIT_CODE_TTL seconds.
Returns:
str: The opaque code to hand to the client.
"""
# Default 48 random bytes -> 64 url-safe characters, 384 bits of
# entropy: unguessable and safe to transit through a URL fragment.
code = secrets.token_urlsafe(settings.TRANSIT_CODE_NBYTES)
cache.set(
self._cache_key(code),
{
"user_id": str(user.id),
"client_id": client_id,
},
timeout=settings.TRANSIT_CODE_TTL,
)
return code
def consume_code(self, code):
"""Consume a transit code, enforcing single use.
The code is deleted from the cache upon consumption. `cache.delete`
returns whether a key was actually deleted, so if two requests race
on the same code, only one of them wins.
Returns:
dict | None: The data stored at creation time ('user_id',
'client_id'), or None if the code is unknown, expired or
already consumed.
"""
if not code:
return None
key = self._cache_key(code)
data = cache.get(key)
if data is None or not cache.delete(key):
return None
return data