136 lines
No EOL
3.8 KiB
Python
136 lines
No EOL
3.8 KiB
Python
"""
|
|
Authentication API endpoints
|
|
"""
|
|
|
|
import logging
|
|
from quart import Blueprint, jsonify, request
|
|
|
|
from ..auth.msal_auth import msal_auth
|
|
from ..auth.middleware import dev_mode_bypass, get_current_user
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
auth_bp = Blueprint('auth', __name__, url_prefix='/api/auth')
|
|
|
|
@auth_bp.route('/config', methods=['GET'])
|
|
async def get_auth_config():
|
|
"""
|
|
Get authentication configuration for frontend
|
|
|
|
Returns client configuration needed for MSAL setup
|
|
"""
|
|
try:
|
|
config = msal_auth.get_client_config()
|
|
return jsonify({
|
|
'config': config,
|
|
'devMode': msal_auth.is_dev_mode()
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to get auth config: {e}")
|
|
return jsonify({
|
|
'error': 'configuration_error',
|
|
'message': 'Failed to retrieve authentication configuration'
|
|
}), 500
|
|
|
|
@auth_bp.route('/validate', methods=['POST'])
|
|
async def validate_token():
|
|
"""
|
|
Validate an access token and return user information
|
|
|
|
Expects: { "accessToken": "jwt-token" }
|
|
Returns: User information if valid
|
|
"""
|
|
try:
|
|
data = await request.get_json()
|
|
access_token = data.get('accessToken')
|
|
|
|
if not access_token:
|
|
return jsonify({
|
|
'error': 'invalid_request',
|
|
'message': 'Access token required'
|
|
}), 400
|
|
|
|
# Validate token
|
|
user_info = await msal_auth.validate_token(access_token)
|
|
|
|
if user_info:
|
|
return jsonify({
|
|
'valid': True,
|
|
'user': {
|
|
'id': user_info['oid'],
|
|
'username': user_info.get('preferred_username'),
|
|
'name': user_info.get('name'),
|
|
'roles': user_info.get('roles', ['user'])
|
|
}
|
|
})
|
|
else:
|
|
return jsonify({
|
|
'valid': False,
|
|
'error': 'invalid_token',
|
|
'message': 'Token is invalid or expired'
|
|
}), 401
|
|
|
|
except Exception as e:
|
|
logger.error(f"Token validation error: {e}")
|
|
return jsonify({
|
|
'error': 'validation_error',
|
|
'message': 'Failed to validate token'
|
|
}), 500
|
|
|
|
@auth_bp.route('/user', methods=['GET'])
|
|
@dev_mode_bypass
|
|
async def get_current_user_info():
|
|
"""
|
|
Get current authenticated user information
|
|
|
|
Returns current user details from token
|
|
"""
|
|
try:
|
|
user = await get_current_user()
|
|
|
|
if user:
|
|
return jsonify({
|
|
'user': {
|
|
'id': user['oid'],
|
|
'username': user.get('preferred_username'),
|
|
'name': user.get('name'),
|
|
'roles': user.get('roles', ['user'])
|
|
}
|
|
})
|
|
else:
|
|
return jsonify({
|
|
'error': 'unauthorized',
|
|
'message': 'No valid authentication found'
|
|
}), 401
|
|
|
|
except Exception as e:
|
|
logger.error(f"Failed to get user info: {e}")
|
|
return jsonify({
|
|
'error': 'server_error',
|
|
'message': 'Failed to retrieve user information'
|
|
}), 500
|
|
|
|
@auth_bp.route('/logout', methods=['POST'])
|
|
async def logout():
|
|
"""
|
|
Get logout URL for proper session termination
|
|
|
|
Returns logout URL for frontend redirect
|
|
"""
|
|
try:
|
|
data = await request.get_json() or {}
|
|
redirect_uri = data.get('redirectUri')
|
|
|
|
logout_url = await msal_auth.get_logout_url(redirect_uri)
|
|
|
|
return jsonify({
|
|
'logoutUrl': logout_url
|
|
})
|
|
|
|
except Exception as e:
|
|
logger.error(f"Logout error: {e}")
|
|
return jsonify({
|
|
'error': 'logout_error',
|
|
'message': 'Failed to generate logout URL'
|
|
}), 500 |