72 lines
2.4 KiB
Python
72 lines
2.4 KiB
Python
"""OAuth provider helpers. Each provider exposes:
|
|
- exchange_code(code, redirect_uri) -> OAuthProfile
|
|
"""
|
|
from dataclasses import dataclass
|
|
|
|
import httpx
|
|
from app.core.config import settings
|
|
|
|
|
|
@dataclass
|
|
class OAuthProfile:
|
|
provider_subject: str
|
|
email: str
|
|
name: str
|
|
|
|
|
|
async def google_exchange_code(code: str, redirect_uri: str) -> OAuthProfile:
|
|
async with httpx.AsyncClient(timeout=10) as cli:
|
|
token_response = await cli.post(
|
|
"https://oauth2.googleapis.com/token",
|
|
data={
|
|
"code": code,
|
|
"client_id": settings.GOOGLE_CLIENT_ID,
|
|
"client_secret": settings.GOOGLE_CLIENT_SECRET,
|
|
"redirect_uri": redirect_uri,
|
|
"grant_type": "authorization_code",
|
|
},
|
|
)
|
|
token_response.raise_for_status()
|
|
access_token = token_response.json()["access_token"]
|
|
|
|
userinfo = await cli.get(
|
|
"https://openidconnect.googleapis.com/v1/userinfo",
|
|
headers={"Authorization": f"Bearer {access_token}"},
|
|
)
|
|
userinfo.raise_for_status()
|
|
data = userinfo.json()
|
|
return OAuthProfile(
|
|
provider_subject=data["sub"],
|
|
email=data["email"],
|
|
name=data.get("name") or data["email"].split("@")[0],
|
|
)
|
|
|
|
|
|
async def microsoft_exchange_code(code: str, redirect_uri: str) -> OAuthProfile:
|
|
async with httpx.AsyncClient(timeout=10) as cli:
|
|
token_response = await cli.post(
|
|
"https://login.microsoftonline.com/common/oauth2/v2.0/token",
|
|
data={
|
|
"code": code,
|
|
"client_id": settings.MS_CLIENT_ID,
|
|
"client_secret": settings.MS_CLIENT_SECRET,
|
|
"redirect_uri": redirect_uri,
|
|
"grant_type": "authorization_code",
|
|
"scope": "openid email profile",
|
|
},
|
|
)
|
|
token_response.raise_for_status()
|
|
access_token = token_response.json()["access_token"]
|
|
|
|
userinfo = await cli.get(
|
|
"https://graph.microsoft.com/v1.0/me",
|
|
headers={"Authorization": f"Bearer {access_token}"},
|
|
)
|
|
userinfo.raise_for_status()
|
|
data = userinfo.json()
|
|
return OAuthProfile(
|
|
provider_subject=data["id"],
|
|
email=data.get("mail") or data["userPrincipalName"],
|
|
name=data.get("displayName") or data["userPrincipalName"].split("@")[0],
|
|
)
|