feat: add OAuth 2.0 user-context auth#11
Open
mrap wants to merge 1 commit intoxdevplatform:masterfrom
Open
Conversation
Several X API endpoints — bookmarks (getUsersBookmarks, createUsersBookmark, deleteUsersBookmark, getUsersBookmarkFolders, getUsersBookmarksByFolderId), searchNews, and a handful of others — reject OAuth 1.0a with HTTP 403 "Unsupported Authentication: ... Supported authentication types are [OAuth 2.0 User Context]". The server currently only signs with OAuth 1.0a, so those tools fail at runtime once allowlisted. This was reported in xdevplatform#7. The README also advertises an "OAuth2 user token" flow via generate_authtoken.py, but that file was never committed to the repo. This PR delivers both sides: 1. server.py: sign_oauth1_request now checks X_OAUTH2_ACCESS_TOKEN at request time. When set, it writes Authorization: Bearer <token> and skips OAuth 1.0a signing entirely. OAuth 2.0 User Context supports every endpoint OAuth 1.0a supports and more, so one env var flips the whole server over. When the var is empty, OAuth 1.0a signing runs unchanged. 2. generate_oauth2_token.py: new script. Runs the X OAuth 2.0 authorization code + PKCE flow locally — spins up a one-shot HTTP (or HTTPS, if TLS_CERT_FILE / TLS_KEY_FILE are set) server on X_OAUTH_CALLBACK_*, opens the browser for consent, exchanges the code for tokens, and writes X_OAUTH2_ACCESS_TOKEN and X_OAUTH2_REFRESH_TOKEN to .env. Requests all user-facing scopes including bookmark.read/write and offline.access. Supports both confidential (CLIENT_SECRET) and public (PKCE-only) clients. 3. env.example + README.md: documents the new env vars, distinguishes OAuth 1.0a pre-provisioned tokens (X_OAUTH_ACCESS_TOKEN*) from the OAuth 2.0 user-context tokens (X_OAUTH2_*), and replaces the aspirational "Generate an OAuth2 user token" section with a real, working walkthrough. Closes xdevplatform#7. This contribution was developed with AI assistance (Claude Code).
|
Hit this exact gap today evaluating xmcp for a bookmark-reading workflow — the One question: any plan to add token refresh in this PR or a follow-up? The 7200s access-token TTL is the next operational pain point once bearer mode works. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add an OAuth 2.0 User Context auth path so endpoints that require it (bookmarks,
searchNews, and others that currently return 403Unsupported Authentication) actually work, and ship thegenerate_authtoken.py-style helper that the README already advertises but never existed in the repo.Problem
Two separate but linked gaps:
sign_oauth1_requestsigns every outbound request with OAuth 1.0a. Several X API endpoints reject OAuth 1.0a entirely — for examplegetUsersBookmarks,createUsersBookmark,deleteUsersBookmark,getUsersBookmarkFolders,getUsersBookmarksByFolderId,searchNews. They return HTTP 403{'title': 'Unsupported Authentication', 'detail': '...OAuth 1.0a User Context is forbidden for this endpoint. Supported authentication types are [OAuth 2.0 User Context]'}. This was reported in some tools do not work - Unsupported Authentication error #7.The README's "Generate an OAuth2 user token" section instructs users to
python generate_authtoken.py, but that file was never committed. Users who hit (1) and follow the docs land on a missing file.Changes
server.py:sign_oauth1_requestreadsX_OAUTH2_ACCESS_TOKENat request time. When set, it writesAuthorization: Bearer <token>and returns before OAuth 1.0a signing. OAuth 2.0 User Context covers every endpoint OAuth 1.0a covers plus the OAuth2-only ones, so one env var flips the whole server over. When unset, OAuth 1.0a signing runs unchanged — no behavior change for existing users.generate_oauth2_token.py(new): runs the X OAuth 2.0 authorization code + PKCE flow locally. Spins up a one-shot callback server onX_OAUTH_CALLBACK_HOST:PORT, opens the browser for consent, exchanges the code for tokens, and writesX_OAUTH2_ACCESS_TOKEN+X_OAUTH2_REFRESH_TOKENto.env. Supports both confidential (CLIENT_SECRET) and public (PKCE-only) clients. Requests all user-facing scopes (tweet.*,users.read,follows.*,bookmark.*,like.*,list.*,offline.access). Optional TLS viaTLS_CERT_FILE/TLS_KEY_FILEfor non-localhost callback hosts (e.g. a tailnet / LAN hostname so a browser on a different device can complete the redirect — X requires HTTPS for any non-localhost callback).env.example: documents the new vars. Separates OAuth 1.0a pre-provisioned tokens (X_OAUTH_ACCESS_TOKEN*) from the new OAuth 2.0 user tokens (X_OAUTH2_*), and adds the optional TLS vars.README.md: replaces the aspirational "Generate an OAuth2 user token" section with a real walkthrough (Developer Portal config, required scopes, running the script, when the server switches to OAuth 2.0). Distinguishes the two credential sets in the Setup checklist.Testing
Verified end-to-end against my own X Developer app:
X_OAUTH2_ACCESS_TOKENunset → OAuth 1.0a signing path runs unchanged.getUsersMereturns 200 with the authenticated user's profile.X_OAUTH2_ACCESS_TOKENset →Authorization: Bearer <token>header on every outbound request.getUsersMe,searchPostsRecent, andgetUsersBookmarksall return 200. Without this PR,getUsersBookmarksreturns the 403 from some tools do not work - Unsupported Authentication error #7.generate_oauth2_token.pycompletes the full PKCE flow, receives the callback, exchanges the code, and writes both access and refresh tokens to.env.Closes #7.
This contribution was developed with AI assistance (Claude Code).