question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Create a custom provider

See original GitHub issue

Hi, I want to create a Twitch login but i can’t make it works …

This is my custom oauth for twitch

/**
 * Module dependencies.
 */
const util = require('util');
const OAuth2Strategy = require('passport-oauth2');
const { InternalOAuthError } = require('passport-oauth2');


/**
 * `Strategy` constructor.
 *
 * The Twitch authentication strategy authenticates requests by delegating to
 * Twitch using the OAuth 2.0 protocol.
 *
 * Applications must supply a `verify` callback which accepts an `accessToken`,
 * `refreshToken` and service-specific `profile`, and then calls the `done`
 * callback supplying a `user`, which should be set to `false` if the
 * credentials are not valid.  If an exception occured, `err` should be set.
 *
 * Options:
 *   - `clientID`      your Twitch application"s client id
 *   - `clientSecret`  your Twitch application"s client secret
 *   - `callbackURL`   URL to which Twitch will redirect the user after granting authorization
 *
 * Examples:
 *
 *     passport.use(new TwitchStrategy({
 *         clientID: "123-456-789",
 *         clientSecret: "shhh-its-a-secret"
 *         callbackURL: "https://www.example.net/auth/twitch/callback"
 *       },
 *       function(accessToken, refreshToken, profile, done) {
 *         User.findOrCreate(..., function (err, user) {
 *           done(err, user);
 *         });
 *       }
 *     ));
 *
 * @param {Object} options
 * @param {Function} verify
 * @api public
 */
function Strategy(options, verify) {
  options = options || {};
  options.authorizationURL = options.authorizationURL || 'https://id.twitch.tv/oauth2/authorize';
  options.tokenURL = options.tokenURL || 'https://id.twitch.tv/oauth2/token';

  OAuth2Strategy.call(this, options, verify);
  this.name = 'twitch';

  this._oauth2.setAuthMethod('Bearer');
  this._oauth2.useAuthorizationHeaderforGET(true);
}

/**
 * Inherit from `OAuth2Strategy`.
 */
util.inherits(Strategy, OAuth2Strategy);

/**
 * Retrieve user profile from Twitch.
 *
 * This function constructs a normalized profile, with the following properties:
 *
 *   - `provider`         always set to `twitch`
 *   - `id`
 *   - `username`
 *   - `displayName`
 *
 * @param {String} accessToken
 * @param {Function} done
 * @api protected
 */
// eslint-disable-next-line func-names
Strategy.prototype.userProfile = function (accessToken, done) {
  this._oauth2.get('https://api.twitch.tv/helix/users', accessToken, (err, body, res) => {
    if (err) { return done(new InternalOAuthError('failed to fetch user profile', err)); }

    try {
      const json = JSON.parse(body);

      const profile = { provider: 'twitch' };
      profile.id = json.data[0].id;
      profile.userName = json.data[0].login;
      profile.email = json.data[0].email;
      profile.displayName = json.data[0].display_name;
      profile.profileImageUrl = json.data[0].profile_image_url;
      profile.viewCount = json.data[0].view_count;

      profile._raw = body;
      profile._json = json;

      done(null, profile);
    } catch (e) {
      done(e);
    }
  });
};

/**
 * Return extra parameters to be included in the authorization request.
 *
 * @param {Object} options
 * @return {Object}
 * @api protected
 */
// eslint-disable-next-line func-names
Strategy.prototype.authorizationParams = function (options) {
  const params = {};
  if (typeof options.forceVerify !== 'undefined') {
    params.force_verify = !!options.forceVerify;
  }
  return params;
};
/**
 * Expose `Strategy`.
 */
module.exports = Strategy;

I import this custom oauth and create a passport strategy with in passport.js

/**
 * Twitch API OAuth.
 */
