Source code for aiohttp_tiny_mcp.oauth.github
"""GitHub.com OAuth App configuration and stable user identity lookup."""
from __future__ import annotations
from collections.abc import Sequence
from typing import Any
from aiohttp import ClientSession
from .provider import Identity, OAuthProvider, UpstreamAuthError, provider_json
async def github_identity(tokens: dict[str, Any], http: ClientSession) -> Identity:
data = await provider_json(
http,
"GET",
"https://api.github.com/user",
headers={
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {tokens['access_token']}",
"User-Agent": "aiohttp-tiny-mcp",
},
)
if type(data.get("id")) is not int or data["id"] <= 0 or not isinstance(data.get("login"), str):
raise UpstreamAuthError("GitHub returned no valid user identity.")
return Identity(
sub=str(data["id"]),
provider="github",
claims={key: data.get(key) for key in ("login", "name", "email")},
)
[docs]
def GitHub(
client_id: str, client_secret: str, *, scopes: Sequence[str] = ("read:user",)
) -> OAuthProvider:
"""GitHub.com OAuth App sign-in. Register the server's callback URL in GitHub."""
if not client_secret:
raise ValueError("the GitHub client secret is required")
return OAuthProvider(
name="GitHub",
authorize_url="https://github.com/login/oauth/authorize",
token_url="https://github.com/login/oauth/access_token",
client_id=client_id,
client_secret=client_secret,
scopes=tuple(scopes),
profile=github_identity,
)
__all__ = ["GitHub"]