Skip to content

Add OAuth 2.1 implementation for ATProto SDK - #636

Draft
zzstoatzz wants to merge 5 commits into
MarshalX:mainfrom
zzstoatzz:main
Draft

Add OAuth 2.1 implementation for ATProto SDK#636
zzstoatzz wants to merge 5 commits into
MarshalX:mainfrom
zzstoatzz:main

Conversation

@zzstoatzz

@zzstoatzz zzstoatzz commented Nov 14, 2025

Copy link
Copy Markdown
Contributor

Summary

Adds an atproto_oauth package implementing OAuth 2.1 for the AT Protocol, aligned with the official TypeScript SDK.

~2,100 lines (implementation + tests + docs) — scoped to match what the Go SDK (indigo) ships for OAuth.

What's included

  • Authorization flow: PAR, PKCE (S256), DPoP proof generation with nonce rotation
  • Token lifecycle: exchange, refresh, revocation (access + refresh tokens)
  • Auth server discovery: PDS → protected resource metadata → authorization server metadata
  • Client authentication: public (none) and confidential (private_key_jwt) clients
  • Authenticated requests: DPoP-signed HTTP helper with automatic nonce retry
  • Session/state stores: abstract base classes + in-memory implementations
  • Security: URL validation (SSRF protection), hardened HTTP clients (redirect/connection limits), issuer re-verification after token exchange (prevents impersonation per spec)
  • Tests: 29 tests covering PKCE, DPoP, client prompt flow, and session expiry
  • Docs: Sphinx API reference (auto-generated) + usage guide with quick start examples

What's NOT included (follow-up PRs)

  • Scope parsing library (port of @atproto/oauth-scopes) — available on the oauth-full branch
  • Flask demo application
  • Auto-refresh on 401 / concurrency safety

Comparison with other SDKs

Feature TypeScript (ref) Go (indigo) This PR
PAR + PKCE + DPoP
Token refresh/revoke
Public + confidential clients
Store abstraction
Scope parsing ❌ (follow-up)
Auto-refresh on 401 ❌ (follow-up)

Files

  • packages/atproto_oauth/ — 11 source files (client, DPoP, PKCE, metadata, models, security, stores)
  • tests/test_oauth_{client,dpop,pkce}.py — 29 tests
  • pyproject.toml — package entry + ruff per-file-ignores
  • docs/source/atproto/ — generated Sphinx autodoc (via make -C docs gen)
  • docs/source/atproto_oauth/index.rst — usage guide with quick start examples
  • docs/source/index.rst — registered in SDK toctree

Test plan

  • ruff check + ruff format --check pass
  • All 29 OAuth tests pass locally
  • CI: ruff, unit_tests (3.9–3.14, 3 platforms), codegen_check, docs build

🤖 Generated with Claude Code

Core OAuth 2.1 client for AT Protocol with PAR, PKCE, DPoP, and
confidential client support. Includes auth server metadata discovery,
token exchange/refresh/revocation, authenticated request helpers,
and abstract session/state stores with in-memory implementations.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Generated via sphinx-apidoc (make -C docs gen).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
zzstoatzz and others added 3 commits March 5, 2026 15:59
handle_callback() and refresh_session() both parsed expires_in from the
auth server token response but never used it to set session.expires_at,
leaving it permanently None. Callers had no way to know when to refresh.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a hand-written docs/source/atproto_oauth/index.rst with prose
explaining the authorization flow, session management, custom stores,
and confidential client setup. Registers atproto_oauth in the main
SDK toctree so it appears alongside the other packages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… narrowed exceptions

- Re-verify DID→PDS→AuthServer chain after token exchange to prevent impersonation
- Use hardened HTTP clients (redirect/connection limits) instead of plain httpx
- Narrow bare `except Exception` to `except (ValueError, KeyError)` in DPoP
- Add spec reference to confidential clients docs section
- Add type annotations to client assertion builder
- Fix misleading comment about implicit atproto scope
- Update tests to mock the new re-verification step

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@krystofyah

Copy link
Copy Markdown

hey @zzstoatzz @MarshalX any plans to merge this oauth implementation?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants