Added cognito authentication - Fix 5
Some checks failed
AWS Deploy on Push / build (push) Failing after 1m0s

This commit is contained in:
2025-05-15 16:24:37 -05:00
parent 38e5a94701
commit 7f282049ac
3 changed files with 30 additions and 25 deletions

View File

@@ -2,7 +2,7 @@ import os
import boto3 import boto3
import requests import requests
import jwt import jwt
from fastapi import Depends, HTTPException, status from fastapi import Depends, HTTPException, status, Request
from fastapi.security import OAuth2AuthorizationCodeBearer from fastapi.security import OAuth2AuthorizationCodeBearer
from fastapi.responses import RedirectResponse from fastapi.responses import RedirectResponse
@@ -10,42 +10,47 @@ REGION = "us-east-2"
USER_POOL_ID = os.getenv("COGNITO_USER_POOL_ID") USER_POOL_ID = os.getenv("COGNITO_USER_POOL_ID")
CLIENT_ID = os.getenv("COGNITO_CLIENT_ID") CLIENT_ID = os.getenv("COGNITO_CLIENT_ID")
DOMAIN = f"https://iptv-updater.auth.{REGION}.amazoncognito.com" DOMAIN = f"https://iptv-updater.auth.{REGION}.amazoncognito.com"
REDIRECT_URI = f"http://localhost:8000/auth/callback"
oauth2_scheme = OAuth2AuthorizationCodeBearer( # Remove the hardcoded REDIRECT_URI, we'll make it dynamic based on the request
class DynamicOAuth2(OAuth2AuthorizationCodeBearer):
async def __call__(self, request: Request):
self.redirect_uri = str(request.base_url) + "auth/callback"
return await super().__call__(request)
oauth2_scheme = DynamicOAuth2(
authorizationUrl=f"{DOMAIN}/oauth2/authorize", authorizationUrl=f"{DOMAIN}/oauth2/authorize",
tokenUrl=f"{DOMAIN}/oauth2/token" tokenUrl=f"{DOMAIN}/oauth2/token"
) )
def exchange_code_for_token(code: str): def exchange_code_for_token(code: str, redirect_uri: str):
token_url = f"{DOMAIN}/oauth2/token" token_url = f"{DOMAIN}/oauth2/token"
data = { data = {
'grant_type': 'authorization_code', 'grant_type': 'authorization_code',
'client_id': CLIENT_ID, 'client_id': CLIENT_ID,
'code': code, 'code': code,
'redirect_uri': REDIRECT_URI 'redirect_uri': redirect_uri
} }
response = requests.post(token_url, data=data) response = requests.post(token_url, data=data)
if response.status_code == 200: if response.status_code == 200:
return response.json() return response.json()
print(f"Token exchange failed: {response.text}") # Add logging print(f"Token exchange failed: {response.text}")
raise HTTPException(status_code=400, detail="Failed to exchange code for token") raise HTTPException(status_code=400, detail="Failed to exchange code for token")
async def get_current_user(token: str = Depends(oauth2_scheme)): async def get_current_user(request: Request, token: str = Depends(oauth2_scheme)):
if not token: if not token:
redirect_uri = str(request.base_url) + "auth/callback"
return RedirectResponse( return RedirectResponse(
f"{DOMAIN}/login?client_id={CLIENT_ID}" f"{DOMAIN}/login?client_id={CLIENT_ID}"
f"&response_type=code" f"&response_type=code"
f"&scope=openid+email+profile" # Added more scopes f"&scope=openid+email+profile"
f"&redirect_uri={REDIRECT_URI}" f"&redirect_uri={redirect_uri}"
) )
try: try:
# Decode JWT token instead of using get_user
decoded = jwt.decode( decoded = jwt.decode(
token, token,
options={"verify_signature": False} # We trust tokens from Cognito options={"verify_signature": False}
) )
return { return {
"Username": decoded.get("email") or decoded.get("sub"), "Username": decoded.get("email") or decoded.get("sub"),
@@ -55,7 +60,7 @@ async def get_current_user(token: str = Depends(oauth2_scheme)):
] ]
} }
except Exception as e: except Exception as e:
print(f"Token verification failed: {str(e)}") # Add logging print(f"Token verification failed: {str(e)}")
raise HTTPException( raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials", detail="Invalid authentication credentials",

View File

@@ -1,6 +1,6 @@
from fastapi import FastAPI, Depends, HTTPException from fastapi import FastAPI, Depends, HTTPException, Request
from fastapi.responses import JSONResponse, RedirectResponse from fastapi.responses import RedirectResponse, JSONResponse
from app.cabletv.utils.auth import exchange_code_for_token, get_current_user, DOMAIN, CLIENT_ID from app.cabletv.utils.auth import get_current_user, exchange_code_for_token
app = FastAPI() app = FastAPI()
@@ -9,26 +9,25 @@ async def root():
return {"message": "IPTV Updater API"} return {"message": "IPTV Updater API"}
@app.get("/protected") @app.get("/protected")
async def protected_route(user = Depends(get_current_user)): async def protected_route(request: Request, user = Depends(get_current_user)):
if isinstance(user, RedirectResponse): if isinstance(user, RedirectResponse):
return user return user
return {"message": "Protected content", "user": user['Username']} return {"message": "Protected content", "user": user['Username']}
@app.get("/auth/callback") @app.get("/auth/callback")
async def auth_callback(code: str): async def auth_callback(request: Request, code: str):
try: try:
tokens = exchange_code_for_token(code) redirect_uri = str(request.base_url)
tokens = exchange_code_for_token(code, redirect_uri)
# Use id_token instead of access_token
response = JSONResponse(content={ response = JSONResponse(content={
"message": "Authentication successful", "message": "Authentication successful",
"id_token": tokens["id_token"] # Changed from access_token "id_token": tokens["id_token"]
}) })
# Store id_token in cookie
response.set_cookie( response.set_cookie(
key="token", key="token",
value=tokens["id_token"], # Changed from access_token value=tokens["id_token"],
httponly=True, httponly=True,
secure=True, secure=True,
samesite="lax" samesite="lax"

View File

@@ -124,9 +124,10 @@ class IptvUpdaterStack(Stack):
), ),
scopes=[cognito.OAuthScope.OPENID], scopes=[cognito.OAuthScope.OPENID],
callback_urls=[ callback_urls=[
"http://localhost:8000/auth/callback", # For local testing "http://localhost:8000/auth/callback", # For local testing
"https://*.amazonaws.com/auth/callback" # Will match EC2 public DNS "http://*.amazonaws.com/auth/callback", # EC2 public DNS
] "http://*.compute.amazonaws.com/auth/callback" # EC2 full domain
]
) )
) )