Skip to content

Error: createTweet 403 #97

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
jiaohu opened this issue Jan 10, 2025 · 1 comment
Open

Error: createTweet 403 #97

jiaohu opened this issue Jan 10, 2025 · 1 comment

Comments

@jiaohu
Copy link

jiaohu commented Jan 10, 2025

When I use sdk to post twitter with code below and I get 403 error. How could I use it correctly?

export class TwitterHandler {
    authClient: auth.OAuth2User;
    client: Client;
    agent: AgentClient;

    constructor() {
        this.authClient = new auth.OAuth2User({
            client_id: envConfig.X_CLIENT_ID,
            client_secret: envConfig.X_CLIENT_SECRET,
            callback: `${envConfig.SERVER_DOMAIN}/callback`,
            scopes: ["tweet.read", "users.read", "tweet.write", "offline.access"],
        });
        this.client = new Client(this.authClient);
        this.agent = new OpenAIAgent();
    }


    async checkAndUpdateAccessToken() : Promise<void> {
        if (this.authClient.isAccessTokenExpired()) {
            await this.authClient.refreshAccessToken()
        }
    }

    async sendTweet(text: string): Promise<void> {
        try {
            let result = await this.agent.responseText(text);
            if (!result) {
                throw new Error("Processed tweet text cannot be null or empty");
            }

            await this.checkAndUpdateAccessToken();
            console.log("result", result);
            console.log("authClient", this.authClient)
            await this.client.tweets.createTweet({ text: result })
        } catch (error) {
            console.error("Error posting tweet:", error);
        }
    }
}
app.get('/auth', (req, res) => {
    const authUrl = twitterHandler.authClient.generateAuthURL({
        state: 'state',
        code_challenge_method: 'plain',
        code_challenge: 'challenge',
    });
    res.redirect(authUrl);
});

app.get('/callback', async (req, res) => {
    const code = req.query.code as string;
    console.log("before", twitterHandler.authClient)
    let token = await twitterHandler.authClient.requestAccessToken(code);

    const userInfo = await twitterHandler.getAuthenticatedUserInfo();
    console.log(token.token)
    await twitterHandler.sendTweet("hello")
    if (userInfo) {
        res.send(`Authentication successful! User ID: ${userInfo.id}, User Name: ${userInfo.name}`);
    } else {
        res.status(500).send("Error fetching user info");
    }
});

Expected behavior

When the twitter user call /auth in the browser, and authorize to the application, then It will post a tweet.

Actual behavior

get error with code 403, more detail in the below


