Working on: The Twitch authentication
This commit is contained in:
9
auth.py
9
auth.py
@@ -1,5 +1,6 @@
|
||||
import httpx
|
||||
import secrets
|
||||
import logging
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, Response
|
||||
from fastapi.responses import RedirectResponse
|
||||
from sqlalchemy.orm import Session
|
||||
@@ -11,6 +12,9 @@ import security
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Dependency to get a DB session
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
@@ -27,6 +31,7 @@ async def login_with_twitch(request: Request):
|
||||
# Generate a random state token for CSRF protection
|
||||
state = secrets.token_urlsafe(16)
|
||||
request.session['oauth_state'] = state
|
||||
logger.info(f"Generated OAuth state: {state} for session.")
|
||||
|
||||
# As per RESEARCH_REPORT.md, these are the minimum required scopes
|
||||
scopes = "chat:read"
|
||||
@@ -48,7 +53,9 @@ async def auth_twitch_callback(code: str, state: str, request: Request, db: Sess
|
||||
Step 2 of OAuth flow: Handle the callback from Twitch after user authorization.
|
||||
"""
|
||||
# CSRF Protection: Validate the state
|
||||
if state != request.session.pop('oauth_state', None):
|
||||
session_state = request.session.pop('oauth_state', None)
|
||||
if state != session_state:
|
||||
logger.error(f"OAuth state mismatch! Received state: '{state}', Session state: '{session_state}'")
|
||||
raise HTTPException(status_code=403, detail="Invalid state parameter. CSRF attack suspected.")
|
||||
|
||||
# Step 4: Exchange the authorization code for an access token
|
||||
|
||||
8
main.py
8
main.py
@@ -65,13 +65,13 @@ async def lifespan(app: FastAPI):
|
||||
|
||||
app = FastAPI(lifespan=lifespan)
|
||||
|
||||
# Add middleware to trust proxy headers (X-Forwarded-For, X-Forwarded-Proto)
|
||||
# This is crucial for running behind a reverse proxy like Nginx or Caddy.
|
||||
app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*")
|
||||
|
||||
# Add session middleware. A secret key is required for signing the session cookie.
|
||||
# We can reuse our encryption key for this, but in production you might want a separate key.
|
||||
# Note: Middleware is applied in reverse order (last added is first executed).
|
||||
# We want ProxyHeaders to run FIRST (outermost) to fix the scheme/host,
|
||||
# then SessionMiddleware to run SECOND (inner) so it sees the correct scheme.
|
||||
app.add_middleware(SessionMiddleware, secret_key=settings.ENCRYPTION_KEY)
|
||||
app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*")
|
||||
|
||||
# Mount the 'static' directory using an absolute path for reliability
|
||||
# This MUST be done before the routes that depend on it are defined.
|
||||
|
||||
Reference in New Issue
Block a user