From 8284ccf05ebe8ec11da4d1a701fb7047369b214d Mon Sep 17 00:00:00 2001 From: "ahmed.mujtaba" Date: Fri, 11 Sep 2026 00:26:21 +0500 Subject: [PATCH] reversion --- backend/users/app.py | 25 ++++++++++++++++++++++--- backend/users/serializers.py | 18 +++++++++++++++--- frontend/src/lib/tokenStore.js | 10 +++++++++- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/backend/users/app.py b/backend/users/app.py index b540928..37ce910 100644 --- a/backend/users/app.py +++ b/backend/users/app.py @@ -8,6 +8,7 @@ from users.views import User from users.permissions import CurrentUser, PermissionTag, require_permission from users.serializers import serialize_token from users.plugins import create_access_token,create_refresh_token +from role.models import Roles from dotenv import load_dotenv load_dotenv() @@ -60,7 +61,13 @@ async def login(payload: UserLogin,session: AsyncSession = Depends(get_session)) try: service=User(session=session) user=await service.authenticate_user(payload.email or payload.username,payload.password) - tokens=serialize_token(create_access_token(user),create_refresh_token(user),user) + permissions=await Roles.resolve_tags(session,user.role) + tokens=serialize_token( + create_access_token(user), + create_refresh_token(user), + user, + permissions=permissions, + ) return JSONResponse(content={**tokens,"status_code":200}) except HTTPException: raise @@ -73,7 +80,13 @@ async def signup(payload: UserSignup,session: AsyncSession = Depends(get_session try: service=User(session=session) user=await service.signup_user(payload.model_dump()) - tokens=serialize_token(create_access_token(user),create_refresh_token(user),user) + permissions=await Roles.resolve_tags(session,user.role) + tokens=serialize_token( + create_access_token(user), + create_refresh_token(user), + user, + permissions=permissions, + ) return JSONResponse(content={**tokens,"status_code":200}) except HTTPException: raise @@ -86,7 +99,13 @@ async def refresh(payload: TokenRefresh,session: AsyncSession = Depends(get_sess try: service=User(session=session) user=await service.refresh_access_token(payload.refresh_token) - tokens=serialize_token(create_access_token(user),create_refresh_token(user),user) + permissions=await Roles.resolve_tags(session,user.role) + tokens=serialize_token( + create_access_token(user), + create_refresh_token(user), + user, + permissions=permissions, + ) return JSONResponse(content={**tokens,"status_code":200}) except HTTPException: raise diff --git a/backend/users/serializers.py b/backend/users/serializers.py index 4c89c0c..b594229 100644 --- a/backend/users/serializers.py +++ b/backend/users/serializers.py @@ -33,12 +33,24 @@ def serialize_user( return data -def serialize_token(access_token: str, refresh_token: str, user: Users) -> dict: - """Login/refresh payload. OAuth2 fields live at the root so Swagger's Authorize can read them.""" +def serialize_token( + access_token: str, + refresh_token: str, + user: Users, + *, + permissions: tuple[str, ...] | list[str] | None = None, +) -> dict: + """Login/refresh payload. OAuth2 fields live at the root so Swagger's Authorize can read them. + + Always include resolved permissions so the SPA can paint the nav before + GET /users/me returns (and so a stale localStorage role cannot linger). + """ return { "access_token": access_token, "refresh_token": refresh_token, "token_type": "bearer", "expires_in": ACCESS_TOKEN_EXPIRE_SECONDS, - "data": serialize_user(user), + "data": serialize_user( + user, with_permissions=True, permissions=permissions or () + ), } diff --git a/frontend/src/lib/tokenStore.js b/frontend/src/lib/tokenStore.js index 2852f6b..bf9fcf7 100644 --- a/frontend/src/lib/tokenStore.js +++ b/frontend/src/lib/tokenStore.js @@ -79,12 +79,20 @@ export function isExpiring(skew = CLOCK_SKEW_MS) { * mid-session. */ export function setSession(res) { + const incoming = res.data ?? {} + const prev = cached?.data ?? {} cached = { access_token: res.access_token, refresh_token: res.refresh_token, expires_in: res.expires_in, expires_at: Date.now() + (res.expires_in ?? 1800) * 1000, - data: { ...(cached?.data ?? {}), ...(res.data ?? {}) }, + // Keep prior permissions when a token response omits them (legacy refresh); + // when login/me includes permissions, those win. + data: { + ...prev, + ...incoming, + permissions: incoming.permissions ?? prev.permissions, + }, } persist() emit()