from IPython.display import MarkdownOAuth
See the docs page for an explanation of how to use this.
GoogleAppClient
def GoogleAppClient(
client_id, client_secret, code:NoneType=None, scope:NoneType=None, project_id:NoneType=None, **kwargs
):A WebApplicationClient for Google oauth2
GitHubAppClient
def GitHubAppClient(
client_id, client_secret, code:NoneType=None, scope:NoneType=None, **kwargs
):A WebApplicationClient for GitHub oauth2
HuggingFaceClient
def HuggingFaceClient(
client_id, client_secret, code:NoneType=None, scope:NoneType=None, state:NoneType=None, **kwargs
):A WebApplicationClient for HuggingFace oauth2
DiscordAppClient
def DiscordAppClient(
client_id, client_secret, is_user:bool=False, perms:int=0, scope:NoneType=None, **kwargs
):A WebApplicationClient for Discord oauth2
Auth0AppClient
def Auth0AppClient(
domain, client_id, client_secret, code:NoneType=None, scope:NoneType=None, redirect_uri:str='', **kwargs
):A WebApplicationClient for Auth0 OAuth2
Apple Sign In requires a few extra steps compared to other OAuth providers:
- Client secret is a JWT — Instead of a static secret, you generate a signed JWT using a private key from Apple
- Callback is POST, not GET — Apple sends the authorization code via form POST, so you need
redir_method='post' - User info is in the ID token — There’s no separate userinfo endpoint; you decode the JWT they return
See Apple’s Sign In documentation for details.
To use Apple Sign In, you’ll need credentials from the Apple Developer Portal:
- Team ID — Found in your Membership section
- App ID — Create under Identifiers → App IDs with “Sign in with Apple” capability enabled
- Service ID — Create under Identifiers → Services IDs, linked to your App ID (this becomes your
client_id) - Key ID — Create under Keys with “Sign in with Apple” enabled
- Private Key (.p8 file) — Downloaded when you create the key (you can only download it once!)
When configuring your Service ID, you’ll need to specify your domain and return URL (e.g., https://yourdomain.com/auth/callback). Note: Apple doesn’t accept localhost — use a real domain or a tunneling service like ngrok for local development. (I used a solveit public domain for easy prototyping)
AppleAppClient
def AppleAppClient(
client_id, key_id, team_id, private_key, code:NoneType=None, scope:NoneType=None, **kwargs
):A WebApplicationClient for Apple Sign In
# cli = GoogleAppClient.from_file('client_secret.json')WebApplicationClient.login_link
def login_link(
redirect_uri, scope:NoneType=None, state:NoneType=None, **kwargs
):Get a login link for this client
Generating a login link that sends the user to the OAuth provider is done with client.login_link().
It can sometimes be useful to pass state to the OAuth provider, so that when the user returns you can pick up where they left off. This can be done by passing the state parameter.
from fasthtml.jupyter import *redir_path = '/redirect'
port = 8000# app,rt = fast_app()
# server = JupyUvi(app, port=port)get_host
def get_host(
request
):Get the host, preferring X-Forwarded-Host if available
from types import SimpleNamespace
from urllib.parse import urlparsemock_request_localhost = SimpleNamespace(headers={}, url=SimpleNamespace(netloc='localhost:8000'))
mock_request_with_forward = SimpleNamespace(
headers={'x-forwarded-host': 'example.com'},
url=SimpleNamespace(netloc='localhost:8000', hostname='localhost')
)
print("Without X-Forwarded-Host:", get_host(mock_request_localhost))
print("With X-Forwarded-Host:", get_host(mock_request_with_forward))Without X-Forwarded-Host: localhost:8000
With X-Forwarded-Host: example.com
redir_url
def redir_url(
req, redir_path, scheme:NoneType=None
):Get the redir url for the host in request
@rt
def index(request):
redir = redir_url(request, redir_path)
return A('login', href=cli.login_link(redir), target='_blank')_AppClient.retr_info
def retr_info(
code, redirect_uri
):Combines parse_response and get_info
_AppClient.get_info
def get_info(
token:NoneType=None
):Get the info for authenticated user
_AppClient.parse_response
def parse_response(
code, redirect_uri
):Get the token from the oauth2 server response
_AppClient.retr_info_async
async def retr_info_async(
code, redirect_uri
):Combines parse_response and get_info
_AppClient.get_info_async
async def get_info_async(
token:NoneType=None
):Get the info for authenticated user
_AppClient.parse_response_async
async def parse_response_async(
code, redirect_uri
):Get the token from the oauth2 server response
@rt(redir_path)
def get(request, code:str):
redir = redir_url(request, redir_path)
info = cli.retr_info(code, redir)
return P(f'Login successful for {info["name"]}!')# HTMX()# server.stop()_AppClient.retr_id
def retr_id(
code, redirect_uri
):Call retr_info and then return id/subscriber value
After logging in via the provider, the user will be redirected back to the supplied redirect URL. The request to this URL will contain a code parameter, which is used to get an access token and fetch the user’s profile information. See the explanation here for a worked example. You can either:
- Use client.retr_info(code) to get all the profile information, or
- Use client.retr_id(code) to get just the user’s ID.
After either of these calls, you can also access the access token (used to revoke access, for example) with client.token["access_token"].
url_match
def url_match(
request, patterns:tuple=('^(localhost|127\\.0\\.0\\.1)(:\\d+)?$',)
):mock_request_prod = SimpleNamespace(headers={}, url=SimpleNamespace(netloc='myapp.com', hostname='myapp.com'))
print("Localhost:", redir_url(mock_request_localhost, '/redirect'))
print("With X-Forwarded-Host:", redir_url(mock_request_with_forward, '/redirect'))
print("Production:", redir_url(mock_request_prod, '/redirect'))Localhost: http://localhost:8000/redirect
With X-Forwarded-Host: https://example.com/redirect
Production: https://myapp.com/redirect
OAuth
def OAuth(
app, cli, skip:NoneType=None, redir_path:str='/redirect', error_path:str='/error', logout_path:str='/logout',
login_path:str='/login', https:bool=True, http_patterns:tuple=('^(localhost|127\\.0\\.0\\.1)(:\\d+)?$',),
redir_method:str='get'
):Google helpers
GoogleAppClient.consent_url
def consent_url(
proj:NoneType=None
):Get Google OAuth consent screen URL
GoogleAppClient.consent_url
def consent_url(
proj:NoneType=None
):Get Google OAuth consent screen URL
Credentials.update
def update():Refresh the credentials if they are expired, and return them
Credentials.update
def update():Refresh the credentials if they are expired, and return them
Credentials.save
def save(
fname
):Save credentials to fname
Credentials.save
def save(
fname
):Save credentials to fname
load_creds
def load_creds(
fname
):Load credentials from fname
GoogleAppClient.creds
def creds():Create Credentials from the client, refreshing if needed
GoogleAppClient.creds
def creds():Create Credentials from the client, refreshing if needed