Search code examples
javascriptnode.jsoauth-2.0twitchrequest-promise

NodeJS Post Request with Request Promise for Twitch Authentication


I'm trying to authenticate a user on my app through their Twitch login. I cannot seem to get request.post() right (using request-promise). I've tried many different variations and I'm usually getting "Unhandled rejection" in the server logs. The Twitch API guide for this is here. The POST response should be JSON. Here is my latest version:

const twitchATParams =
'?client_id=' + twitchAppClientId +
'&client_secret=' + twitchClientSecret +
'&code=' + code +
'&grant_type=authorization_code' +
'&redirect_uri=' + twitchAppRedirect;

request.post(twitchATRequestUrl + twitchATParams)
.then((accessTokenResponse) => {
    const accessToken = accessTokenResponse.access_token;
    console.log('Got an access token: ' + accessToken);
    res.status(200).send('Got an access token: ' + accessToken);
  })
  .catch((error) => {
    res.status(error.statusCode).send(error.error.error_description);
  });

I've also tried this:

request.post({
url:     twitchATRequestUrl,
form:    { client_id: twitchAppClientId,
           client_secret: twitchClientSecret,
           code: code,
           grant_type: "authorization_code",
           redirect_uri:  twitchAppRedirect}
}, function(error, accessTokenResponse, body){
  const accessToken = accessTokenResponse.access_token;
  console.log('Got an access token: ' + accessToken);
  res.status(200).send('Got an access token: ' + accessToken);
});

This is what the Twitch API Guide says I need to do, I think I'm having trouble translating this into JavaScript:

POST https://id.twitch.tv/oauth2/token
  ?client_id=<your client ID>
  &client_secret=<your client secret>
  &code=<authorization code received above>
  &grant_type=authorization_code
  &redirect_uri=<your registered redirect URI>

UPDATE: The app is hosted on Firebase using Cloud Functions. Maybe this is affecting my request?

UPDATE 2: According to this: Deployed Firebase Function Cannot Execute HTTP GET to external API? I can only make external API requests on a Firebase paid plan. I'm assuming this is my issue. I will upgrade to the pay-as-you-go plan (which actually provides a lot of data for free) and try this again and post my results here.


Solution

  • Solved. Turns out I did need a paid plan (Blaze, pay as you go) to access external APIs. I upgraded and that basically solved the issue. It allowed me to see a new error code: StatusCodeError: 400 - "{\"status\":400,\"message\":\"Parameter redirect_uri does not match registered URI\"} so I discovered my redirect url in my code was missing "/callback" (the OAuth Redirect URL on the Twitch app management settings had this "/callback" at the end).

    I was also able to use these two blocks of code to successfully get the access token:

    const twitchTokenPayload = {
      client_id: twitchAppClientId,
      client_secret: twitchClientSecret,
      code: code,
      grant_type: 'authorization_code',
      redirect_uri: twitchAppRedirect,
    };
    
    request.post(twitchATRequestUrl, { json: twitchTokenPayload })
      .then((accessTokenResponse) => {
        const accessToken = accessTokenResponse.access_token;
        console.log('Got an access token: ' + accessToken);
        res.status(200).send('Got an access token: ' + accessToken);
      })
      .catch((error) => {
        console.log('Caught error: ' + error.error.error_description);
        res.status(error.statusCode).send(error.error.error_description);
      });
    

    And this also worked:

    request.post({
    url:     twitchATRequestUrl,
    form:    { client_id: twitchAppClientId,
               client_secret: twitchClientSecret,
               code: code,
               grant_type: "authorization_code",
               redirect_uri:  twitchAppRedirect}
    }, function(error, response, body){
      console.log(JSON.parse(body));
      const jsonStuff = JSON.parse(body);
      const accessToken = jsonStuff.access_token;
      console.log('Got an access token: ' + accessToken);
      res.status(200).send('Got an access token: ' + accessToken);
    });