fix: specific redirect codes for mobile
This commit is contained in:
1 parent
7ae137f865
commit
640bbea802
1 file changed
+25
-11
+25
-11
@@ -7,7 +7,7 @@ from fastapi import FastAPI, Header, HTTPException, Request, status
|
|||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.responses import FileResponse, RedirectResponse
|
from fastapi.responses import FileResponse, RedirectResponse
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import Annotated
|
from typing import Annotated, Optional
|
||||||
from . import myice
|
from . import myice
|
||||||
|
|
||||||
# OIDC Configuration
|
# OIDC Configuration
|
||||||
@@ -151,11 +151,10 @@ async def favico():
|
|||||||
|
|
||||||
|
|
||||||
@app.get("/login")
|
@app.get("/login")
|
||||||
async def login(request: Request):
|
async def login(request: Request, redirect_uri: Optional[str] = None):
|
||||||
"""Redirect to Infomaniak OIDC login"""
|
"""Redirect to Infomaniak OIDC login"""
|
||||||
import urllib.parse
|
|
||||||
|
|
||||||
import secrets
|
import secrets
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
state = secrets.token_urlsafe(32)
|
state = secrets.token_urlsafe(32)
|
||||||
nonce = secrets.token_urlsafe(32)
|
nonce = secrets.token_urlsafe(32)
|
||||||
@@ -196,6 +195,16 @@ async def login(request: Request):
|
|||||||
samesite="Lax",
|
samesite="Lax",
|
||||||
max_age=300,
|
max_age=300,
|
||||||
)
|
)
|
||||||
|
# Store target redirect URI (e.g. myice://callback) for mobile app flow
|
||||||
|
if redirect_uri:
|
||||||
|
response.set_cookie(
|
||||||
|
"oidc_target_redirect",
|
||||||
|
redirect_uri,
|
||||||
|
httponly=True,
|
||||||
|
secure=True,
|
||||||
|
samesite="Lax",
|
||||||
|
max_age=300,
|
||||||
|
)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@@ -204,12 +213,17 @@ async def callback(request: Request, code: str, state: str):
|
|||||||
"""Handle OIDC callback and exchange code for token"""
|
"""Handle OIDC callback and exchange code for token"""
|
||||||
expected_state = request.cookies.get("oidc_state")
|
expected_state = request.cookies.get("oidc_state")
|
||||||
code_verifier = request.cookies.get("oidc_verifier")
|
code_verifier = request.cookies.get("oidc_verifier")
|
||||||
|
# Determine final redirect target (mobile app or web frontend)
|
||||||
|
target_redirect = request.cookies.get("oidc_target_redirect") or os.environ.get(
|
||||||
|
"FRONTEND_URL", "/"
|
||||||
|
)
|
||||||
# We should also delete state/nonce cookies once read
|
# We should also delete state/nonce cookies once read
|
||||||
if not expected_state or state != expected_state:
|
if not expected_state or state != expected_state:
|
||||||
response = RedirectResponse("/?error=Invalid state parameter")
|
response = RedirectResponse(f"/{target_redirect}?error=Invalid state parameter")
|
||||||
response.delete_cookie("oidc_state")
|
response.delete_cookie("oidc_state")
|
||||||
response.delete_cookie("oidc_nonce")
|
response.delete_cookie("oidc_nonce")
|
||||||
response.delete_cookie("oidc_verifier")
|
response.delete_cookie("oidc_verifier")
|
||||||
|
response.delete_cookie("oidc_target_redirect")
|
||||||
return response
|
return response
|
||||||
# Exchange authorization code for access token
|
# Exchange authorization code for access token
|
||||||
token_data = {
|
token_data = {
|
||||||
@@ -227,14 +241,14 @@ async def callback(request: Request, code: str, state: str):
|
|||||||
# Log the error for debugging
|
# Log the error for debugging
|
||||||
logging.error("Token exchange failed: %s", token_response)
|
logging.error("Token exchange failed: %s", token_response)
|
||||||
# Redirect back to frontend with error
|
# Redirect back to frontend with error
|
||||||
frontend_url = os.environ.get("FRONTEND_URL", "/")
|
|
||||||
error_detail = token_response.get(
|
error_detail = token_response.get(
|
||||||
"error_description", "Failed to obtain access token"
|
"error_description", "Failed to obtain access token"
|
||||||
)
|
)
|
||||||
error_response = RedirectResponse(f"{frontend_url}?error={error_detail}")
|
error_response = RedirectResponse(f"{target_redirect}?error={error_detail}")
|
||||||
error_response.delete_cookie("oidc_state")
|
error_response.delete_cookie("oidc_state")
|
||||||
error_response.delete_cookie("oidc_nonce")
|
error_response.delete_cookie("oidc_nonce")
|
||||||
error_response.delete_cookie("oidc_verifier")
|
error_response.delete_cookie("oidc_verifier")
|
||||||
|
error_response.delete_cookie("oidc_target_redirect")
|
||||||
return error_response
|
return error_response
|
||||||
|
|
||||||
access_token = token_response["access_token"]
|
access_token = token_response["access_token"]
|
||||||
@@ -250,19 +264,19 @@ async def callback(request: Request, code: str, state: str):
|
|||||||
user_email = userinfo.get("email")
|
user_email = userinfo.get("email")
|
||||||
if ALLOWED_USERS and user_email not in ALLOWED_USERS:
|
if ALLOWED_USERS and user_email not in ALLOWED_USERS:
|
||||||
# Redirect back to frontend with error
|
# Redirect back to frontend with error
|
||||||
frontend_url = os.environ.get("FRONTEND_URL", "/")
|
response = RedirectResponse(f"{target_redirect}?error=User not authorized")
|
||||||
response = RedirectResponse(f"{frontend_url}?error=User not authorized")
|
|
||||||
response.delete_cookie("oidc_state")
|
response.delete_cookie("oidc_state")
|
||||||
response.delete_cookie("oidc_nonce")
|
response.delete_cookie("oidc_nonce")
|
||||||
response.delete_cookie("oidc_verifier")
|
response.delete_cookie("oidc_verifier")
|
||||||
|
response.delete_cookie("oidc_target_redirect")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
# Redirect back to frontend with access token and user info
|
# Redirect back to frontend with access token and user info
|
||||||
frontend_url = os.environ.get("FRONTEND_URL", "/")
|
response = RedirectResponse(f"{target_redirect}#access_token={access_token}")
|
||||||
response = RedirectResponse(f"{frontend_url}#access_token={access_token}")
|
|
||||||
response.delete_cookie("oidc_state")
|
response.delete_cookie("oidc_state")
|
||||||
response.delete_cookie("oidc_nonce")
|
response.delete_cookie("oidc_nonce")
|
||||||
response.delete_cookie("oidc_verifier")
|
response.delete_cookie("oidc_verifier")
|
||||||
|
response.delete_cookie("oidc_target_redirect")
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user