React Native: Implementing Browser-Based Authentication using Expo’s AuthSession Component

Dan Ward
Level Up Coding
Published in
6 min readOct 12, 2018

--

This is an excerpt from my book, the React Native Cookbook, 2nd Edition, from Packt Publishing, due to be published this winter.

This tutorial will cover using Expo’s AuthSession component for implementing authentication in a React Native app. For more information on how to develop apps using Expo you can read my previous article, Expo vs React Native CLI: A Guide to Bootstrapping New React Native Apps.

AuthSession is built on top of Expo’s WebBrowser component, which can be used for opening a website via a browser embedded in the app. The typical login workflow consists of four steps:

  1. User Initiates
  2. Web Browser Opens to Login Page
  3. Authentication Provider Provides a Redirect on Successful Login
  4. React Native App Handles the Redirect

In this app we’ll be using the Spotify API to get Spotify account information for our app via user login. Head over to https://beta.developer.spotify.com/dashboard/applications to create a new Spotify dev account (if you don’t already have one) and to create a new Spotify app. The app can be named whatever you like. Once the app is created with Spotify, you’ll see a Client ID string displayed in the information for your app. We’ll need this ID when building the React Native app.

Getting Ready

We’ll start building this project by creating a new app in Expo. I’ll be using the name browser-based-auth for my app.

The redirect URI also needs to be whitelisted in the Spotify app we created above. The redirect url should be in the form https://auth.expo.io/@YOUR_EXPO_USERNAME/YOUR_APP_SLUG. Since my Expo user name is warlyware, and since this React Native app we’re building is named browser-based-auth, my redirect URI is https://auth.expo.io/@warlyware/browser-based-auth. Be sure to add this to the Redirect URIs list in the Settings of the Spotify app.

How to Do It

1. We’ll start by opening the App.js file in the root of the React Native project. Let’s remove all of the boilerplate code so that we can start from scratch together. The first step is importing the dependencies we will be using.

import React, { Component } from 'react';
import { TouchableOpacity, StyleSheet, Text, View } from 'react-native';
import { AuthSession } from 'expo';
import { FontAwesome } from '@expo/vector-icons';

2. Let’s also declare the client ID as a constants to be used later. Copy the Client ID for the Spotify app we created previously so that we can save it in the CLIENT_ID const.

const CLIENT_ID = Your-Spotify-App-Client-ID;

3. Let’s create the App class and the initial state. The userInfo property will hold the user information we receive back from the Spotify API, and didError is a boolean for tracking whether an error occurred during login.

export default class App extends React.Component {
state = {
userInfo: null,
didError: false
};
// Defined in following steps
}

4. Next, let’s define the method that logs the user into Spotify. The AuthSession component’s getRedirectUrl method provides the redirect URL needed for returning to the React Native app after login, which is the same redirect URI we saved in the Spotify App in the Getting Ready section. We’ll then use the redirect in the login request, which we’ll launch with the AuthSession.startAsync method, passing in an options object with the authUrl property set to the Spotify endpoint for authorizing user data with an app. There’s more information on this URL in the How it Works section at the end of this tutorial.

handleSpotifyLogin = async () => {
let redirectUrl = AuthSession.getRedirectUrl();
let results = await AuthSession.startAsync({
authUrl:
`https://accounts.spotify.com/authorize?client_id=${CLIENT_ID}
&redirect_uri=${encodeURIComponent(redirectUrl)}
&scope=user-read-email&response_type=token`
});
// Defined in next step
};

5. We saved the results of hitting the Spotify endpoint for user authentication in the local variable results. If the type property on the results object returns anything other than ‘success’ then an error occurred, so we’ll update the didError property of state accordingly. Otherwise we’ll hit the /me endpoint with the access token we received from authorization to get the user’s info, which we’ll save to this.state.userInfo.

handleSpotifyLogin = async () => {
if (results.type !== 'success') {
this.setState({ didError: true });
} else {
const userInfo = await axios.get(`https://api.spotify.com/v1/me`, {
headers: {
"Authorization": `Bearer ${results.params.access_token}`
}
});
this.setState({ userInfo: userInfo.data });
}
};

