feat: Consolidate OAuth2 endpoints into auth module and remove redundant oauth file
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api.v1 import auth, main, oauth
|
||||
from app.api.v1 import auth, main
|
||||
|
||||
# V1 API router with v1 prefix
|
||||
api_router = APIRouter(prefix="/v1")
|
||||
@@ -10,4 +10,3 @@ api_router = APIRouter(prefix="/v1")
|
||||
# Include all route modules
|
||||
api_router.include_router(main.router, tags=["main"])
|
||||
api_router.include_router(auth.router, prefix="/auth", tags=["authentication"])
|
||||
api_router.include_router(oauth.router, prefix="/oauth", tags=["oauth"])
|
||||
|
||||
@@ -2,20 +2,27 @@
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Cookie, Depends, HTTPException, Response, status
|
||||
from fastapi import APIRouter, Cookie, Depends, HTTPException, Query, Response, status
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.dependencies import get_auth_service, get_current_active_user
|
||||
from app.core.dependencies import (
|
||||
get_auth_service,
|
||||
get_current_active_user,
|
||||
get_oauth_service,
|
||||
)
|
||||
from app.core.logging import get_logger
|
||||
from app.models.user import User
|
||||
from app.schemas.auth import UserLoginRequest, UserRegisterRequest, UserResponse
|
||||
from app.services.auth import AuthService
|
||||
from app.services.oauth import OAuthService
|
||||
from app.utils.auth import JWTUtils
|
||||
|
||||
router = APIRouter()
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
# Authentication endpoints
|
||||
@router.post(
|
||||
"/register",
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
@@ -224,3 +231,100 @@ async def logout(
|
||||
)
|
||||
|
||||
return {"message": "Successfully logged out"}
|
||||
|
||||
|
||||
# OAuth2 endpoints
|
||||
@router.get("/{provider}/authorize")
|
||||
async def oauth_authorize(
|
||||
provider: str,
|
||||
oauth_service: Annotated[OAuthService, Depends(get_oauth_service)],
|
||||
) -> dict[str, str]:
|
||||
"""Get OAuth authorization URL."""
|
||||
try:
|
||||
# Generate secure state parameter
|
||||
state = oauth_service.generate_state()
|
||||
|
||||
# Get authorization URL
|
||||
auth_url = oauth_service.get_authorization_url(provider, state)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.exception("OAuth authorization failed for provider: %s", provider)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="OAuth authorization failed",
|
||||
) from e
|
||||
else:
|
||||
return {
|
||||
"authorization_url": auth_url,
|
||||
"state": state,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{provider}/callback")
|
||||
async def oauth_callback(
|
||||
provider: str,
|
||||
response: Response,
|
||||
code: Annotated[str, Query()],
|
||||
oauth_service: Annotated[OAuthService, Depends(get_oauth_service)],
|
||||
auth_service: Annotated[AuthService, Depends(get_auth_service)],
|
||||
) -> RedirectResponse:
|
||||
"""Handle OAuth callback."""
|
||||
try:
|
||||
# Handle OAuth callback and get user info
|
||||
oauth_user_info = await oauth_service.handle_callback(provider, code)
|
||||
|
||||
# Perform OAuth login (link or create user)
|
||||
auth_response = await auth_service.oauth_login(oauth_user_info)
|
||||
|
||||
# Create and store refresh token
|
||||
user = await auth_service.get_current_user(auth_response.user.id)
|
||||
refresh_token = await auth_service.create_and_store_refresh_token(user)
|
||||
|
||||
# Set HTTP-only cookies for both tokens
|
||||
response.set_cookie(
|
||||
key="access_token",
|
||||
value=auth_response.token.access_token,
|
||||
max_age=auth_response.token.expires_in,
|
||||
httponly=True,
|
||||
secure=settings.COOKIE_SECURE,
|
||||
samesite=settings.COOKIE_SAMESITE,
|
||||
)
|
||||
response.set_cookie(
|
||||
key="refresh_token",
|
||||
value=refresh_token,
|
||||
max_age=settings.JWT_REFRESH_TOKEN_EXPIRE_DAYS * 24 * 60 * 60,
|
||||
httponly=True,
|
||||
secure=settings.COOKIE_SECURE,
|
||||
samesite=settings.COOKIE_SAMESITE,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"OAuth login successful for user: %s via %s",
|
||||
auth_response.user.email,
|
||||
provider,
|
||||
)
|
||||
|
||||
# Redirect back to frontend after successful authentication
|
||||
return RedirectResponse(
|
||||
url="http://localhost:8001/?auth=success",
|
||||
status_code=302,
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.exception("OAuth callback failed for provider: %s", provider)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="OAuth callback failed",
|
||||
) from e
|
||||
|
||||
|
||||
@router.get("/providers")
|
||||
async def get_oauth_providers() -> dict[str, list[str]]:
|
||||
"""Get list of available OAuth providers."""
|
||||
return {
|
||||
"providers": ["google", "github"],
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
"""OAuth2 authentication endpoints."""
|
||||
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Response, status
|
||||
from fastapi.responses import RedirectResponse
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.dependencies import get_auth_service, get_oauth_service
|
||||
from app.core.logging import get_logger
|
||||
from app.services.auth import AuthService
|
||||
from app.services.oauth import OAuthService
|
||||
|
||||
router = APIRouter()
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
@router.get("/{provider}/authorize")
|
||||
async def oauth_authorize(
|
||||
provider: str,
|
||||
oauth_service: Annotated[OAuthService, Depends(get_oauth_service)],
|
||||
) -> dict[str, str]:
|
||||
"""Get OAuth authorization URL."""
|
||||
try:
|
||||
# Generate secure state parameter
|
||||
state = oauth_service.generate_state()
|
||||
|
||||
# Get authorization URL
|
||||
auth_url = oauth_service.get_authorization_url(provider, state)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.exception("OAuth authorization failed for provider: %s", provider)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="OAuth authorization failed",
|
||||
) from e
|
||||
else:
|
||||
return {
|
||||
"authorization_url": auth_url,
|
||||
"state": state,
|
||||
}
|
||||
|
||||
|
||||
@router.get("/{provider}/callback")
|
||||
async def oauth_callback(
|
||||
provider: str,
|
||||
response: Response,
|
||||
code: Annotated[str, Query()],
|
||||
oauth_service: Annotated[OAuthService, Depends(get_oauth_service)],
|
||||
auth_service: Annotated[AuthService, Depends(get_auth_service)],
|
||||
) -> RedirectResponse:
|
||||
"""Handle OAuth callback."""
|
||||
try:
|
||||
# Handle OAuth callback and get user info
|
||||
oauth_user_info = await oauth_service.handle_callback(provider, code)
|
||||
|
||||
# Perform OAuth login (link or create user)
|
||||
auth_response = await auth_service.oauth_login(oauth_user_info)
|
||||
|
||||
# Create and store refresh token
|
||||
user = await auth_service.get_current_user(auth_response.user.id)
|
||||
refresh_token = await auth_service.create_and_store_refresh_token(user)
|
||||
|
||||
# Set HTTP-only cookies for both tokens
|
||||
response.set_cookie(
|
||||
key="access_token",
|
||||
value=auth_response.token.access_token,
|
||||
max_age=auth_response.token.expires_in,
|
||||
httponly=True,
|
||||
secure=settings.COOKIE_SECURE,
|
||||
samesite=settings.COOKIE_SAMESITE,
|
||||
)
|
||||
response.set_cookie(
|
||||
key="refresh_token",
|
||||
value=refresh_token,
|
||||
max_age=settings.JWT_REFRESH_TOKEN_EXPIRE_DAYS * 24 * 60 * 60,
|
||||
httponly=True,
|
||||
secure=settings.COOKIE_SECURE,
|
||||
samesite=settings.COOKIE_SAMESITE,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"OAuth login successful for user: %s via %s",
|
||||
auth_response.user.email,
|
||||
provider,
|
||||
)
|
||||
|
||||
# Redirect back to frontend after successful authentication
|
||||
return RedirectResponse(
|
||||
url="http://localhost:8001/?auth=success",
|
||||
status_code=302,
|
||||
)
|
||||
|
||||
except HTTPException:
|
||||
raise
|
||||
except Exception as e:
|
||||
logger.exception("OAuth callback failed for provider: %s", provider)
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail="OAuth callback failed",
|
||||
) from e
|
||||
|
||||
|
||||
@router.get("/providers")
|
||||
async def get_oauth_providers() -> dict[str, list[str]]:
|
||||
"""Get list of available OAuth providers."""
|
||||
return {
|
||||
"providers": ["google", "github"],
|
||||
}
|
||||
Reference in New Issue
Block a user