Implement OAuth login with Authentik integration, update user management, and enhance team functionalities
- Added OAuth login functionality using Authentik, allowing users to log in via OpenID. - Updated user registration and login processes to handle OAuth users. - Enhanced team management features, including joining and leaving teams, and displaying user-specific team information. - Improved error handling and user feedback for team actions. - Added new database migrations for OAuth-related fields in the users table. - Updated templates to reflect changes in user authentication and team management. - Refactored dashboard and leaderboard views to include user context and team memberships.
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
import os
|
||||
from httpx_oauth.clients.openid import OpenID
|
||||
from httpx_oauth.oauth2 import GetAccessTokenError
|
||||
from fastapi import HTTPException, Request
|
||||
from starlette.responses import RedirectResponse
|
||||
from typing import Optional, Dict, Any
|
||||
import json
|
||||
import httpx
|
||||
from urllib.parse import urlencode
|
||||
|
||||
class AuthentikOAuth:
|
||||
def __init__(self):
|
||||
self.client_id = os.getenv("AUTHENTIK_CLIENT_ID", "dRXLBdTdG6JSHqkcM0ZQBPwBVMBrG6SF32LZ1XAT")
|
||||
self.client_secret = os.getenv("AUTHENTIK_CLIENT_SECRET",
|
||||
"hn1aKecLeYj1tVc7QtsavrWjSOF4t7Ty1akVTmUqvIFJF1y0H3Myv7InUxAX6E2GLpMxxhhZZ2aUSJ9VEQz7zGcMbgUeMStxx2U7bEQxmuOGjZf0XJbOBGjdwGZYJlz7")
|
||||
self.config_url = os.getenv("AUTHENTIK_CONFIG_URL",
|
||||
"https://authentik.hosterra.net/application/o/leagueledger/.well-known/openid-configuration")
|
||||
self.client = None
|
||||
self.initialize_client()
|
||||
|
||||
def initialize_client(self):
|
||||
try:
|
||||
self.client = OpenID(
|
||||
client_id=self.client_id,
|
||||
client_secret=self.client_secret,
|
||||
openid_configuration_endpoint=self.config_url,
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Error initializing Authentik OAuth client: {str(e)}")
|
||||
self.client = None
|
||||
|
||||
async def get_login_url(self, request: Request, redirect_uri: str) -> str:
|
||||
if not self.client:
|
||||
self.initialize_client()
|
||||
|
||||
if not self.client:
|
||||
raise HTTPException(status_code=500, detail="OAuth client could not be initialized")
|
||||
|
||||
try:
|
||||
authorization_url = await self.client.get_authorization_url(
|
||||
redirect_uri=redirect_uri,
|
||||
scope=["openid", "email", "profile"],
|
||||
state=str(request.session.get("session_id", "")),
|
||||
)
|
||||
return authorization_url
|
||||
except Exception as e:
|
||||
print(f"Error getting authorization URL: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"OAuth error: {str(e)}")
|
||||
|
||||
async def get_user_info(self, request: Request, redirect_uri: str, code: str) -> Dict[str, Any]:
|
||||
if not self.client:
|
||||
self.initialize_client()
|
||||
|
||||
if not self.client:
|
||||
raise HTTPException(status_code=500, detail="OAuth client could not be initialized")
|
||||
|
||||
try:
|
||||
# Exchange code for token
|
||||
token = await self.client.get_access_token(
|
||||
code=code,
|
||||
redirect_uri=redirect_uri,
|
||||
)
|
||||
|
||||
access_token = token.get("access_token")
|
||||
if not access_token:
|
||||
raise HTTPException(status_code=400, detail="Could not get access token")
|
||||
|
||||
# Get user info from OpenID userinfo endpoint
|
||||
async with httpx.AsyncClient() as client:
|
||||
# Get the configuration to find the userinfo_endpoint
|
||||
config_response = await client.get(self.config_url)
|
||||
if config_response.status_code != 200:
|
||||
raise HTTPException(status_code=500, detail="Could not fetch OpenID configuration")
|
||||
|
||||
config = config_response.json()
|
||||
userinfo_endpoint = config.get("userinfo_endpoint")
|
||||
|
||||
if not userinfo_endpoint:
|
||||
raise HTTPException(status_code=500, detail="UserInfo endpoint not found in OpenID configuration")
|
||||
|
||||
# Make request to userinfo endpoint
|
||||
headers = {"Authorization": f"Bearer {access_token}"}
|
||||
user_response = await client.get(userinfo_endpoint, headers=headers)
|
||||
|
||||
if user_response.status_code != 200:
|
||||
raise HTTPException(status_code=500, detail=f"Error fetching user info: {user_response.text}")
|
||||
|
||||
return user_response.json()
|
||||
|
||||
except GetAccessTokenError as e:
|
||||
error_description = e.args[0]
|
||||
raise HTTPException(status_code=400, detail=f"OAuth error: {error_description}")
|
||||
except Exception as e:
|
||||
print(f"Error getting user info: {str(e)}")
|
||||
raise HTTPException(status_code=500, detail=f"OAuth error: {str(e)}")
|
||||
|
||||
# Instantiate the OAuth client for the application to use
|
||||
authentik_oauth = AuthentikOAuth()
|
||||
Reference in New Issue
Block a user