-
Notifications
You must be signed in to change notification settings - Fork 631
Description
Summary
The twitterv2 provider does not actually use OAuth 2.0 for its authentication flow. It uses OAuth 1.0a via mrjones/oauth, and only calls the Twitter API v2 endpoints (/2/users/me). This causes a 401 Unauthorized error on X's Free plan, which does not support OAuth 1.0a.
Details
The twitterv2 provider was added in #460 to address #440, but the underlying auth mechanism was not changed to OAuth 2.0 — only the API endpoints were updated to v2.
Internal dependency chain:
goth/providers/twitterv2
→ github.com/mrjones/oauth (OAuth 1.0a, HMAC-SHA1 signatures)
Error seen at runtime:
HTTP response is not 200/OK as expected.
Response Status: '401 Unauthorized'
Request Headers: Authorization: OAuth oauth_signature_method="HMAC-SHA1" ...
X's Free plan (the only plan available for new developer accounts) requires OAuth 2.0 with PKCE. The OAuth 1.0a request token endpoint returns 401 because it is disabled for Free-tier apps.
Expected behavior
The twitterv2 provider should use OAuth 2.0 + PKCE (code_challenge_method=S256) as documented in X's OAuth 2.0 documentation.
Workaround
I worked around this by implementing X OAuth 2.0 + PKCE outside of goth using golang.org/x/oauth2, while keeping goth for Google login.
Implementation approach:
- Created a standalone X OAuth 2.0 handler that wraps
golang.org/x/oauth2.Config - In the HTTP handler, routes for
"x"are dispatched to the custom OAuth 2.0 flow; all other providers continue to use goth - State and PKCE code verifier are stored in a dedicated
gorilla/sessionscookie (separate from goth's session) - On callback: validate state, exchange code with PKCE verifier, then call
/2/users/meto fetch user info - The result is mapped to the same internal user struct used by goth providers, so downstream session/account logic is unchanged
Key golang.org/x/oauth2 APIs used:
oauth2.GenerateVerifier()— generate PKCE code verifieroauth2.S256ChallengeOption(verifier)— attach S256 challenge to auth URLoauth2.VerifierOption(verifier)— attach verifier to token exchangeConfig.AuthCodeURL()/Config.Exchange()/Config.Client()— standard OAuth 2.0 flow
X OAuth 2.0 endpoints:
- Auth:
https://twitter.com/i/oauth2/authorize - Token:
https://api.twitter.com/2/oauth2/token - User info:
https://api.twitter.com/2/users/me?user.fields=id,name,username,profile_image_url - Scopes:
users.read tweet.read
This works correctly with X's Free plan. Login flow completes successfully and returns user profile data.
Related issues
- Support for Twitter OAuth2 or State Parameter in OAuth #440 — Original request for Twitter OAuth 2.0 support (closed by Twitter API v2 support #460)
- Twitter API v2 support #460 — Added
twitterv2provider (API v2 endpoints, but auth flow remained OAuth 1.0a)
Environment
- goth v1.82.0
- Go 1.26
- X Developer Portal: Free plan