Reindex
TeamBlogDocs
By

Using Auth0 with Reindex

Auth0 is an amazing service for handling authentication in your apps. It not only supports many popular social login APIs, but also has ready-made libraries and UI components to really speed up your application development. Reindex supports Auth0 as an authentication provider, and we actually use it for our own dashboard app. In this blog post, I’ll describe various ways to use Auth0 with Reindex.

First, I’ll cover how to set up Auth0 in Reindex. Then I’ll continue to basic use cases using the Lock component in React and React Native. Finally, I will cover common patterns for using Auth0 in Reindex—copying the profile info and using the Auth0 API.

Basic Configuration

Once you are registered in both Reindex and Auth0, take note of the Auth0 domain, Client ID, and Client Secret. Then go to the Reindex Dashboard and click Open GraphiQL on your app. Alternatively, you can run reindex graphiql at the Reindex CLI.

In GraphiQL, run the following command, replacing the dummy values with your Auth0 credentials:

mutation {
  createReindexAuthenticationProvider(input: {
    type: auth0,
    isEnabled: true,
    domain: "YOUR-AUTH0-DOMAIN.auth0.com",
    clientId: "YOUR-AUTH0-CLIENT-ID",
    clientSecret: "YOUR-AUTH0-CLIENT-SECRET",
  }) {
    id
  }
}

Now Reindex is configured to accept Auth0 as an authentication provider.

React Example with Auth0 Lock

First, you need to install dependencies:

npm install --save reindex-js auth0-lock

Note that if you are using webpack, you will need to add transforms for the Auth0 lock.

Let’s write a function that opens the Auth0 lock and logs the user into Reindex. You can put it in the file login.js. It will accept an instance of Reindex from reindex-js and perform a login.

import Auth0Lock from 'auth0-lock';

export default function login(auth0Options, reindex) {
  const lock = new Auth0Lock('YOUR-AUTH0-CLIENT-ID', 'YOUR-AUTH0-SECRET');
  lock.show(auth0Options, (err, profile, idToken) => {
    if (err) {
      console.log(err);
      return;
    }
    reindex.loginWithToken('auth0', idToken)
      .catch((err) => {
        console.log(err)
      });
  });
}

You can use this function in your main React component. The function will listen for the the Reindex library’s tokenChange event (which indicates whether the user is logged in or not) and provide a link for logging in or out. The Reindex library stores the token locally and will automatically load it during initialization, so you don’t need to do any additional work there.

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Reindex from 'reindex-js';

import login from './login';

const reindex = new Reindex('https://YOUR-REINDEX-APP.myreindex.com');

class Main extends Component {
  constructor() {
    super();
    this.state = {
      isLoggedIn: reindex.isLoggedIn(),
    };
  }

  componentDidMount() {
    reindex.addListener('tokenChange', this.handleTokenChange);
  }

  componentWillUnmount() {
    reindex.removeListener('tokenChange', this.handleTokenChange);
  }

  handleTokenChange = () => {
    this.setState({ isLoggedIn: reindex.isLoggedIn() });
  };

  handleLogin = () => {
    login({}, reindex);
  }

  handleLogout = () => {
    reindex.logout();
  }

  render() {
    if (this.state.isLoggedIn) {
      return (
        <button onClick={this.handleLogout}>Logout</button>
      );
    } else {
      return (
        <button onClick={this.handleLogin}>Login</button>
      );
    }
  }
}

You can use the Reindex Starter Kit with Auth0, which already implements the solution above.

React Native Example with Auth0 Lock

Unlike browsers, React Native doesn’t have a synchronous LocalStorage, so it can’t incorporate the solution above. You can use the AsyncStorage API, which is similar to LocalStorage, but asynchronous. In addition, a Auth0 React Native lock should be used instead of a browser-based one.

First, let’s install the dependencies:

npm install --save reindex-js react-native-lock
rnpm link react-native-lock

On Android, you also need to add information about the lock to Manifest.xml.

The login function will change a bit to accommodate the AsyncStorage.

import Auth0Lock from 'react-native-lock';

export async function login(auth0Options, reindex) {
  const reindexToken = await AsyncStorage.getItem('REINDEX_TOKEN');
  if (reindexToken) {
    reindex.setToken(reindexToken);
    return;
  }

  const lock = new Auth0Lock({
    clientId: 'YOUR-AUTH0-CLIENT-ID',
    domain: 'YOUR-AUTH0-DOMAIN',
  });
  lock.show(auth0Options, async (err, profile, idToken) => {
    if (err) {
      console.log(err);
      return;
    }
    const reindexResponse = await reindex.loginWithToken('auth0', idToken);
    await AsyncStorage.setItem('REINDEX_TOKEN', reindexResponse.token);    
  });
}

