feat: Implement OAuth with DPoP using @atproto/oauth-client-node
Replace manual OAuth implementation with official @atproto/oauth-client-node library to properly support DPoP (Demonstrating Proof of Possession) authentication. Changes: - Added @atproto/oauth-client-node dependency - Created OAuth state store (SurrealDB-backed) for CSRF protection - Created OAuth session store (SurrealDB-backed) for token persistence - Created OAuth client singleton with localhost exception for development - Rewrote /api/auth/login to use client.authorize() - Rewrote /api/auth/callback to use client.callback() with DPoP - Updated lib/auth/session.ts with getAuthenticatedAgent() for ATproto API calls - Updated db/schema.surql with oauth_state and oauth_session tables - Added scripts/apply-schema.js for database schema management - Created plans/oauth-dpop-implementation.md with detailed implementation plan - Removed legacy lib/auth/atproto.ts and lib/auth/oauth-state.ts - Updated .env to use localhost exception (removed BLUESKY_CLIENT_ID) The OAuth client now handles: - PKCE code generation and verification - DPoP proof generation and signing - Automatic token refresh - Session persistence across server restarts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -89,3 +89,54 @@ DEFINE TABLE links_to SCHEMAFULL
|
||||
|
||||
-- (No fields needed, it's a simple relation)
|
||||
-- Example usage: RELATE (node:1)-[links_to]->(node:2);
|
||||
|
||||
-- --------------------------------------------------
|
||||
-- Table: oauth_state
|
||||
-- --------------------------------------------------
|
||||
|
||||
-- Stores temporary OAuth state during the authorization flow.
|
||||
-- Used for CSRF protection. States should expire after 1 hour.
|
||||
DEFINE TABLE oauth_state SCHEMAFULL;
|
||||
|
||||
-- The state key (random string generated during authorize)
|
||||
DEFINE FIELD key ON TABLE oauth_state TYPE string
|
||||
ASSERT $value != NONE;
|
||||
|
||||
-- The state value (contains PKCE verifier, DPoP key, etc.)
|
||||
DEFINE FIELD value ON TABLE oauth_state TYPE object
|
||||
ASSERT $value != NONE;
|
||||
|
||||
-- Timestamp for cleanup
|
||||
DEFINE FIELD created_at ON TABLE oauth_state TYPE datetime
|
||||
DEFAULT time::now();
|
||||
|
||||
-- Index for fast lookups by key
|
||||
DEFINE INDEX oauth_state_key_idx ON TABLE oauth_state COLUMNS key UNIQUE;
|
||||
|
||||
-- Event to auto-delete expired states (older than 1 hour)
|
||||
DEFINE EVENT oauth_state_cleanup ON TABLE oauth_state WHEN time::now() - created_at > 1h THEN (
|
||||
DELETE oauth_state WHERE id = $event.id
|
||||
);
|
||||
|
||||
-- --------------------------------------------------
|
||||
-- Table: oauth_session
|
||||
-- --------------------------------------------------
|
||||
|
||||
-- Stores persistent OAuth sessions (access/refresh tokens).
|
||||
-- Sessions are managed by the @atproto/oauth-client-node library.
|
||||
DEFINE TABLE oauth_session SCHEMAFULL;
|
||||
|
||||
-- The user's DID (unique identifier)
|
||||
DEFINE FIELD did ON TABLE oauth_session TYPE string
|
||||
ASSERT $value != NONE;
|
||||
|
||||
-- The session data (contains tokens, DPoP key, etc.)
|
||||
DEFINE FIELD session_data ON TABLE oauth_session TYPE object
|
||||
ASSERT $value != NONE;
|
||||
|
||||
-- Timestamp for last update (useful for debugging)
|
||||
DEFINE FIELD updated_at ON TABLE oauth_session TYPE datetime
|
||||
DEFAULT time::now();
|
||||
|
||||
-- Index for fast lookups by DID
|
||||
DEFINE INDEX oauth_session_did_idx ON TABLE oauth_session COLUMNS did UNIQUE;
|
||||
|
||||
Reference in New Issue
Block a user