From f26020cf7f985be7c98a8b5ab6e0da8ef5143daf Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Fri, 27 Mar 2026 08:34:06 -0700 Subject: [PATCH] fix: use Directus 11 'id' claim instead of 'sub' for JWT user_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Directus 11.x JWT payload uses 'id' (not 'sub') for the user UUID. Our validate_session_jwt required 'sub' → MissingRequiredClaimError on every request → persistent 401 on all cloud endpoints. --- api/cloud_session.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/api/cloud_session.py b/api/cloud_session.py index fd24c1e..a977344 100644 --- a/api/cloud_session.py +++ b/api/cloud_session.py @@ -100,11 +100,13 @@ def _extract_session_token(header_value: str) -> str: def validate_session_jwt(token: str) -> str: - """Validate a cf_session JWT and return the Directus user_id (sub claim). + """Validate a cf_session JWT and return the Directus user_id. Uses HMAC-SHA256 verification against DIRECTUS_JWT_SECRET (same secret cf-directus uses to sign session tokens). Returns user_id on success, raises HTTPException(401) on failure. + + Directus 11+ uses 'id' (not 'sub') for the user UUID in its JWT payload. """ try: import jwt as pyjwt @@ -112,9 +114,9 @@ def validate_session_jwt(token: str) -> str: token, DIRECTUS_JWT_SECRET, algorithms=["HS256"], - options={"require": ["sub", "exp"]}, + options={"require": ["id", "exp"]}, ) - return payload["sub"] + return payload["id"] except Exception as exc: log.debug("JWT validation failed: %s", exc) raise HTTPException(status_code=401, detail="Session invalid or expired")