47 lines
1.7 KiB
Python
47 lines
1.7 KiB
Python
from repositories.pocketbase_client import pb_client
|
|
from repositories.tenant_repository import tenant_repository
|
|
from repositories.seat_repository import seat_repository
|
|
|
|
|
|
def get_tenant_id_from_request(request):
|
|
"""
|
|
Resolves the tenant_id for a dashboard request from its
|
|
`Authorization: Bearer {jwt}` header. The JWT itself is issued and
|
|
verified by PocketBase (the dashboard authenticates directly against
|
|
PocketBase) — this backend doesn't hold the JWT signing secret, so
|
|
it validates the token by asking PocketBase to refresh it, then
|
|
resolves the returned email to a tenant via the existing seat record.
|
|
|
|
Data flow:
|
|
request.headers['Authorization'] → strip "Bearer " prefix →
|
|
PocketBase POST /api/collections/users/auth-refresh →
|
|
{ record: { email } } → seat lookup by email across known tenants
|
|
(via domain) → tenant_id returned, or None if unresolvable
|
|
"""
|
|
auth_header = request.headers.get('Authorization', '')
|
|
if not auth_header.startswith('Bearer '):
|
|
return None
|
|
token = auth_header[len('Bearer '):]
|
|
|
|
record = pb_client.auth_refresh(token)
|
|
if not record or not record.get('email'):
|
|
return None
|
|
|
|
email = record['email']
|
|
domain = email.split('@', 1)[1].lower() if '@' in email else None
|
|
if not domain:
|
|
return None
|
|
|
|
tenant = tenant_repository.get_by_domain(domain)
|
|
if not tenant:
|
|
return None
|
|
|
|
# Confirm this email actually holds an active seat on the tenant —
|
|
# a verified PocketBase login alone isn't sufficient authorization,
|
|
# the email must also be a registered, active seat.
|
|
seat = seat_repository.get_active(tenant['id'], email)
|
|
if not seat:
|
|
return None
|
|
|
|
return tenant['id']
|