feat: add refresh

This commit is contained in:
2026-06-05 12:41:25 +03:00
parent d300d2eabe
commit 9d3c5b401a
8 changed files with 175 additions and 50 deletions

View File

@@ -4,38 +4,17 @@ from starlette import status
from src.application.commands import AdminJwtRefreshCommand
from src.application.domain.exceptions import ApplicationException, RefreshConcurrentException
from src.infrastructure.config import settings
from src.presentation.auth_cookies import clear_auth_cookies, set_auth_cookies
from src.presentation.dependencies.commands import get_admin_jwt_refresh_command
jwt_router = APIRouter(prefix='/jwt', tags=['jwt'])
def _clear_auth_cookies(response: ORJSONResponse) -> None:
response.delete_cookie('access_token', path='/', domain=settings.ADMIN_COOKIE_DOMAIN)
response.delete_cookie('refresh_token', path='/', domain=settings.ADMIN_COOKIE_DOMAIN)
def _set_auth_cookies(response: ORJSONResponse, access: str, refresh: str) -> None:
response.set_cookie(
key='access_token',
value=access,
httponly=True,
secure=settings.ADMIN_COOKIE_SECURE,
samesite='lax',
path='/',
domain=settings.ADMIN_COOKIE_DOMAIN,
max_age=int(settings.JWT_ACCESS_TTL_SECONDS),
)
response.set_cookie(
key='refresh_token',
value=refresh,
httponly=True,
secure=settings.ADMIN_COOKIE_SECURE,
samesite='lax',
path='/',
domain=settings.ADMIN_COOKIE_DOMAIN,
max_age=int(settings.JWT_REFRESH_TTL_SECONDS),
)
def _client_ip(request: Request) -> str | None:
xff = request.headers.get('x-forwarded-for')
if xff:
return xff.split(',')[0].strip()
return request.client.host if request.client else None
@jwt_router.post('/refresh', response_class=ORJSONResponse, status_code=status.HTTP_200_OK)
@@ -45,26 +24,26 @@ async def refresh_tokens(
):
refresh_token = request.cookies.get('refresh_token')
if not refresh_token:
response = ORJSONResponse({'ok': False, 'error': 'No refresh token'}, status_code=401)
_clear_auth_cookies(response)
response = ORJSONResponse({'result': False, 'error': 'No refresh token'}, status_code=401)
clear_auth_cookies(response)
return response
xff = request.headers.get('x-forwarded-for')
ip = xff.split(',')[0].strip() if xff else (request.client.host if request.client else None)
user_agent = request.headers.get('user-agent')
try:
tokens = await command(refresh_token=refresh_token, ip=ip, user_agent=user_agent)
tokens = await command(
refresh_token=refresh_token,
ip=_client_ip(request),
user_agent=request.headers.get('user-agent'),
)
except RefreshConcurrentException:
return ORJSONResponse({'result': True, 'concurrent': True}, status_code=status.HTTP_200_OK)
except ApplicationException as exc:
if exc.status_code == status.HTTP_401_UNAUTHORIZED:
response = ORJSONResponse({'result': False}, status_code=401)
_clear_auth_cookies(response)
clear_auth_cookies(response)
return response
raise
access, refresh = tokens
response = ORJSONResponse({'result': True})
_set_auth_cookies(response, access, refresh)
set_auth_cookies(response, access, refresh)
return response