Skip to content

feat(import): implement X OAuth 2.0 backend for live bookmark import#54

Open
davidorban wants to merge 1 commit intoviperrcrypto:mainfrom
davidorban:feat/x-oauth-live-import
Open

feat(import): implement X OAuth 2.0 backend for live bookmark import#54
davidorban wants to merge 1 commit intoviperrcrypto:mainfrom
davidorban:feat/x-oauth-live-import

Conversation

@davidorban
Copy link
Contributor

Closes #50

The Live Import tab already has the complete X OAuth 2.0 UI, but all five backend routes were missing — causing every user to see:

X OAuth not configured
Could not connect to the server

This PR implements the missing backend.

New routes

Method Path Purpose
GET /api/import/x-oauth/status Returns { configured, connected, tokenExpired, user }
GET /api/import/x-oauth/authorize Generates PKCE challenge, returns X auth URL
GET /api/import/x-oauth/callback Exchanges code for tokens, stores them, redirects
POST /api/import/x-oauth/disconnect Removes stored tokens
POST /api/import/x-oauth/fetch Fetches bookmarks via X API v2 with auto-pagination and token refresh

Notes

  • PKCE flow (S256) — works with both public and confidential clients (autodetected from whether a Client Secret is present in Settings)
  • PKCE verifiers are stored ephemerally in the Setting table and cleaned up after the callback
  • The fetch route automatically refreshes an expired access token before failing
  • Add APP_URL env var to override the callback base URL (defaults to http://localhost:3000) — useful for reverse proxies or custom ports
  • .env.example updated with APP_URL documentation

Testing

Tested end-to-end with a live X Developer account: connected, fetched 900+ bookmarks with pagination, disconnected, and reconnected.

Closes viperrcrypto#50

The Live Import tab in the UI already had the full X OAuth 2.0 flow
wired up on the frontend, but all five backend API routes were missing,
causing the tab to display 'X OAuth not configured' and
'Could not connect to the server' for every user.

This PR implements the missing backend:

## New routes

- GET  /api/import/x-oauth/status
  Returns { configured, connected, tokenExpired, user } so the UI
  can render the correct state.

- GET  /api/import/x-oauth/authorize
  Generates a PKCE code_verifier + code_challenge, stores the verifier
  keyed by a random state value, and returns the X OAuth 2.0
  authorization URL for the client to redirect to.

- GET  /api/import/x-oauth/callback
  Exchanges the auth code + PKCE verifier for access/refresh tokens,
  fetches the authenticated user via /2/users/me, stores everything in
  the Setting table, then redirects to /import?x_connected=true.

- POST /api/import/x-oauth/disconnect
  Removes all stored X OAuth tokens from the database.

- POST /api/import/x-oauth/fetch
  Fetches bookmarks via the X API v2 /2/users/:id/bookmarks endpoint
  with full pagination support (up to 50 pages). Automatically
  refreshes an expired access token using the stored refresh token.
  Supports both photo and video/GIF media via media_keys expansion.

## Configuration

Add `APP_URL` to your environment to override the callback URL base
(defaults to `http://localhost:3000`). Useful when running behind a
reverse proxy or on a custom port.

## Notes

- Supports both public clients (PKCE only) and confidential clients
  (PKCE + Basic auth with client_id:client_secret) — autodetected from
  whether a Client Secret is configured in Settings.
- PKCE verifiers are stored ephemerally in the Setting table and
  cleaned up immediately after the callback completes.
- Token refresh is handled transparently in the fetch route.

Co-Authored-By: Oz <oz-agent@warp.dev>
@alejandrofcarrera
Copy link

Just a suggestion because I tried the same on my own local development side.

The API costs are related per each item read (not per page received), so if you read a pagination of 100 elements, you will pay per 100 elementes either you already have them or not. For me, the right approach is getting 5 elements per page, so when one of the elements is already exported in a previous session, the deprecation cost will be 1 to 4 instead of 1 to 99.

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.

X OAuth Live Import: API endpoints not implemented

2 participants