How to access the returning auth code after Twitch social login

I use Twitch social login, so users can login with their Twitch account. Twitch also offers an API to query profile data such as follower count. For this I would like to implement the authorization code grant flow.

https://id.twitch.tv/oauth2/token
{
client_id=
&client_secret=
&code=gulfwdmys5lsm6qyz4xiz9q32l10. // How to get the code via auth0 
&grant_type=authorization_code
&redirect_uri=
}

For this I need the code to be returned after authorization. I use the following function to login using the Twitch connection.

function loginWithTwitch() {
  webAuth.authorize({
    connection: 'twitch'
  }, function(err) {
    if (err) {
      console.debug('Error: ' + JSON.stringify(err));
      displayError(err);
    }
  });
}

In addition, I use an action in which I call other actions in my backend. Here I want to implement the authorization code grant flow.

exports.onExecutePostLogin = async (event, api) => {
  // Implement authorization code grant flow to access Twitch user API
}

I also need to define a scope for Twitch. The request would look like this. How can this be mapped with auth0?

https://id.twitch.tv/oauth2/authorize?response_type=code&
client_id=...&
redirect_uri=...&
scope=user:read:follows&
state=...

How can I set the scope for Twitch and access the auth code after the user logs in in the action?

The problem here is that what Auth0 issues to your application as the code is usable to get an access token Auth0 issues. This token is for an API you own and manage on Auth0 in the APIs section. In your use case, I understand you need a token for Twitch API which may be non-trivial to access.

I haven’t used Twitch as an IdP, but you may check the user profile to see if there is a refresh or access token for Twitch. Please take a look at this link as it may be helpful.

1 Like

Thanks for your contribution @saltuka

Did you ever discover that there is an Auth0 extension called Custom Social Connections? I just became aware of it and installed it in my dashboard. There it is possible to edit the social connections.

There is a Fetch User Profile Script where the user access token of Twitch is available, so that I do not need the auth code. The following script is the default setup.

I wonder what request method is. Would it be possible to change this code so that I am able to make another request, for example using axios or whatever, I could use the accessToken to call the Twitch user API and add data via the app_metadata.

Do you know more about it? How to execute multiple requests in this script?

I hope the Auth0 community support will be here as well.

function fetchUserProfile(accessToken, context, callback) {
  request.get({
      url: 'https://api.twitch.tv/helix/users',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Client-ID': context.options.client_id
      }
    },
    (err, resp, body) => {
      if (err) {
        return callback(err);
      }
      if (resp.statusCode !== 200) {
        return callback(new Error(`[Response code: ${resp.statusCode}] ${body}`));
      }
      let bodyParsed;
      try {
        let twitchData = JSON.parse(body);
        twitchData = twitchData.data[0];
        bodyParsed = {
          username: twitchData.display_name,
          user_id: twitchData.id,
          picture: twitchData.profile_image_url || '',
          email: twitchData.email || '',
          nickname: twitchData.username || '',
          // Set custom data
          app_metadata: {}
        };
      } catch (jsonError) {
        return callback(new Error(body));
      }
      return callback(null, bodyParsed);
    });
}

UPDATE

I haven’t found any documentation on this, but I just tried a few things and found a solution. I wish this was better documented.

I just used another request method inside to call another API endpoint.

function fetchUserProfile(accessToken, context, callback) {

  request.get({
      url: 'https://api.twitch.tv/helix/users',
      headers: {
        'Authorization': `Bearer ${accessToken}`,
        'Client-ID': context.options.client_id
      }
    },
    (err, resp, body) => {
      if (err) {
        return callback(err);
      }

      if (resp.statusCode !== 200) {
        return callback(new Error(`[Response code: ${resp.statusCode}] ${body}`));
      }

      let bodyParsed;

      // Additional request to fetch more data using user access token
      request.get({
          url: 'https://api.twitch.tv/helix/channels/followers?broadcaster_id=XXX',
          headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Client-ID': context.options.client_id
          }
        },
        (err1, resp1, body1) => {

          try {
            let twitchData = JSON.parse(body);
            twitchData = twitchData.data[0];
            bodyParsed = {
              username: twitchData.display_name,
              user_id: twitchData.id,
              picture: twitchData.profile_image_url || '',
              email: twitchData.email || '',
              nickname: twitchData.username || '',
              app_metadata: {
                response: JSON.stringify(body1)
              }
            };
          } catch (jsonError) {
            return callback(new Error(body));
          }

          return callback(null, bodyParsed);

        }
      );
      
    });

}
1 Like

Hi @ArkasDev your solution looks great.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.