Skip to main content

Client library for utpd-oauth service with framework integrations

Project description

utpd-oauth-client

Client library for the utpd-oauth service, with framework integrations for FastAPI and NiceGUI.

Installation

uv add utpd-oauth-client

The only dependency is httpx. Framework integrations assume you already have the relevant framework installed.

Usage

Core Client (Framework-Agnostic)

The core client works anywhere - scripts, CLI tools, any web framework:

from utpd_oauth_client import OAuthClient

client = OAuthClient("https://utpd-oauth.ward.au")

# Step 1: Get the URL to redirect users to
login_url = client.login_url("https://myapp.com/auth/callback")
# -> "https://utpd-oauth.ward.au/login?next_url=https%3A%2F%2Fmyapp.com%2Fauth%2Fcallback"

# Step 2: After OAuth completes, exchange the token_code for an access_token
access_token = await client.exchange(token_code)

FastAPI Integration

The FastAPI integration provides a router factory that handles the OAuth redirect flow:

from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse
from starlette.responses import Response

from utpd_oauth_client import OAuthClient
from utpd_oauth_client.fastapi import create_auth_router

app = FastAPI()
client = OAuthClient(settings.oauth_service_url)


async def handle_token(token: str, request: Request) -> Response:
    """Called after successful OAuth with the access_token."""
    # Store token, create session, look up user, etc.
    request.session["access_token"] = token
    return RedirectResponse("/")


router = create_auth_router(
    client=client,
    public_base_url=settings.public_base_url,  # e.g. "https://myapp.com"
    on_token=handle_token,
)
app.include_router(router)

This creates two endpoints:

  • GET /auth/start - Redirects user to utpd-oauth to begin the flow
  • GET /auth/callback - Receives the token_code, exchanges it, calls your handler

NiceGUI Integration

The NiceGUI integration adds OAuth routes to your NiceGUI app:

import os

from nicegui import app, ui
from starlette.requests import Request
from starlette.responses import RedirectResponse, Response

from utpd_oauth_client import OAuthClient
from utpd_oauth_client.nicegui import setup_oauth_routes

client = OAuthClient(os.getenv("OAUTH_SERVICE_URL"))


async def handle_token(token: str, request: Request) -> Response:
    """Called after successful OAuth with the access_token."""
    app.storage.user["access_token"] = token
    app.storage.user["authenticated"] = True
    return RedirectResponse("/")


setup_oauth_routes(
    app=app,
    client=client,
    public_base_url=os.getenv("PUBLIC_BASE_URL"),
    on_token=handle_token,
)


@ui.page("/")
def main_page() -> None:
    if not app.storage.user.get("authenticated"):
        ui.link("Login with Untappd", "/auth/start")
    else:
        ui.label(f"Welcome! Your token: {app.storage.user.get('access_token', '')[:10]}...")

Configuration

Both integrations accept these parameters:

Parameter Default Description
client required OAuthClient instance
public_base_url required Your app's public URL (for callback)
on_token required Async callback receiving (token, request)
start_path /auth/start Path for the "begin OAuth" endpoint
callback_path /auth/callback Path for the callback endpoint
error_handler None Optional async callback for handling errors

Error Handling

The client raises TokenExchangeError when the exchange fails:

from utpd_oauth_client import OAuthClient, TokenExchangeError

client = OAuthClient("https://utpd-oauth.ward.au")

try:
    token = await client.exchange(token_code)
except TokenExchangeError as e:
    print(f"Exchange failed: {e}")
    print(f"Status code: {e.status_code}")
    print(f"Detail: {e.detail}")

For framework integrations, you can provide a custom error handler:

async def handle_error(exc: TokenExchangeError, request: Request) -> Response:
    # Log the error, show a friendly message, etc.
    return RedirectResponse("/login?error=oauth_failed")


router = create_auth_router(
    client=client,
    public_base_url=settings.public_base_url,
    on_token=handle_token,
    error_handler=handle_error,
)

Development

cd utpd-oauth-client
uv sync --all-groups
uv run pytest

Sequence Diagram

sequenceDiagram
    participant User
    participant YourApp
    participant utpd-oauth-client
    participant utpd-oauth
    participant Untappd

    User->>YourApp: GET /auth/start
    YourApp->>utpd-oauth-client: client.login_url(callback_url)
    utpd-oauth-client-->>YourApp: redirect URL
    YourApp->>utpd-oauth: Redirect to /login
    utpd-oauth->>Untappd: Redirect to OAuth
    Untappd->>utpd-oauth: Callback with code
    utpd-oauth->>YourApp: Redirect to /auth/callback?token_code=...
    YourApp->>utpd-oauth-client: client.exchange(token_code)
    utpd-oauth-client->>utpd-oauth: POST /get-token
    utpd-oauth-->>utpd-oauth-client: { access_token }
    utpd-oauth-client-->>YourApp: access_token
    YourApp->>YourApp: on_token(access_token, request)
    YourApp-->>User: Redirect to app

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

utpd_oauth_client-0.2.0.tar.gz (6.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

utpd_oauth_client-0.2.0-py3-none-any.whl (10.1 kB view details)

Uploaded Python 3

File details

Details for the file utpd_oauth_client-0.2.0.tar.gz.

File metadata

  • Download URL: utpd_oauth_client-0.2.0.tar.gz
  • Upload date:
  • Size: 6.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.23 {"installer":{"name":"uv","version":"0.9.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for utpd_oauth_client-0.2.0.tar.gz
Algorithm Hash digest
SHA256 4c87a49bb2a86fba9a55d560f170314027434bbf2697b690972ef4de1c1aa3c8
MD5 3a99bd22846325ee9c0bee4a5ba4d2cc
BLAKE2b-256 5c04e0babe90132f112f9a6d503d82dda9b78d7fd50774aaade289936337648a

See more details on using hashes here.

File details

Details for the file utpd_oauth_client-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: utpd_oauth_client-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 10.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.23 {"installer":{"name":"uv","version":"0.9.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for utpd_oauth_client-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5c48f73996bef6d5d9c8c37b7b1e2a97dbd7b27079558e84b6df77e33f09e971
MD5 bb9e0c0860ec7936e599fc9b26939686
BLAKE2b-256 4641d0b20d5c15730df035517b07a9164df08ece48ce545bec3043733f332793

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page