Social Authentication

Ally is a 1st party social authentication provider for AdonisJs.

Using Ally makes it trivial to authenticate users via 3rd party websites like Google, Twitter, and Facebook.

The Ally Provider supports the following drivers:

  • Facebook (facebook)

  • Github (github)

  • Google (google)

  • Instagram (instagram)

  • Linkedin (linkedin)

  • Twitter (twitter)

  • Foursquare (foursquare)

Setup

As the Ally Provider is not installed by default, we need to pull it from npm:

> adonis install @adonisjs/ally

Next, register the provider inside the start/app.js file:

start/app.js
const providers = [
  '@adonisjs/ally/providers/AllyProvider'
]
Social authentication configuration is saved inside the config/services.js file, which is created by the adonis install command when installing the Ally Provider.

Config

Your config must be stored inside the config/services.js file’s ally object:

config/services.js
module.exports = {
  ally: {
    facebook: {}
  }
}
You can always access the latest config source file on Github.

Basic Example

Let’s start with a basic example of logging in using Facebook.

First, we need to register routes to redirect the user to Facebook then handle the response when the user is redirected back from Facebook:

start/routes.js
Route.get('login/facebook', 'LoginController.redirect')
Route.get('facebook/callback', 'LoginController.callback')
Make sure the Auth Provider and auth-related middleware is configured correctly.

Next, we need to create the controller to implement our route methods:

> adonis make:controller Login
app/Controllers/Http/LoginController.js
const User = use('App/Models/User')

class LoginController {
  async redirect ({ ally }) {
    await ally.driver('facebook').redirect()
  }

  async callback ({ ally, auth }) {
    try {
      const fbUser = await ally.driver('facebook').getUser()

      // user details to be saved
      const userDetails = {
        email: fbUser.getEmail(),
        token: fbUser.getAccessToken(),
        login_source: 'facebook'
      }

      // search for existing user
      const whereClause = {
        email: fbUser.getEmail()
      }

      const user = await User.findOrCreate(whereClause, userDetails)
      await auth.login(user)

      return 'Logged in'
    } catch (error) {
      return 'Unable to authenticate. Try again later'
    }
  }
}

We now have a fully working login system in a few lines of code!

Ally’s API is consistent across drivers, so it’s easy to swap facebook with google or any other driver required by your application.

Ally API

Below is the list of available functions.

redirect

Redirect user to the 3rd party website:

await ally.driver('facebook').redirect()

getRedirectUrl

Get redirect URL back as a string:

const url = await ally.driver('facebook').getRedirectUrl()

return view.render('login', { url })

scope(scopesArray)

Define runtime scopes before redirecting the user:

await ally
  .driver('facebook')
  .scope(['email', 'birthday'])
  .redirect()
Check the relevant provider’s official OAuth documentation for a list of their available scopes.

fields(fieldsArray)

Fields to be fetched when getting the authenticated user profile:

await ally
  .driver('facebook')
  .fields(['username', 'email', 'profile_pic'])
  .getUser()

getUser

Get the user profile of an authenticated user (returns an AllyUser instance):

await ally
  .driver('facebook')
  .fields(['email'])
  .getUser()

getUserByToken(accessToken, [accessSecret])

Returns the user details using the accessToken:

await ally.getUserByToken(accessToken)

This is helpful when using client-side code to perform the OAuth action and you have access to the accessToken.

The accessSecret parameter is required when the OAuth 1 protocol is used (e.g. Twitter relies on OAuth 1).

User API

Below is the list of available methods on an AllyUser instance.

getName

Returns the user name:

const user = await ally.driver('facebook').getUser()

user.getName()

getEmail

Returns the user email:

user.getEmail()
Some 3rd party providers do not share email, in which case this method returns null.

getNickname

Returns the nickname / display name of the user:

user.getNickname()

getAvatar

Returns public URL to the user’s profile picture:

user.getAvatar()

getAccessToken

Returns the access token which may be used later to update the user profile:

user.getAccessToken()

getRefreshToken

Refresh token to be used when access token expires:

user.getRefreshToken()
Available only when 3rd party provider implements OAuth 2.

getExpires

Access token expiry data:

user.getExpires()
Available only when 3rd party provider implements OAuth 2.

getTokenSecret

Returns token secret:

user.getTokenSecret()
Available only when 3rd party provider implements OAuth 1.

getOriginal

Original payload returned by the 3rd party provider:

user.getOriginal()