diff --git a/be/app/api/auth/oauth.py b/be/app/api/auth/oauth.py index a610429..0276c60 100644 --- a/be/app/api/auth/oauth.py +++ b/be/app/api/auth/oauth.py @@ -4,7 +4,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from app.database import get_transactional_session from app.models import User -from app.auth import oauth, fastapi_users, auth_backend, get_jwt_strategy, get_refresh_jwt_strategy +from app.auth import oauth, fastapi_users, auth_backend, get_jwt_strategy, get_refresh_jwt_strategy, get_user_manager from app.config import settings from fastapi.security import OAuth2PasswordRequestForm @@ -88,16 +88,33 @@ async def apple_callback(request: Request, db: AsyncSession = Depends(get_transa return RedirectResponse(url=redirect_url) @router.post('/jwt/refresh') -async def refresh_jwt_token(request: Request): +async def refresh_jwt_token( + request: Request, + user_manager=Depends(get_user_manager), +): + """Refresh the JWT access token using a valid refresh token. + + The incoming request must provide a JSON body with a ``refresh_token`` field. + A new access and refresh token pair will be returned when the provided refresh + token is valid. If the token is invalid or expired, a *401* error is raised. + """ + data = await request.json() refresh_token = data.get('refresh_token') + if not refresh_token: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Missing refresh token") refresh_strategy = get_refresh_jwt_strategy() + try: - user = await refresh_strategy.read_token(refresh_token, None) + # ``read_token`` needs a callback capable of loading the *User* from the + # database. We therefore pass the user manager obtained via dependency + # injection so that the strategy can hydrate the full *User* instance. + user = await refresh_strategy.read_token(refresh_token, user_manager) except Exception: + # Any error during decoding or lookup should result in an unauthorized + # response to avoid leaking information about token validity. raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid refresh token") if not user: @@ -106,6 +123,7 @@ async def refresh_jwt_token(request: Request): access_strategy = get_jwt_strategy() access_token = await access_strategy.write_token(user) new_refresh_token = await refresh_strategy.write_token(user) + return JSONResponse({ "access_token": access_token, "refresh_token": new_refresh_token,