Skip to content

Commit 799ca8d

Browse files
committed
Fix oauth2 bugs for Python and TypeScript XDKs
1 parent 5a4e14f commit 799ca8d

File tree

4 files changed

+31
-19
lines changed

4 files changed

+31
-19
lines changed

xdk-gen/templates/python/main_client.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class Client:
2222
"""Client for interacting with the X API."""
2323

2424
def __init__(self,
25-
base_url: str = "https://api.twitter.com",
25+
base_url: str = "https://api.x.com",
2626
bearer_token: str = None,
2727
client_id: str = None,
2828
client_secret: str = None,

xdk-gen/templates/python/oauth2_auth.j2

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class OAuth2PKCEAuth:
2121
"""OAuth2 PKCE authentication for the X API."""
2222

2323
def __init__(self,
24-
base_url: str = "https://api.twitter.com",
24+
base_url: str = "https://api.x.com",
2525
client_id: str = None,
2626
client_secret: str = None,
2727
redirect_uri: str = None,
@@ -30,7 +30,7 @@ class OAuth2PKCEAuth:
3030
"""Initialize the OAuth2 PKCE authentication.
3131

3232
Args:
33-
base_url: The base URL for the X API.
33+
base_url: The base URL for the X API token endpoint (defaults to https://api.x.com).
3434
client_id: The client ID for the X API.
3535
client_secret: The client secret for the X API.
3636
redirect_uri: The redirect URI for OAuth2 authorization.
@@ -100,8 +100,10 @@ class OAuth2PKCEAuth:
100100
scope=self.scope
101101
)
102102

103+
# Authorization URL is always https://x.com/i/oauth2/authorize
104+
# (not using base_url since it's for API calls, not authorization)
103105
auth_url, state = self.oauth2_session.authorization_url(
104-
f"{self.base_url}/oauth2/authorize",
106+
"https://x.com/i/oauth2/authorize",
105107
code_challenge=self.code_challenge,
106108
code_challenge_method="S256"
107109
)
@@ -121,7 +123,7 @@ class OAuth2PKCEAuth:
121123
raise ValueError("OAuth2 session not initialized. Call get_authorization_url first.")
122124

123125
self.token = self.oauth2_session.fetch_token(
124-
f"{self.base_url}/oauth2/token",
126+
f"{self.base_url}/2/oauth2/token",
125127
authorization_response=authorization_response,
126128
code_verifier=self.code_verifier,
127129
client_id=self.client_id,
@@ -139,7 +141,7 @@ class OAuth2PKCEAuth:
139141
if not self.oauth2_session or not self.token:
140142
raise ValueError("No token to refresh")
141143

142-
refresh_url = f"{self.base_url}/oauth2/token"
144+
refresh_url = f"{self.base_url}/2/oauth2/token"
143145

144146
self.token = self.oauth2_session.refresh_token(
145147
refresh_url,

xdk-gen/templates/python/process_for_mintlify.j2

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,43 +1042,49 @@ This example shows how to use OAuth 2.0 with Proof Key for Code Exchange (PKCE).
10421042
**Example** (using a web server for callback):
10431043
10441044
```python
1045-
from xdk.auth import OAuth2PKCE
1045+
from xdk.oauth2_auth import OAuth2PKCEAuth
10461046
from urllib.parse import urlparse
10471047
import webbrowser
10481048
10491049
# Step 1: Create PKCE instance
1050-
auth = OAuth2PKCE(
1051-
client_id="your_client_id",
1052-
redirect_uri="http://localhost:8080/callback",
1053-
scopes=["tweet.read", "users.read", "offline.access"] # Adjust scopes as needed
1050+
auth = OAuth2PKCEAuth(
1051+
base_url="https://x.com/i",
1052+
client_id="YOUR_CLIENT_ID",
1053+
redirect_uri="YOUR_CALLBACK_URL",
1054+
scope="tweet.read users.read offline.access"
10541055
)
10551056
10561057
# Step 2: Get authorization URL
1057-
auth_url = auth.get_authorization_url()
1058+
auth_url, state = auth.get_authorization_url()
10581059
print(f"Visit this URL to authorize: {auth_url}")
10591060
webbrowser.open(auth_url)
10601061
10611062
# Step 3: Handle callback (in a real app, use a web framework like Flask)
10621063
# Assume callback_url = "http://localhost:8080/callback?code=AUTH_CODE_HERE"
10631064
callback_url = input("Paste the full callback URL here: ")
1064-
parsed = urlparse(callback_url)
1065-
code = parsed.query.split("=")[1]
10661065
10671066
# Step 4: Exchange code for tokens
1068-
tokens = auth.fetch_token(authorization_code=code)
1067+
tokens = auth.fetch_token(authorization_response=callback_url)
10691068
access_token = tokens["access_token"]
10701069
refresh_token = tokens["refresh_token"] # Store for renewal
10711070
10721071
# Step 5: Create client
1073-
client = Client(oauth2_access_token=access_token)
1072+
# Option 1: Use bearer_token (OAuth2 access tokens work as bearer tokens)
1073+
client = Client(bearer_token=access_token)
1074+
1075+
# Option 2: Pass the full token dict for automatic refresh support
1076+
# client = Client(token=tokens)
10741077
```
10751078
10761079
**Token Refresh** (automatic in SDK for long-lived sessions):
10771080
10781081
```python
10791082
# If access token expires, refresh using stored refresh_token
1080-
tokens = auth.refresh_token(refresh_token=refresh_token)
1081-
client = Client(oauth2_access_token=tokens["access_token"])
1083+
# The refresh_token method uses the stored token from the OAuth2PKCEAuth instance
1084+
tokens = auth.refresh_token()
1085+
# Use the refreshed token
1086+
client = Client(bearer_token=tokens["access_token"])
1087+
# Or pass the full token dict: client = Client(token=tokens)
10821088
```
10831089
10841090
### 3. OAuth 1.0a User Context

xdk-gen/templates/typescript/oauth2_auth.j2

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,11 @@ export class OAuth2 {
6464
state: state || ''
6565
});
6666

67-
// PKCE parameters are handled separately - not generated automatically
67+
// Add PKCE parameters if they've been set
68+
if (this.codeChallenge) {
69+
params.append('code_challenge', this.codeChallenge);
70+
params.append('code_challenge_method', 'S256');
71+
}
6872

6973
return `https://x.com/i/oauth2/authorize?${params.toString()}`;
7074
}

0 commit comments

Comments
 (0)