Your main component can stay mostly the same; the only difference is that you need to replace DOM components in render() with relevant Native components.

class Main extends Component {
  // ...

  render() {
    if (this.state.isLoggedIn) {
      return (
        <TouchableHighlight onPress={this.handleLogout}>
          <Text>
            Logout
          </Text>
        </TouchableHighlight>
      );
    } else {
      return (
        <TouchableHighlight onPress={this.handleLogin}>
          <Text>
            Login
          </Text>
        </TouchableHighlight>
      );
    }
  }
}

Copying Auth0 Profile into Reindex User

When you call reindex.loginWithToken, Reindex will check that the Auth0 id_token is valid and save the Auth0 id and profile information in the user’s credentials.auth0 field. To maintain privacy, only the user can read this field, so, if you want to reveal some of the profile info to other users, you need to copy it. First, you need to add fields to the User profile in your Reindex Schema:

[
  {
    name: "User",
    kind: "OBJECT",
    interfaces: [
      "Node"
    ],
    fields: [
      {
        "name": "id",
        "type": "ID",
        "nonNull": true,
        "unique": true
      },
      {
        "name": "username",
        "type": "String"
      },
      {
        "name": "email",
        "type": "String"
      },
      {
        "name": "avatarUrl",
        "type": "String"
      },
      // ... Other fields
    ],
  // ... Other types
]

Remember to push your schema with reindex schema-push.

There are two ways to copy the data from Auth0 profile to publicly readable fields in User type. You can call the mutation manually in your login function or use a Relay Mutation.

In Login Function

After you’ve logged in with the loginWithToken, you can issue a GraphQL mutation to update the user.

export default function login(auth0Options, reindex) {
  const lock = new Auth0Lock('YOUR-AUTH0-CLIENT-ID', 'YOUR-AUTH0-SECRET');
  lock.show(auth0Options, async (err, profile, idToken) => {
    if (err) {
      console.log(err);
      return;
    }
    await reindex.loginWithToken('auth0', idToken)
      .catch((err) => {
        console.log(err)
      });
    await reindex.query(`
      mutation($input: _UpdateUserInput!) {
        updateUser(input: $input) {
          id
        }
      }
    `, {
      input: {
        id: reindexResponse.user.id,
        username: profile.nickname,
        avatarUrl: profile.picture,
        email: profile.email,
      },
    });
  });
}

In Relay Mutation

Alternatively, you can update the user with a Relay mutation.

import Relay from 'react-relay'

export default class UpdateUserInfoMutation extends Relay.Mutation {
  static fragments = {
    user: () => Relay.QL`
      fragment on User {
        id
        credentials {
          auth0 {
            displayName
            picture
            email            
          }
        }
      }
    `
  };

  getMutation() {
    return Relay.QL`mutation { updateUser }`
  }

  getVariables() {
    return {
      id: this.props.user.id,
      username: this.props.user.credentials.auth0.displayName,
      email: this.props.user.credentials.auth0.email,
      avatarUrl: this.props.user.credentials.auth0.picture,
    };
  }

  getFatQuery() {
    return Relay.QL`
      fragment on _UserPayload {
        changedUser {
          username
          email
          avatarUrl
        }
      }
    `
  }

  getConfigs() {
    return [
      {
        type: 'FIELDS_CHANGE',
        fieldIDs: {
          changedUser: this.props.user.id,
        },
      },
    ]
  }

  getOptimisticResponse() {
    return {
      changedUser: {
        username: this.props.user.credentials.auth0.displayName,
        email: this.props.user.credentials.auth0.email,
        avatarUrl: this.props.user.credentials.auth0.picture,
      }
    }
  }
}

You can run this mutation in componentDidMount of your main component.

Using Auth0 API

The user’s Auth0 access token is stored inside credentials.auth0.accessToken. It can be used to access calls in the Auth0 Authentication API, such as retrieving the User Profile.

async function getProfile(user)
  const profileResponse = await fetch(
    `https://YOUR-AUTH0-DOMAIN/userinfo`,
    {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${user.credentials.auth0.accessToken}`,
      },
    }
  );
  return profileResponse.json();
}

Conclusion

At Reindex, we want to empower product developers to build their apps better and faster. We believe that Auth0 is a technology that immensely helps developers with that. With Reindex and Auth0, you don’t need to worry about your backend or authentication because they are handled for you.

Further Reading

Written by
CTO & Co-founder

Reindex Blog