Coverage for backend/django/authentication/token_helpers.py: 94%
27 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-05-13 02:47 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-05-13 02:47 +0000
1"""Testing-only helpers for synthetic proxy JWTs.
3These helpers generate unsigned-trust test tokens (HS256 with a hardcoded
4development secret) used by local/debug middleware and test suites.
6Do not use this module for production authentication or authorization flows.
7Production token handling must rely on real upstream tokens and signature
8verification against trusted keys.
9"""
11from __future__ import annotations
13import os
14from collections.abc import Iterable
15from typing import Any
17import jwt
18from django.conf import settings
20_BASE_ACCESS_TOKEN_CLAIMS = {
21 "exp": 1756268489,
22 "iat": 1756268189,
23 "auth_time": 1756268189,
24 "jti": "f7cf0ea7-6e22-4f37-be16-32399127e500",
25 "iss": "http://issuer.com",
26 "aud": ["platform"],
27 "sub": "a60d7a1e-7d65-4b8d-92a9-1c0dcc1fe44f",
28 "typ": "Bearer",
29 "azp": "platform",
30 "sid": "70d7f166-facb-4c09-ad27-bc3f6ee897ce",
31 "acr": "1",
32 "allowed-origins": ["*"],
33 "email_verified": True,
34 "name": "John Smith",
35 "preferred_username": "example@email.com",
36 "given_name": "John",
37 "family_name": "Smith",
38 "email": "example@email.com",
39}
42def _ensure_not_production_mode() -> None:
43 if "UNDER_PYTEST" not in os.environ and not settings.DEBUG:
44 raise RuntimeError(
45 "Synthetic access-token test helpers are disabled when UNDER_PYTEST is False and debug is not enabled."
46 )
49def build_proxy_access_token(
50 scopes: Iterable[str] | None = None,
51 *,
52 extra_claims: dict[str, Any] | None = None,
53) -> str:
54 """Build a synthetic proxy-style JWT for tests/debug only.
56 Warning:
57 This function is not safe for production use.
58 It uses a static signing secret and produces tokens intended only for
59 local test execution and debug middleware defaults.
60 """
61 _ensure_not_production_mode()
63 scope_values = ["openid", "profile", "email", *(scopes or [])]
64 normalized_scopes = [item for item in dict.fromkeys(scope_values) if item]
66 payload = dict(_BASE_ACCESS_TOKEN_CLAIMS)
67 payload["scope"] = " ".join(normalized_scopes)
69 if extra_claims:
70 payload.update(extra_claims)
72 return jwt.encode(payload, "secret", algorithm="HS256")
75def build_human_user_access_token() -> str:
76 """Return a synthetic token with the configured HumanUser scope.
78 Testing/debug only. Not for production authentication.
79 """
80 return build_proxy_access_token(scopes=[settings.AUTH_GENERAL_SCOPE_KEY])
83def build_excel_client_access_token() -> str:
84 """Return a synthetic token with the configured ExcelClient scope.
86 Testing/debug only. Not for production authentication.
87 """
88 return build_proxy_access_token(scopes=[settings.AUTH_EXCEL_SCOPE_KEY])
91# Backward-compatible aliases for existing imports.
92def build_general_access_token() -> str:
93 return build_human_user_access_token()
96def build_delegated_access_token() -> str:
97 return build_excel_client_access_token()