Fix auth to handle JWT tokens without actor_id
- Default actor_id to @username when not in token claims - Support both artdag_session (base64 JSON) and auth_token (JWT) cookies - Check both 'username' and 'sub' claims for username - Check both 'actor_id' and 'actor' claims for actor_id This fixes authentication when L2 tokens don't include actor_id. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
BIN
artdag_common/middleware/__pycache__/auth.cpython-310.pyc
Normal file
BIN
artdag_common/middleware/__pycache__/auth.cpython-310.pyc
Normal file
Binary file not shown.
@@ -31,8 +31,9 @@ def get_user_from_cookie(request: Request) -> Optional[UserContext]:
|
|||||||
"""
|
"""
|
||||||
Extract user context from session cookie.
|
Extract user context from session cookie.
|
||||||
|
|
||||||
The cookie format is expected to be base64-encoded JSON:
|
Supports two cookie formats:
|
||||||
{"username": "user", "actor_id": "@user@server.com"}
|
1. artdag_session: base64-encoded JSON {"username": "user", "actor_id": "@user@server.com"}
|
||||||
|
2. auth_token: raw JWT token (used by L1 servers)
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
request: FastAPI request
|
request: FastAPI request
|
||||||
@@ -40,19 +41,38 @@ def get_user_from_cookie(request: Request) -> Optional[UserContext]:
|
|||||||
Returns:
|
Returns:
|
||||||
UserContext if valid cookie found, None otherwise
|
UserContext if valid cookie found, None otherwise
|
||||||
"""
|
"""
|
||||||
|
# Try artdag_session cookie first (base64-encoded JSON)
|
||||||
cookie = request.cookies.get("artdag_session")
|
cookie = request.cookies.get("artdag_session")
|
||||||
if not cookie:
|
if cookie:
|
||||||
return None
|
try:
|
||||||
|
data = json.loads(base64.b64decode(cookie))
|
||||||
|
username = data.get("username", "")
|
||||||
|
actor_id = data.get("actor_id", "")
|
||||||
|
if not actor_id and username:
|
||||||
|
actor_id = f"@{username}"
|
||||||
|
return UserContext(
|
||||||
|
username=username,
|
||||||
|
actor_id=actor_id,
|
||||||
|
)
|
||||||
|
except (json.JSONDecodeError, ValueError, KeyError):
|
||||||
|
pass
|
||||||
|
|
||||||
try:
|
# Try auth_token cookie (raw JWT, used by L1)
|
||||||
# Decode base64 cookie
|
token = request.cookies.get("auth_token")
|
||||||
data = json.loads(base64.b64decode(cookie))
|
if token:
|
||||||
return UserContext(
|
claims = decode_jwt_claims(token)
|
||||||
username=data.get("username", ""),
|
if claims:
|
||||||
actor_id=data.get("actor_id", ""),
|
username = claims.get("username") or claims.get("sub", "")
|
||||||
)
|
actor_id = claims.get("actor_id") or claims.get("actor")
|
||||||
except (json.JSONDecodeError, ValueError, KeyError):
|
if not actor_id and username:
|
||||||
return None
|
actor_id = f"@{username}"
|
||||||
|
return UserContext(
|
||||||
|
username=username,
|
||||||
|
actor_id=actor_id or "",
|
||||||
|
token=token,
|
||||||
|
)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_user_from_header(request: Request) -> Optional[UserContext]:
|
def get_user_from_header(request: Request) -> Optional[UserContext]:
|
||||||
@@ -76,9 +96,14 @@ def get_user_from_header(request: Request) -> Optional[UserContext]:
|
|||||||
# Attempt to decode JWT claims
|
# Attempt to decode JWT claims
|
||||||
claims = decode_jwt_claims(token)
|
claims = decode_jwt_claims(token)
|
||||||
if claims:
|
if claims:
|
||||||
|
username = claims.get("username") or claims.get("sub", "")
|
||||||
|
actor_id = claims.get("actor_id") or claims.get("actor")
|
||||||
|
# Default actor_id to @username if not provided
|
||||||
|
if not actor_id and username:
|
||||||
|
actor_id = f"@{username}"
|
||||||
return UserContext(
|
return UserContext(
|
||||||
username=claims.get("username", ""),
|
username=username,
|
||||||
actor_id=claims.get("actor_id", ""),
|
actor_id=actor_id or "",
|
||||||
token=token,
|
token=token,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user