Skip to content

GitHub

To set up GitHub OAuth for your app, you'll need to get your clientId and clientSecret credentials from GitHub. See Creating an OAuth App for instructions.

Configuration

Add your GitHub provider in config/wish.js:

js
// config/wish.js
module.exports.wish = {
  provider: 'github',
  providers: {
    github: {
      clientId: 'your-client-id',
      clientSecret: 'your-client-secret',
      redirect: 'http://localhost:1337/auth/callback'
    }
  }
}

Or use environment variables (Wish automatically detects these):

VariableDescription
GITHUB_CLIENT_IDYour GitHub OAuth App Client ID
GITHUB_CLIENT_SECRETYour GitHub OAuth App Client Secret
GITHUB_CALLBACK_URLThe callback URL registered with GitHub
js
// config/wish.js - credentials loaded from env vars
module.exports.wish = {
  provider: 'github',
  providers: {
    github: {}
  }
}

Customizing Scopes

To request additional permissions from GitHub:

js
// config/wish.js
module.exports.wish = {
  provider: 'github',
  providers: {
    github: {
      scopes: ['user:email', 'read:user', 'repo']
    }
  }
}

See GitHub OAuth Scopes for available scopes.

Defaults

Wish provides these defaults for GitHub (override only what you need):

OptionDefault
scopes['user:email']
scopeSeparator,
tokenUrlhttps://github.com/login/oauth/access_token
userUrlhttps://api.github.com/user

The Redirect

A typical flow is to have a button on your website like "Sign in with GitHub". A good example can be found here.

Clicking that button should call a redirect route you've set in routes.js:

js
'GET /auth/redirect': 'auth/redirect',

Now let's author this auth/redirect action:

js
module.exports = {
  friendlyName: 'Redirect',

  description: 'Redirect auth.',

  inputs: {},

  exits: {
    success: {
      responseType: 'redirect'
    }
  },

  fn: async function () {
    return sails.wish.redirect()
  }
}

INFO

Notice the redirect is a one-line of code and when this action is called, it will redirect to GitHub to begin the OAuth process.

The Callback

Note the callback URL we set above that Wish will callback? Let's also implement that starting from the route in routes.js:

js
'GET /auth/callback': 'auth/callback',
js
module.exports = {
  friendlyName: 'Callback',

  description: 'Callback auth.',

  inputs: {
    code: {
      type: 'string',
      required: true
    }
  },

  exits: {
    success: {
      responseType: 'redirect'
    }
  },

  fn: async function ({ code }, exits) {
    const req = this.req

    // Get the GitHub user info
    const githubUser = await sails.wish.user(code)

    User.findOrCreate(
      { githubId: githubUser.id },
      {
        id: sails.helpers.getUuid(),
        githubId: githubUser.id,
        email: githubUser.email,
        name: githubUser.name,
        githubAvatarUrl: githubUser.avatar_url,
        githubAccessToken: githubUser.accessToken
      }
    ).exec(async (error, user, wasCreated) => {
      if (error) throw error

      // Checks if the user email has changed since last log in
      if (!wasCreated && user.email !== githubUser.email) {
        await User.updateOne({ id: user.id }).set({
          emailChangeCandidate: githubUser.email
        })
      }

      // Checks if the user name has changed since last log in
      if (!wasCreated && user.name !== githubUser.name) {
        await User.updateOne({ id: user.id }).set({
          name: githubUser.name
        })
      }

      if (!wasCreated && user.githubAvatarUrl !== githubUser.avatar_url) {
        await User.updateOne({ id: user.id }).set({
          githubAvatarUrl: githubUser.avatar_url
        })
      }

      if (!wasCreated && user.githubAccessToken !== githubUser.accessToken) {
        await User.updateOne({ id: user.id }).set({
          githubAccessToken: githubUser.accessToken
        })
      }

      // Modify the active session instance.
      req.session.userId = user.id
      return exits.success('/')
    })
  }
}

The above is an actual real world use case of Wish in https://sailscasts.com. You can perform any business logic you want.

There you have it, a GitHub OAuth flow with just two routes!

All open source projects are released under the MIT License.