routes.identity
Identity OAuth routes for token exchange.
Most OAuth providers (including GitHub, Google, Kaggle) don't support CORS on their token endpoints, so we need a backend proxy to exchange the authorization code for an access token.
Provider-specific notes:
- GitHub: Requires client_secret even with PKCE, returns errors as 200 with error body
- Google: Standard OAuth 2.1 with PKCE support
- Kaggle: Standard OAuth 2.1 with PKCE support
TokenExchangeRequest Objects
class TokenExchangeRequest(BaseModel)
Request body for OAuth token exchange.
TokenExchangeResponse Objects
class TokenExchangeResponse(BaseModel)
Response from OAuth token exchange.
get_client_id
def get_client_id(provider: str) -> str
Get client ID from environment variables.
get_client_secret
def get_client_secret(provider: str) -> Optional[str]
Get client secret from environment variables (optional for PKCE).
exchange_token
@router.post("/oauth/token", response_model=TokenExchangeResponse)
async def exchange_token(
request: TokenExchangeRequest) -> TokenExchangeResponse
Exchange an authorization code for an access token.
This endpoint proxies the token exchange to the OAuth provider, which is necessary because most providers don't support CORS.
For PKCE flows, the client_secret is optional - the code_verifier provides the security instead.
UserInfoRequest Objects
class UserInfoRequest(BaseModel)
Request body for fetching user info.
UserInfoResponse Objects
class UserInfoResponse(BaseModel)
Response from userinfo endpoint.
login
Username (GitHub calls it login)
raw
Full response from provider
get_userinfo
@router.post("/oauth/userinfo", response_model=UserInfoResponse)
async def get_userinfo(request: UserInfoRequest) -> UserInfoResponse
Fetch user information from the OAuth provider.
This endpoint proxies the userinfo request to the OAuth provider, normalizing the response into a common format.