refactor(env): unify Docker env vars — canonical AUTH_SECRET_KEY, remove JWT_SECRET fallback
Canonical variables:
- AUTH_SECRET_KEY — JWT signing key for backend + agent (was split across
AUTH_SECRET_KEY / JWT_SECRET)
- SERVICE_JWT — agent→backend service token
- No JWT_SECRET fallback: decoder fails with migration guidance if only
JWT_SECRET is set
Compose files unified:
- docker-compose.yml, docker-compose.enterprise-clean.yml,
docker-compose.e2e.yml — all use AUTH_SECRET_KEY
- build.sh generated compose now passes AUTH_SECRET_KEY + ENCRYPTION_KEY
to backend
Env examples unified and completed:
- .env.example — comprehensive template, all compose vars
- .env.enterprise-clean.example — production template
- backend/.env.example — backend-only run
- docker/.env.agent.example — agent-only run
- NEW: .env.current.example, .env.master.example,
.env.e2e.example, frontend/.env.example
Tests aligned:
- conftest sets AUTH_SECRET_KEY (canonical value matched across test files)
- test mocks use canonical name
- 1176 passed, 0 failed
This commit is contained in:
@@ -1,52 +1,50 @@
|
||||
# backend/src/agent/_jwt_decoder.py
|
||||
# #region AgentChat.JwtDecoder [C:1] [TYPE Module] [SEMANTICS agent-chat,jwt,decode]
|
||||
# @BRIEF Lightweight JWT decode for agent — uses JWT_SECRET env var directly, avoids
|
||||
# @BRIEF Lightweight JWT decode for agent — uses AUTH_SECRET_KEY env var, avoids
|
||||
# pulling src.core.auth.jwt which requires AUTH_DATABASE_URL and ORM deps.
|
||||
# @RATIONALE The agent only needs stateless JWT validation (exp, sub, signature).
|
||||
# Token blacklisting is only relevant for backend auth flow — the agent
|
||||
# processes one request at a time and doesn't need DB-backed revocation.
|
||||
# @INVARIANT AUTH_SECRET_KEY is the ONLY accepted JWT signing key. JWT_SECRET is
|
||||
# unsupported and triggers a migration message if present without
|
||||
# AUTH_SECRET_KEY.
|
||||
# @REJECTED Importing src.core.auth.jwt.decode_token was rejected — it drags in
|
||||
# AuthConfig → AUTH_DATABASE_URL/SECRET_KEY validators → SQLAlchemy models,
|
||||
# AuthConfig -> AUTH_DATABASE_URL/SECRET_KEY validators -> SQLAlchemy models,
|
||||
# bloating the agent image with backend infrastructure it doesn't need.
|
||||
# @REJECTED Fallback from JWT_SECRET to AUTH_SECRET_KEY was rejected — ambiguous
|
||||
# naming caused operator confusion and secret drift between environments.
|
||||
import os
|
||||
|
||||
from jose import JWTError, jwt
|
||||
|
||||
|
||||
def decode_token(token: str) -> dict:
|
||||
"""Decode and validate a JWT token. Tries JWT_SECRET first, then AUTH_SECRET_KEY.
|
||||
"""Decode and validate a JWT token using AUTH_SECRET_KEY from environment.
|
||||
|
||||
Performs stateless validation: signature, expiration, and required claims
|
||||
(exp, sub). Does NOT check token blacklist or audience/issuer.
|
||||
"""
|
||||
keys = []
|
||||
jwt_key = os.getenv("JWT_SECRET", "")
|
||||
auth_key = os.getenv("AUTH_SECRET_KEY", "")
|
||||
if jwt_key:
|
||||
keys.append(jwt_key)
|
||||
if auth_key and auth_key != jwt_key:
|
||||
keys.append(auth_key)
|
||||
if not keys:
|
||||
raise JWTError("Neither JWT_SECRET nor AUTH_SECRET_KEY is set")
|
||||
|
||||
algorithm = os.getenv("JWT_ALGORITHM", "HS256")
|
||||
last_error = None
|
||||
for key in keys:
|
||||
try:
|
||||
return jwt.decode(
|
||||
token,
|
||||
key,
|
||||
algorithms=[algorithm],
|
||||
options={
|
||||
"verify_signature": True,
|
||||
"verify_exp": True,
|
||||
"verify_aud": False,
|
||||
"require": ["exp", "sub"],
|
||||
},
|
||||
)
|
||||
except JWTError as e:
|
||||
last_error = e
|
||||
raise last_error
|
||||
Raises JWTError with migration guidance if JWT_SECRET is set but
|
||||
AUTH_SECRET_KEY is missing (old deployments must rename the variable).
|
||||
"""
|
||||
secret = os.getenv("AUTH_SECRET_KEY", "")
|
||||
jwt_secret_legacy = os.getenv("JWT_SECRET", "")
|
||||
if not secret:
|
||||
if jwt_secret_legacy:
|
||||
raise JWTError("JWT_SECRET is no longer supported. Rename JWT_SECRET to AUTH_SECRET_KEY in your .env / docker-compose and restart the agent.")
|
||||
raise JWTError("AUTH_SECRET_KEY environment variable is not set")
|
||||
|
||||
return jwt.decode(
|
||||
token,
|
||||
secret,
|
||||
algorithms=[os.getenv("JWT_ALGORITHM", "HS256")],
|
||||
options={
|
||||
"verify_signature": True,
|
||||
"verify_exp": True,
|
||||
"verify_aud": False,
|
||||
"require": ["exp", "sub"],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
# #endregion AgentChat.JwtDecoder
|
||||
|
||||
Reference in New Issue
Block a user