2025-01-10 15:48:00 | {"log":"before OAuth2User { token: undefined }\n","stream":"stdout","time":"2025-01-10T07:48:00.151143423Z"}
-- | --
  | 2025-01-10 15:48:00 | {"log":"{\n","stream":"stdout","time":"2025-01-10T07:48:00.548233539Z"}
  | 2025-01-10 15:48:00 | {"log":"  token_type: 'bearer',\n","stream":"stdout","time":"2025-01-10T07:48:00.548246461Z"}
  | 2025-01-10 15:48:00 | {"log":"  access_token: 'QVdsT29FM*****OjE',\n","stream":"stdout","time":"2025-01-10T07:48:00.548249972Z"}
  | 2025-01-10 15:48:00 | {"log":"  scope: 'tweet.write users.read tweet.read offline.access',\n","stream":"stdout","time":"2025-01-10T07:48:00.548253294Z"}
  | 2025-01-10 15:48:00 | {"log":"  refresh_token: 'MHZTMXNvcC1NS****OnJ0OjE',\n","stream":"stdout","time":"2025-01-10T07:48:00.548256494Z"}
  | 2025-01-10 15:48:00 | {"log":"  expires_at: 1736502480492\n","stream":"stdout","time":"2025-01-10T07:48:00.548259962Z"}
  | 2025-01-10 15:48:00 | {"log":"}\n","stream":"stdout","time":"2025-01-10T07:48:00.548262902Z"}
  | 2025-01-10 15:48:02 | {"log":"result Why did *****🐔💰 \n","stream":"stdout","time":"2025-01-10T07:48:02.195043921Z"}
  | 2025-01-10 15:48:02 | {"log":"\n","stream":"stdout","time":"2025-01-10T07:48:02.195083118Z"}
  | 2025-01-10 15:48:02 | {"log":"But seriously, my dear influencer friend******n! 🐓🚀 \n","stream":"stdout","time":"2025-01-10T07:48:02.195087814Z"}
  | 2025-01-10 15:48:02 | {"log":"\n","stream":"stdout","time":"2025-01-10T07:48:02.195091444Z"}
  | 2025-01-10 15:48:02 | {"log":"For today's ******","stream":"stdout","time":"2025-01-10T07:48:02.195094169Z"}
  | 2025-01-10 15:48:02 | {"log":"authClient OAuth2User {\n","stream":"stdout","time":"2025-01-10T07:48:02.19527886Z"}
  | 2025-01-10 15:48:02 | {"log":"  token: {\n","stream":"stdout","time":"2025-01-10T07:48:02.19528524Z"}
  | 2025-01-10 15:48:02 | {"log":"    token_type: 'bearer',\n","stream":"stdout","time":"2025-01-10T07:48:02.195288325Z"}
  | 2025-01-10 15:48:02 | {"log":"    access_token: 'QVdsT29FMk9****TowOmF0OjE',\n","stream":"stdout","time":"2025-01-10T07:48:02.195291498Z"}
  | 2025-01-10 15:48:02 | {"log":"    scope: 'tweet.write users.read tweet.read offline.access',\n","stream":"stdout","time":"2025-01-10T07:48:02.195295135Z"}
  | 2025-01-10 15:48:02 | {"log":"    refresh_token: 'MHZTMXNvcC1NSnI0****ODA0ODA6MTowOnJ0OjE',\n","stream":"stdout","time":"2025-01-10T07:48:02.195298292Z"}
  | 2025-01-10 15:48:02 | {"log":"    expires_at: 1736502480492\n","stream":"stdout","time":"2025-01-10T07:48:02.195301608Z"}
  | 2025-01-10 15:48:02 | {"log":"  }\n","stream":"stdout","time":"2025-01-10T07:48:02.195331158Z"}
  | 2025-01-10 15:48:02 | {"log":"}\n","stream":"stdout","time":"2025-01-10T07:48:02.19533885Z"}
  | 2025-01-10 15:48:02 | {"log":"Error posting tweet: TwitterResponseError\n","stream":"stderr","time":"2025-01-10T07:48:02.273021542Z"}
  | 2025-01-10 15:48:02 | {"log":"    at request (/app/node_modules/twitter-api-sdk/dist/request.js:67:15)\n","stream":"stderr","time":"2025-01-10T07:48:02.273033255Z"}
  | 2025-01-10 15:48:02 | {"log":"    at processTicksAndRejections (node:internal/process/task_queues:105:5)\n","stream":"stderr","time":"2025-01-10T07:48:02.273035931Z"}
  | 2025-01-10 15:48:02 | {"log":"    at async rest (/app/node_modules/twitter-api-sdk/dist/request.js:100:22) {\n","stream":"stderr","time":"2025-01-10T07:48:02.273038241Z"}
  | 2025-01-10 15:48:02 | {"log":"  status: 403,\n","stream":"stderr","time":"2025-01-10T07:48:02.273040415Z"}
  | 2025-01-10 15:48:02 | {"log":"  statusText: 'Forbidden',\n","stream":"stderr","time":"2025-01-10T07:48:02.273042335Z"}
  | 2025-01-10 15:48:02 | {"log":"  headers: {\n","stream":"stderr","time":"2025-01-10T07:48:02.273044301Z"}
  | 2025-01-10 15:48:02 | {"log":"    'api-version': '2.120',\n","stream":"stderr","time":"2025-01-10T07:48:02.273046199Z"}
  | 2025-01-10 15:48:02 | {"log":"    'cache-control': 'no-cache, no-store, max-age=0',\n","stream":"stderr","time":"2025-01-10T07:48:02.273048098Z"}
  | 2025-01-10 15:48:02 | {"log":"    'content-disposition': 'attachment; filename=json.json',\n","stream":"stderr","time":"2025-01-10T07:48:02.273050001Z"}
  | 2025-01-10 15:48:02 | {"log":"    'content-encoding': 'gzip',\n","stream":"stderr","time":"2025-01-10T07:48:02.273051938Z"}
  | 2025-01-10 15:48:02 | {"log":"    'content-length': '122',\n","stream":"stderr","time":"2025-01-10T07:48:02.273053981Z"}
  | 2025-01-10 15:48:02 | {"log":"    'content-type': 'application/json; charset=utf-8',\n","stream":"stderr","time":"2025-01-10T07:48:02.273055835Z"}
  | 2025-01-10 15:48:02 | {"log":"    date: 'Fri, 10 Jan 2025 07:48:02 UTC',\n","stream":"stderr","time":"2025-01-10T07:48:02.273057724Z"}
  | 2025-01-10 15:48:02 | {"log":"    perf: '7402827104',\n","stream":"stderr","time":"2025-01-10T07:48:02.273059634Z"}
  | 2025-01-10 15:48:02 | {"log":"    server: 'tsa_p',\n","stream":"stderr","time":"2025-01-10T07:48:02.273061819Z"}
  | 2025-01-10 15:48:02 | {"log":"    'set-cookie': 'guest_id=v1%3A173649528220742917; Max-Age=34214400; Expires=Tue, 10 Feb 2026 07:48:02 GMT; Path=/; Domain=.twitter.com; Secure; SameSite=None',\n","stream":"stderr","time":"2025-01-10T07:48:02.273063748Z"}
  | 2025-01-10 15:48:02 | {"log":"    'strict-transport-security': 'max-age=631138519',\n","stream":"stderr","time":"2025-01-10T07:48:02.273065837Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-access-level': 'read-write',\n","stream":"stderr","time":"2025-01-10T07:48:02.27306772Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-app-limit-24hour-limit': '17',\n","stream":"stderr","time":"2025-01-10T07:48:02.273069891Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-app-limit-24hour-remaining': '16',\n","stream":"stderr","time":"2025-01-10T07:48:02.273072615Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-app-limit-24hour-reset': '1736581682',\n","stream":"stderr","time":"2025-01-10T07:48:02.27307566Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-connection-hash': 'b9dbb429a720a831a3f3a37ffe3352ea6926a45e8eff752b7e4298ec4292afe5',\n","stream":"stderr","time":"2025-01-10T07:48:02.2730786Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-content-type-options': 'nosniff',\n","stream":"stderr","time":"2025-01-10T07:48:02.273081951Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-frame-options': 'SAMEORIGIN',\n","stream":"stderr","time":"2025-01-10T07:48:02.273085641Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-rate-limit-limit': '1080000',\n","stream":"stderr","time":"2025-01-10T07:48:02.273087799Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-rate-limit-remaining': '1079999',\n","stream":"stderr","time":"2025-01-10T07:48:02.273089615Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-rate-limit-reset': '1736496182',\n","stream":"stderr","time":"2025-01-10T07:48:02.273091455Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-response-time': '61',\n","stream":"stderr","time":"2025-01-10T07:48:02.273093328Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-transaction-id': 'b018055ffeca5a70',\n","stream":"stderr","time":"2025-01-10T07:48:02.273095182Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-user-limit-24hour-limit': '17',\n","stream":"stderr","time":"2025-01-10T07:48:02.273097111Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-user-limit-24hour-remaining': '16',\n","stream":"stderr","time":"2025-01-10T07:48:02.273098975Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-user-limit-24hour-reset': '1736581682',\n","stream":"stderr","time":"2025-01-10T07:48:02.273100845Z"}
  | 2025-01-10 15:48:02 | {"log":"    'x-xss-protection': '0'\n","stream":"stderr","time":"2025-01-10T07:48:02.273102743Z"}
  | 2025-01-10 15:48:02 | {"log":"  },\n","stream":"stderr","time":"2025-01-10T07:48:02.273113161Z"}
  | 2025-01-10 15:48:02 | {"log":"  error: {\n","stream":"stderr","time":"2025-01-10T07:48:02.27311512Z"}
  | 2025-01-10 15:48:02 | {"log":"    detail: 'You are not permitted to perform this action.',\n","stream":"stderr","time":"2025-01-10T07:48:02.273116957Z"}
  | 2025-01-10 15:48:02 | {"log":"    type: 'about:blank',\n","stream":"stderr","time":"2025-01-10T07:48:02.273118855Z"}
  | 2025-01-10 15:48:02 | {"log":"    title: 'Forbidden',\n","stream":"stderr","time":"2025-01-10T07:48:02.273120724Z"}
  | 2025-01-10 15:48:02 | {"log":"    status: 403\n","stream":"stderr","time":"2025-01-10T07:48:02.273122578Z"}
  | 2025-01-10 15:48:02 | {"log":"  }\n","stream":"stderr","time":"2025-01-10T07:48:02.273124428Z"}
  | 2025-01-10 15:48:02 | {"log":"}\n","stream":"stderr","time":"2025-01-10T07:48:02.273126205Z"}


@jiaohu
Copy link
Author

jiaohu commented Jan 10, 2025

And more strange thing is that I use post with curl can do it well

curl --location 'https://api.twitter.com/2/tweets' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer QVdsT29FMk9****TowOmF0OjE' \
--data '{
    "text": "Hello World 2!"
}'  

response

{"data":{"id":"1877655379427082389","text":"Hello World 2!","edit_history_tweet_ids":["1877655379427082389"]}}

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

No branches or pull requests

1 participant