This is an automated email from the ASF dual-hosted git repository.
yasithdev pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airavata-portals.git
The following commit(s) were added to refs/heads/main by this push:
new b8323b191 fix(portal): keep the DB session user in the token-auth
browser bridge (Track D, D5) (#182)
b8323b191 is described below
commit b8323b1913a08e4b6f5ace2fd050faee0de5e7b3
Author: Yasith Jayawardana <[email protected]>
AuthorDate: Mon Jun 8 22:00:17 2026 -0400
fix(portal): keep the DB session user in the token-auth browser bridge
(Track D, D5) (#182)
`KeycloakTokenAuthentication` derived a lightweight non-DB `KeycloakUser`
from
the token for every request, including browser-session requests bridged via
the
session-stored access token. That broke every view that depends on the
DB-backed user the session login established — e.g. `UserViewSet.current`
does
`redirect(... pk=request.user.id)` and 500'd with
`'KeycloakUser' object has no attribute 'id'`; the user/profile serializers
likewise read `request.user.user_profile`.
When the token comes from the session (no `Authorization: Bearer` header),
reuse
the DB-backed user the Django session login already established. A pure
Bearer
request (API/desktop client) has no session user, so it still gets the
non-DB
`KeycloakUser` derived from the verified token claims. The token is
validated the
same way in both cases.
Verified live: `/auth/users/current/` 500 -> 302 -> user-detail 200 (full
UserSerializer payload); `/workspace/dashboard` 200.
---
.../django_airavata/apps/auth/token_authentication.py | 16 +++++++++++++++-
1 file changed, 15 insertions(+), 1 deletion(-)
diff --git
a/airavata-django-portal/django_airavata/apps/auth/token_authentication.py
b/airavata-django-portal/django_airavata/apps/auth/token_authentication.py
index a78313d7d..e41ddd60e 100644
--- a/airavata-django-portal/django_airavata/apps/auth/token_authentication.py
+++ b/airavata-django-portal/django_airavata/apps/auth/token_authentication.py
@@ -67,12 +67,14 @@ class
KeycloakTokenAuthentication(authentication.BaseAuthentication):
header = request.META.get('HTTP_AUTHORIZATION', '')
if header.startswith('Bearer '):
token = header[len('Bearer '):].strip()
+ bearer = True
else:
# Browser bridge: the session login flow stores the Keycloak access
# token in the session; use it when no Authorization header is sent
# so the existing browser session authenticates against the
# token-only API. (Final state: the frontend sends the token as a
# Bearer header and the session login is removed.)
+ bearer = False
session = getattr(request, 'session', None)
token = session.get('ACCESS_TOKEN') if session is not None else
None
if not token:
@@ -86,7 +88,19 @@ class
KeycloakTokenAuthentication(authentication.BaseAuthentication):
logger.warning("Keycloak token validation failed: %s", e)
raise exceptions.AuthenticationFailed("Invalid or expired token")
- user = KeycloakUser(claims)
+ # Browser-session bridge: when the token comes from the session (no
+ # Bearer header), the Django session login already established a
+ # DB-backed user that the user/profile views depend on
+ # (``request.user.id``, ``request.user.user_profile``). Reuse it. A
pure
+ # Bearer request (API/desktop client) has no session user, so derive a
+ # lightweight non-DB user straight from the verified token claims.
+ session_user = None
+ if hasattr(request, '_request'):
+ session_user = getattr(request._request, 'user', None)
+ if not bearer and session_user is not None and
session_user.is_authenticated:
+ user = session_user
+ else:
+ user = KeycloakUser(claims)
authz_token = AuthzToken(
accessToken=token,
claimsMap={'gatewayID': settings.GATEWAY_ID,