6. Now that the auth related methods are defined, let’s create the render function. We’ll use the FontAwesome Expo icon library to display the Spotify logo, add a button to allow the user to log in, and add methods for rendering either an error or the user info depending on the value of this.state.didError. We’ll also disable the login button once there’s data saved on the userInfo property of state.

render() {
return (
<View style={styles.container}>
<FontAwesome
name="spotify"
color="#2FD566"
size={128}
/>
<TouchableOpacity
style={styles.button}
onPress={this.handleSpotifyLogin}
disabled={this.state.userInfo ? true : false}
>
<Text style={styles.buttonText}>
Login with Spotify
</Text>
</TouchableOpacity>
{this.state.didError ?
this.displayError() :
this.displayResults()
}
</View>
);
}

7. Next, let’s define the JSX for handling errors. The template just displays a generic error message to indicate that the user should try again.

displayError = () => {
return (
<View style={styles.userInfo}>
<Text style={styles.errorText}>
There was an error, please try again.
</Text>
</View>
);
}

8. The displayResults function will be a View component that displays the user’s image, username, and email address if there is userInfo saved to state, otherwise it will prompt the user to log in.

displayResults = () => {
{ return this.state.userInfo ? (
<View style={styles.userInfo}>
<Image
style={styles.profileImage}
source={ {'uri': this.state.userInfo.images[0].url} }
/>
<View>
<Text style={styles.userInfoText}>
Username:
</Text>
<Text style={styles.userInfoText}>
{this.state.userInfo.id}
</Text>
<Text style={styles.userInfoText}>
Email:
</Text>
<Text style={styles.userInfoText}>
{this.state.userInfo.email}
</Text>
</View>
</View>
) : (
<View style={styles.userInfo}>
<Text style={styles.userInfoText}>
Login to Spotify to see user data.
</Text>
</View>
)}
}

9. The styles for this recipe are quite simple. It uses a column flex layout, applies the Spotify color scheme of black and green, and adds font sizes and margins.

const styles = StyleSheet.create({
container: {
flexDirection: 'column',
backgroundColor: '#000',
flex: 1,
alignItems: 'center',
justifyContent: 'space-evenly',
},
button: {
backgroundColor: '#2FD566',
padding: 20
},
buttonText: {
color: '#000',
fontSize: 20
},
userInfo: {
height: 250,
width: 200,
alignItems: 'center',
},
userInfoText: {
color: '#fff',
fontSize: 18
},
errorText: {
color: '#fff',
fontSize: 18
},
profileImage: {
height: 64,
width: 64,
marginBottom: 32
}
});

10. Now if we run the app, we should be able to log into Spotify, and see the associated image, username, and email address for the account used to log in!

How it Works

In step 4, we created the method for handling the Spotify login process. The AuthSession.startAsync method just needs an authUrl which is provided by the Spotify developer documentation. The four pieces required are the Client ID, the redirect URI for handling the response from Spotify, a scope parameter indicating the scope of user information the app is requesting, and a response_type parameter of token. We only need basic information from the user, so we requested a scope type of user-read-email. For information on all the scopes available, check the documentation at https://beta.developer.spotify.com/documentation/general/guides/scopes/.

In step 5, we completed the Spotify login handler. If the login was not successful, we updated didError on state accordingly. If it was successful, we used that response to access the Spotify API endpoint for getting user data [https://api.spotify.com/v1/me]. We defined the Authorization header of the get request with Bearer ${results.params.access_token} to validate the request, per Spotify’s documentation. On the success of this request, we store the returned user data in the userInfo state object, which will re-render the UI and display the user’s information.

For a deeper dive into Spotify’s auth process, you can find the guide at https://beta.developer.spotify.com/documentation/general/guides/authorization-guide/.

You can also take a look at the source code for this tutorial on GitHub at https://github.com/warlyware/react-native-cookbook/tree/master/chapter-5/browser-based-auth.

If you found this article helpful, please take a moment to👏 👏 👏. You can also follow me for more articles on React Native, Vue, and JavaScript development.

--

--