You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

86 lines
3.8 KiB

from services.log import access_logger as logger
from nicegui import app, ui
from fastapi import Request
from services.auth.oidc import oidc_config
import time
@ui.page('/auth/callback')
async def auth_callback(request: Request, code: str = None, state: str = None, error: str = None, redirect_to: str = "/") -> None:
logger.info(f"Auth callback received - code: {'present' if code else 'missing'}, state: {state}, error: {error}")
if error:
logger.error(f"Authentication error: {error}")
ui.notify(f'Authentication failed: {error}', color='negative')
ui.label(f'Authentication failed: {error}').classes('text-red-500')
#ui.navigate.to('/login')
return
if not code or not state:
logger.error(f"Missing callback parameters - code: {'present' if code else 'missing'}, state: {'present' if state else 'missing'}")
ui.notify('Invalid callback parameters', color='negative')
ui.label('Invalid callback parameters').classes('text-red-500')
#ui.navigate.to('/login')
return
# Verify state parameter to prevent CSRF attacks
stored_state = app.storage.user.get('oidc_state')
state = app.storage.user.get('oidc_state', 'not set')
# For debugging purposes, you can display the state parameter
ui.label(f'OIDC state: {state}')
if not stored_state or stored_state != state:
logger.error(f"State parameter mismatch - expected: {stored_state}, received: {state}")
ui.notify('Invalid state parameter', color='negative')
ui.label('Invalid state parameter').classes('text-red-500')
#ui.navigate.to('/login')
return
logger.info("State parameter verified successfully")
try:
# Exchange code for tokens
logger.info("Exchanging authorization code for tokens")
tokens = await oidc_config.exchange_code_for_tokens(code, redirect_uri=oidc_config.redirect_uri)
# Validate and decode ID token to get user info
logger.info("Validating ID token")
user_info = oidc_config.validate_token(tokens['id_token'])
if not user_info:
logger.error("Invalid ID token received")
ui.notify('Invalid ID token', color='negative')
#ui.navigate.to('/login')
return
app.storage.user['id_token'] = tokens['id_token']
logger.info("ID token validated successfully")
user_id = user_info.get('sub')
username = user_info.get('preferred_username', user_info.get('email', 'Unknown'))
email = user_info.get('email')
logger.info(f"User authenticated successfully - ID: {user_id}, Username: {username}, Email: {email}")
# Store user session
app.storage.user.update({
'username': username,
'email': email,
'user_id': user_id,
'authenticated': True,
'access_token': tokens['access_token'],
'refresh_token': tokens.get('refresh_token'),
'token_expires_at': time.time() + tokens.get('expires_in', 3600)
})
# Start token refresh timer
logger.info(f"Starting token refresh timer for user {user_id}")
# Redirect to original destination or home
redirect_to = app.storage.user.get('redirect_to', '/')
app.storage.user.pop('redirect_to', None) # Clean up
app.storage.user.pop('oidc_state', None) # Clean up
logger.info(f"Authentication complete for user {username}, redirecting to: {redirect_to}")
ui.navigate.to(redirect_to)
except Exception as e:
logger.error(f"Authentication failed with exception: {str(e)}", exc_info=True)
ui.notify(f'Authentication failed: {str(e)}', color='negative')
#ui.navigate.to('/login')