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.