passport.use(new Strategy({
  clientID: process.env.TWITCH_CLIENT_ID,
  clientSecret: process.env.TWITCH_CLIENT_SECRET,
  callbackURL: `${process.env.BASE_URL}/auth/twitch/callback`,
  scope: ['user_read', 'chat:read', 'chat:edit', 'whispers:read', 'whispers:edit', 'user:read:email'],
  passReqToCallback: true
},
(req, accessToken, refreshToken, params, profile, done) => {
  console.log({ accessToken, refreshToken, params, profile });
  if (req.user) {
    User.findOne({ twitch: profile.id }, (err, existingUser) => {
      if (existingUser) {
        req.flash('errors', { msg: 'There is already a Twitch account that belongs to you. Sign in with that account or delete it, then link it with your current account.' });
        done(err);
      } else {
        User.findById(req.user.id, (err, user) => {
          if (err) { return done(err); }
          user.twitch = profile.id;
          user.email = profile.email;
          user.tokens.push({
            kind: 'twitch',
            accessToken,
            refreshToken,
            accessTokenExpires: moment().add(params.expires_in, 'seconds').format()
          });
          user.profile.name = user.profile.name || profile.userName || profile.displayName;
          user.profile.picture = user.profile.picture || profile.profileImageUrl;

          user.save((err) => {
            req.flash('info', { msg: 'Twitch account has been linked.' });
            done(err, user);
          });
        });
      }
    });
  } else {
    User.findOne({ twitch: profile.id }, (err, existingUser) => {
      if (err) { return done(err); }
      if (existingUser) {
        return done(null, existingUser);
      }
      User.findOne({ email: profile.email }, (err, existingEmailUser) => {
        if (err) { return done(err); }
        if (existingEmailUser) {
          req.flash('errors', { msg: 'There is already an account using this email address. Sign in to that account and link it with GitHub manually from Account Settings.' });
          done(err);
        } else {
          const user = new User();
          user.twitch = profile.id;
          user.email = profile.email;
          user.tokens.push({
            kind: 'twitch',
            accessToken,
            refreshToken,
            accessTokenExpires: moment().add(params.expires_in, 'seconds').format()
          });
          user.profile.name = user.profile.name || profile.userName || profile.displayName;
          user.profile.picture = user.profile.picture || profile.profileImageUrl;
          user.save((err) => {
            done(err, user);
          });
        }
      });
    });
  }
}));

I add some links in app.js

/**
 * OAuth authorization routes. (API examples)
 */
app.get('/auth/twitch', passport.authorize('twitch', {}));
app.get('/auth/twitch/callback', passport.authorize('twitch', { failureRedirect: '/login' }), (req, res) => {
  res.redirect(req.session.returnTo);
});

I add this in login.pug

      .offset-md-3.col-md-7.pl-2
        a.btn.btn-block.btn-snapchat.btn-social(href='/auth/twitch')
          i.fab.fa-snapchat-ghost.fa-sm
          | Sign in with Twitch

Everything is OK, i can login, everything is in database but i never got a session ! If i create an account with email it works correctly …

What i have missed ?

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6

github_iconTop GitHub Comments

0reactions
tilicancommented, Mar 5, 2020

i got it …

in app.js

/**
 * OAuth authorization routes. (API examples)
 */
app.get('/auth/twitch', passport.authorize('twitch', {}));
app.get('/auth/twitch/callback', passport.authorize('twitch', { failureRedirect: '/login' }), (req, res) => {
  res.redirect(req.session.returnTo);
});

should be

/**
 * OAuth authorization routes. (API examples)
 */
app.get('/auth/twitch', passport.authenticate('twitch', {}));
app.get('/auth/twitch/callback', passport.authenticate('twitch', { failureRedirect: '/login' }), (req, res) => {
  res.redirect(req.session.returnTo || '/');
});
Read more comments on GitHub >

github_iconTop Results From Across the Web

Setup and Implement Read | Terraform - HashiCorp Developer
In these tutorials, you will write a custom provider against the API of a fictional coffee-shop application called HashiCups using the Terraform Plugin ......
Read more >
Create and use a custom resource provider - Azure
This tutorial shows how to create and use an Azure Custom Resource Provider. Use custom resource providers to change workflows on Azure.
Read more >
How to Develop a Custom Provider in Terraform - InfraCloud
Saravanan explores Terraform Custom Provider - what it is and steps to create and build an example Terraform provider. Let's dive in.
Read more >
Writing A Custom Terraform Provider - BoxBoat
The Provider must know the address of the API to communicate with it · The Provider must know how to map specific keywords...
Read more >
Custom Terraform Provider Design: Part 01 | by Sourav Patnaik
This is the Part 01 of creating a Custom Terraform Provider to manage our application. Terraform is an Open-Source Infrastructure as Code (IaC)...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found