initial commit
This commit is contained in:
91
backend/src/service.py
Normal file
91
backend/src/service.py
Normal file
@@ -0,0 +1,91 @@
|
||||
from fastapi import HTTPException, status, Request
|
||||
from keycloak.exceptions import KeycloakAuthenticationError, KeycloakPostError
|
||||
from keycloak import KeycloakOpenID
|
||||
from src.config import get_settings
|
||||
from src.models import UserInfo
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
settings = get_settings()
|
||||
|
||||
# Create a fresh KeycloakOpenID instance for token exchange
|
||||
def get_keycloak_openid():
|
||||
return KeycloakOpenID(
|
||||
server_url=settings.keycloak_server_url,
|
||||
realm_name=settings.keycloak_realm,
|
||||
client_id=settings.keycloak_client_id,
|
||||
client_secret_key=settings.keycloak_client_secret,
|
||||
verify=False
|
||||
)
|
||||
|
||||
|
||||
class AuthService:
|
||||
@staticmethod
|
||||
def authenticate_user(keycode: str, request: Request) -> str:
|
||||
"""
|
||||
Authenticate the user using Keycloak and return an access token.
|
||||
"""
|
||||
try:
|
||||
# Use the same redirect_uri that was used in the login endpoint
|
||||
redirect_uri = f"{settings.frontend_url}/api/callback"
|
||||
|
||||
logger.info(f"=== Token Exchange Debug ===")
|
||||
logger.info(f"Keycloak Server URL: {settings.keycloak_server_url}")
|
||||
logger.info(f"Realm: {settings.keycloak_realm}")
|
||||
logger.info(f"Client ID: {settings.keycloak_client_id}")
|
||||
logger.info(f"Client Secret (first 5 chars): {settings.keycloak_client_secret[:5]}...")
|
||||
logger.info(f"Redirect URI: {redirect_uri}")
|
||||
logger.info(f"Auth Code (first 10 chars): {keycode[:10]}...")
|
||||
|
||||
# Get fresh KeycloakOpenID instance
|
||||
keycloak_openid = get_keycloak_openid()
|
||||
|
||||
token = keycloak_openid.token(
|
||||
grant_type='authorization_code',
|
||||
code=keycode,
|
||||
redirect_uri=redirect_uri,
|
||||
)
|
||||
logger.info("Token exchange successful")
|
||||
return token["access_token"]
|
||||
except KeycloakAuthenticationError as exc:
|
||||
logger.error(f"KeycloakAuthenticationError: {exc}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail=f"Invalid Login: {str(exc)}",
|
||||
) from exc
|
||||
except KeycloakPostError as exc:
|
||||
logger.error(f"KeycloakPostError: {exc}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"Invalid Grant: {str(exc)}",
|
||||
) from exc
|
||||
except Exception as exc:
|
||||
logger.error(f"Unexpected error during token exchange: {exc}")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Token exchange failed: {str(exc)}",
|
||||
) from exc
|
||||
|
||||
@staticmethod
|
||||
def verify_token(token: str) -> UserInfo:
|
||||
"""
|
||||
Verify the given token and return user information.
|
||||
"""
|
||||
try:
|
||||
keycloak_openid = get_keycloak_openid()
|
||||
user_info = keycloak_openid.userinfo(token)
|
||||
print(user_info)
|
||||
if not user_info:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token"
|
||||
)
|
||||
return UserInfo(
|
||||
preferred_username=user_info["preferred_username"],
|
||||
email=user_info.get("email"),
|
||||
full_name=user_info.get("name"),
|
||||
)
|
||||
except KeycloakAuthenticationError as exc:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Could not validate credentials",
|
||||
) from exc
|
||||
Reference in New Issue
Block a user