I’m working on a pretty basic bot and am running into issues setting up the OAuth2 flow. I’m using this library to initialize the client: node-twitter-api-v2
From what I can tell the authorization URL looks well formed but I’m getting the “Something went wrong, you weren’t able to give access to the App” screen without a login attempt when I hit the URL. Can’t seem to find any more specific errors and it’s not hitting my callback URL since it’s not actually authenticating. I tried to paste the URL formed by the client but the forum says I can’t paste links so…?

current auth URL params (at /i/oauth2/authorize): ?response_type=code&client_id=VHNyVUF3UXhxRjEtSXpZQndmeVE6MTpjaQ&redirect_uri=http%3A%2F%2Fwww.mettabot.app%2Fapi%2Ftwitter%2Foauthcb&state=fycMwlLe2bGkZ.29UXN9sjzq~VT1X.1S&code_challenge=HASoYJOFlhHPWnDcGv9qDU1xVkkj_8HtVGMwXGGX5Ac&code_challenge_method=s256&scope=tweet.read%20user.read%20tweet.write%20offline.access

Also confirming I’m correct in using the “OAuth2 ClientID and Client Secret” to instantiate the client that makes the initial authorization request and that I shouldn’t be using the consumer key/secret or bearer token, or access token/secret generated in the developer portal for any of this effort to get a valid Oauth2 token to write a tweet?

Hi @erich_keil ! Welcome to the community

Have you set your callback url in developer portal?

Thank you for the suggestion. Yes I had checked that, and just now double checked it’s correct. On first pass at this I constructed the url manually rather than using a client and it hit the callback url correctly so I think that part should be good, I was just having issues making the second request for the token and though using a well formed client would help. It cleaned up the code a bit but now I’m getting this issue.

So one more thing I just tried - I switched browsers to one that has no login cache data. This time I was forced to login, but on successful login I still got the “something went wrong” screen refereneced in the OP, so it appears the credentials for the user account are authenticating but then between acceptance of user credentials and the redirect it’s erroring out.

can i see a sample code to handle the callback?

I’ve pasted samples of the route that generates the initial authorization url and the callback route as well. However, let me be clear, the callback route is not being initiated at all. At the top of the middleware chain is a request logger. I am seeing the initial GET request to /auth on my API that generates the initial auth URL, but after that loads in the browser and requests user approval, I get the ‘something went wrong’ screen and there is no GET request to /oauthcb (the callback redirect URI) being logged (or any request period). When I was attempting to manually generate the signature rather than using the client I was at least successful in triggering a GET request to /oauthcb but now it appears after authentication on the twitter side that is no longer happening. I changed nothing about the logging/routes in between those two stages, so either something is wrong with my initial auth URL request that should trigger the callback, or something is breaking internally on the twitter side after the authentication BEFORE it makes the callback GET request.

Code snippets:
Logger (first thing that should see the callback and is not logging any callback GET request)

// request logger
app.use((req, res, next) => {
  console.log(`request ${req.method} ${req.url}`);
  next();
});

Initial step to request authentication:

//INIT Twitter Client
const client = new TwitterApi({
  clientId: process.env.O2_TWITTER_ID,
  clientSecret: process.env.O2_TWITTER_SECRET,
});

// authenticator url
app.get('/api/twitter/auth', async (req, res) => {
  const authLink = await client.generateOAuth2AuthLink(
    'https://www.mettabot.app/api/twitter/oauthcb',
    { scope: ['tweet.read', 'user.read', 'tweet.write', 'offline.access'] }
  );
  const { url: authUrl, codeVerifier, state } = authLink;
  console.log('authlink: ', authLink);
  twitCodeVerifier = codeVerifier;
  twitState = state;
  res.redirect(authUrl);
});

Callback route (never being requested):

// twitter callback url for code request
app.get('/api/twitter/oauthcb', async (req, res) => {
  console.log('response from twitter auth request: ', {
    body: req.body,
    qparams: req.query,
  });
  try {
    const { state, code } = req.query;
    const codeVerifier = twitCodeVerifier;
    const sessionState = twitState;

    if (!codeVerifier || !state || !sessionState || !code) {
      return res.status(400).send('App denied or session expired');
    }
    if (state !== sessionState) {
      return res.status(400).send('Stored tokens did not match');
    }

    client
      .loginWithOAuth2({
        code,
        codeVerifier,
        redirectUri: 'https://www.mettabot.app',
      })
      .then(
        async ({
          client: loggedClient,
          accessToken,
          refreshToken,
          expiresIn,
        }) => {
          const newMsg = getMsg();
          console.log('message to be tweeted: ', newMsg);
          const { data } = await loggedClient.v2.tweet(newMsg);
          console.log('data return from tweet attempt: ', data);
        }
      )
      .catch(() => res.status(403).send('Invalid verifier or access tokens!'));
  } catch (err) {
    console.log(err.message);
    res.send(err);
  }
});

