Feature: OAuth 2.0 for ActivityPub C2S (phase 1 — auth handshake)
First half of AP Client-to-Server: the auth layer native/web clients (Shaer)
need before they can drive a Klonkt account. The AP spec's own C2S half is what
keeps this inside-spec instead of cloning Mastodon's REST API.
- OAuthService: public-client OAuth (RFC 8252), PKCE S256 REQUIRED, no secrets.
Dynamic registration (RFC 7591 subset) with strict redirect_uri validation
(https / loopback http / reverse-DNS custom scheme). Single-use 10-min codes;
tokens stored sha256-hashed; a token is scoped to one user + one site.
- routes/oauth.js: /oauth/register, /oauth/authorize (session-authed consent
screen picking the site), /oauth/token, and RFC 8414 server metadata at
/.well-known/oauth-authorization-server. Redirect params are appended to the
registered URI verbatim (no new URL() round-trip that would mangle a native
custom scheme). Pre-redirect validation errors never bounce to an unvalidated
URI (open-redirect guard).
- Actor doc advertises oauthAuthorizationEndpoint/oauthTokenEndpoint/uploadMedia
in endpoints{} — all AP-spec terms, added to the AS2 conformance allowlist —
so clients discover paths instead of hardcoding them (Klonkt's /ap/users/:slug
differs from the daemon's /actors/:name; discovery makes that irrelevant).
- oauth_clients/oauth_codes/oauth_tokens tables (additive).
- i18n NL/EN/DE for the consent screen.
7 new OAuth tests (PKCE round-trip, replay protection, wrong-verifier reject,
bearer resolution incl. revoke, redirect-uri validation); 73 green. Verified
the full HTTP flow end to end (register → consent → code → token → bearer) and
that the raw Location header preserves the native redirect URI exactly. Beads:
klonkt-demo-srr. Next: klonkt-demo-1w4 (POST outbox accepts the activities).
Co-Authored-By: Claude Opus 4.8 <noreply@…>