Skip to content

Commit

Permalink
oauth and oauth2
Browse files Browse the repository at this point in the history
  • Loading branch information
elliotBraem committed Jan 10, 2025
1 parent 6981706 commit d42ef42
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 14 deletions.
8 changes: 7 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Twitter OAuth 2.0 credentials
# Twitter OAuth 2.0 credentials (for tweet.read, tweet.write)
TWITTER_CLIENT_ID=your_oauth2_client_id
TWITTER_CLIENT_SECRET=your_oauth2_client_secret

# Twitter OAuth 1.0a credentials (for user context endpoints)
TWITTER_API_KEY=your_oauth1_api_key
TWITTER_API_SECRET=your_oauth1_api_secret
TWITTER_ACCESS_TOKEN=your_oauth1_access_token
TWITTER_ACCESS_SECRET=your_oauth1_access_secret

# Base URL for OAuth callback
NEXT_PUBLIC_BASE_URL=http://localhost:3000
52 changes: 39 additions & 13 deletions src/services/twitter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,60 @@ import { TwitterApi } from "twitter-api-v2";
// which manages API credentials and handles OAuth communciation with Twitter

export class TwitterService {
constructor(clientId, clientSecret) {
if (!clientId || !clientSecret) {
constructor(credentials) {
if (!credentials.clientId || !credentials.clientSecret) {
throw new Error("Twitter OAuth 2.0 credentials are required");
}
this.client = new TwitterApi({
clientId: clientId,
clientSecret: clientSecret,

// OAuth 2.0 client for tweet operations
this.oauth2Client = new TwitterApi({
clientId: credentials.clientId,
clientSecret: credentials.clientSecret,
});

// OAuth 1.0a client for user operations if credentials are provided
if (credentials.apiKey && credentials.apiSecret && credentials.accessToken && credentials.accessSecret) {
this.oauth1Client = new TwitterApi({
appKey: credentials.apiKey,
appSecret: credentials.apiSecret,
accessToken: credentials.accessToken,
accessSecret: credentials.accessSecret,
});
}
}

static async initialize() {
const clientId = process.env.TWITTER_CLIENT_ID;
const clientSecret = process.env.TWITTER_CLIENT_SECRET;
const credentials = {
clientId: process.env.TWITTER_CLIENT_ID,
clientSecret: process.env.TWITTER_CLIENT_SECRET,
apiKey: process.env.TWITTER_API_KEY,
apiSecret: process.env.TWITTER_API_SECRET,
accessToken: process.env.TWITTER_ACCESS_TOKEN,
accessSecret: process.env.TWITTER_ACCESS_SECRET,
};

return new TwitterService(clientId, clientSecret);
return new TwitterService(credentials);
}

async getAuthLink(callbackUrl) {
// Use OAuth 2.0 with PKCE for more granular scope control
const { url, codeVerifier, state } = this.client.generateOAuth2AuthLink(
const { url, codeVerifier, state } = this.oauth2Client.generateOAuth2AuthLink(
callbackUrl,
{ scope: ["tweet.read", "tweet.write", "users.read"] },
);
return { url, codeVerifier, state };
}

async handleCallback(code, codeVerifier, state) {
return this.client.loginWithOAuth2({
return this.oauth2Client.loginWithOAuth2({
code,
codeVerifier,
redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/api/twitter/callback`,
});
}

async tweet(accessToken, posts) {
// Create OAuth 2.0 client with user access token for tweet operations
const userClient = new TwitterApi(accessToken);

// Handle array of post objects
Expand Down Expand Up @@ -69,9 +88,16 @@ export class TwitterService {
}

async getUserInfo(accessToken) {
const userClient = new TwitterApi(accessToken);
if (!this.oauth1Client) {
throw new Error("OAuth 1.0a credentials are required for user operations");
}

const me = await userClient.v2.me();
return me.data;
try {
const me = await this.oauth1Client.v2.me();
return me.data;
} catch (error) {
console.error("Failed to fetch user info:", error);
throw error;
}
}
}

0 comments on commit d42ef42

Please sign in to comment.