thanks, the code doesn’t seem to have a problem, and if the callback isn’t requested, it’s probably a problem generating the authlink. Usually it’s in the credentials and whitelist callback url

Thanks for looking. That’s what I’ve figured but not sure how to narrow it down further. I’m using the twitter-api-v2 node library to initiate the client and per their example if I’m following it right, I’m initiating the client just using clientId and clientSecret fields. Those fields contain the “OAuth2 Client ID and Client Secret” keys for the app generated in the dashboard portal. I’m not currently using the consumer_api_key or secret, the bearer token, or the access token/secret provided in the dashboard. Is that correct that generating the authlink for OAuth2 only requires the O2 specific client ID/Secret from the developer portal? I regenerated those OAuth2 tokens and updated them in the server environment just to be sure they were correct but that doesn’t seem to have fixed anything so I’m assuming I’m missing a credential I’m supposed to supply or am supplying the wrong one of the multitude of keys I was handed by twitter? No idea how to diagnose that at this point since I’m not getting any error specificity back from twitter on the initial authurl request.

yes that’s right, I happen to be working on this right now, I’ll let you know if there are any clues.
In the meantime may I have a look at your developer portal settings? Including the callback url field?

Previously I had the same problem, but I forgot where I fixed it, now I’m replicating it.

Here’s a screencap of the settings fields for the app:

OAuth2.0(new) is enabled at the top of that page. Not sure what else you’d want to see that would be relevant/helpful…here’s the keys/tokens page just in case. Again I’m using the last two OAuth2 specific ones at the moment:

2 Likes

Try changing the url to exactly match the callback url

based on reference https://datatracker.ietf.org/doc/html/rfc6749#section-10.6
Came from https://developer.twitter.com/en/docs/authentication/oauth-2-0/authorization-code
It said:

Redirect URI

Your callback URL. You will need to have exact match validation.

Confused. I have the callback url matched exactly in the first field (‘https://www.mettabot.app/api/twitter/oauthcb’) which is copy pasted from the callback URL provided to the twitter API client. The second link there ‘https://www.mettabot.app’ was for whitelisting the second, optional callback URI provided to the next step where the OAuth2 token itself is requested.

Oh my bad, misreading

Just now I managed to make a replica and it worked.
If I change client id or callback url then screen will give error
Error :

There is a technical error

You cannot grant access to your Application. Go back and try logging in again.

If the error is the same, it looks like the problem is callback whitelist or client id, because when I try other settings the authorization screen will work. Other settings I’ve tried to make wrong: client secret, application type

Addendum: if your .env file stores values ​​with quotes try to remove those quotes

So I’m setting the env variables directly on the heroku employment (not publishing my .env file) I just confirmed the client ID and secret I’m using match the OAuth2 Client ID and Secret provided in the twitter developer portal exactly with no quotes. So nothing to fix there…

Tried to do some more sleuthing…looking at the network traffic in the browser dev tools:
Here you can see the first request which returns a 200 but with this odd response about JS not available

Then later on in the sequence, it makes another request to a slightly different authURL:
/authorize?code_challenge=ETdjB5CxirioGkJrP9FCGL4WPliitdtSsJ9wjMA5Q2I&code_challenge_method=s256&client_id=VHNyVUF3UXhxRjEtSXpZQndmeVE6MTpjaQ&redirect_uri=https%3A%2F%2Fwww.mettabot.app%2Fapi%2Ftwitter%2Foauthcb&response_type=code&scope=tweet.read%20user.read%20tweet.write%20offline.access&state=x~qPJcQVwEjEQBPSJ4HQUc22dZExTl-c

which is failing with code 400(Bad Request) and the error: {
“0”: {
“error”: “invalid_request”,
“error_description”: “Redirect is requested.”,
“redirect_uri”: “https://www.mettabot.app/api/twitter/oauthcb?error=invalid_scope&state=x~qPJcQVwEjEQBPSJ4HQUc22dZExTl-c
}
}
so there’s an issue with the scope or state params…?

it’s quite confusing, I suspect it’s a hosting handler issue, have you tried the local server?

Just confirming, that the redirectUri should indeed exactly match the callback url, otherwise the following error will occur:

{
  error: 'invalid_request',
  error_description: 'Value passed for the redirect uri did not match the uri of the authorization code.'
}

But the error occurs after the callback is requested.