Newby Coder header banner

Implementing Jwt Authentication in a React Native Android/iOS application

A Json Web Token or JWT is a token or string which is typically associated with one or more attribute of user data which can uniquely identify a user

It is typically sent from a server to a client(such as mobile app) in the response of a user authentication request

The client then uses this token for subsequent requests to the server, restricting user credentials to authentication apis

A jwt can be associated with an expiry period and additional session data, which is implemented on the server side

Provided application requires a server which performs the authentication and returns a Jwt

Check Nodejs Jwt Authentication Server to implement such a server in Nodejs

Creating new React Native App

Check React Native Installation for installation related info

Use react-native init command to create a new React Native project (here named NcJwtAuthApp)

react-native init NcJwtAuthApp

This creates a directory named NcJwtAuthApp and initializes it as a react native application directory

This can be skipped in case an existing react native project is being integrated into


Dependency

Since this example uses NavigationDrawer component, related packages have to be added

Go to project directory (here NcJwtAuthApp)

cd NcJwtAuthApp

Add react-navigation react-navigation-drawer && react-navigation-stack and associated dependencies to current project using yarn

yarn add react-navigation react-navigation-drawer react-navigation-stack \
react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-screens

or using npm

npm install react-navigation react-navigation-drawer react-navigation-stack \
react-native-gesture-handler react-native-reanimated react-native-safe-area-context react-native-screens --save

iOS

After yarn add command, cd into ios folder inside project directory

cd ios

Use pod command to install any required CocoaPods dependencies:

pod install

Implementation

Login Page

ViewUser page

To ger user info, authorization string is created with username and password

App Code

Following code of App.js defines

App.js
import React from 'react';
import {
  StyleSheet,
  View,
  Text,
  StatusBar,
  KeyboardAvoidingView,
  TextInput,
  Button, ScrollView
} from 'react-native';

import { createAppContainer } from 'react-navigation';
import { createStackNavigator} from 'react-navigation-stack';
import base64 from 'react-native-base64'

import ViewUser from './ViewUser';


class LoginPage extends React.Component {

  constructor() {
    super();
    this.state = {
      username:'',
      password:''
    }
  }

  navigateToPage(data) {
    const { navigate } = this.props.navigation;
    navigate('User', {
      userData: data
    })
  };

  login() {
    const {username, password} = this.state;
    const encrypted =  base64.encode(password);
    if(username.length < 1) {
      alert('Enter username');
    }
    else if (password.length < 1) {
      alert('enter password');
    }
    else {
      fetch('http://192.168.43.34:4000/users/authenticate', {
        method: 'POST',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({username: username, password: encrypted})
      })
      .then(response => response.json())
      .then(responseJson => {
        this.navigateToPage(responseJson);
      })
      .catch(error => {
        console.error(error);
      });
    }
  };

  render() {
    return (
      <View style={{ backgroundColor: 'white', flex: 1 }}>
        <ScrollView keyboardShouldPersistTaps="handled">
          <KeyboardAvoidingView
            behavior="padding"
            style={{ flex: 1, justifyContent: 'space-between' }}>
            <TextInput
              placeholder="Enter username"
              onChangeText={username => this.setState({ username })}
              style={{ padding:10 }}
            />
            <TextInput
              placeholder="Enter password"
              onChangeText={password => this.setState({ password })}
              style={{ padding:10 }}
              secureTextEntry
            />
            <Button
              title="Submit"
              onPress={this.login.bind(this)}
            />
          </KeyboardAvoidingView>
        </ScrollView>
      </View>
    );
  };
};

const styles = StyleSheet.create({
  engine: {
    position: 'absolute',
    right: 0,
  },
  sectionContainer: {
    marginTop: 32,
    paddingHorizontal: 24,
  },
});


const App = createStackNavigator({
  HomeScreen: {
    screen: LoginPage,
    navigationOptions: {
      title: 'Jwt Auth - Login Page',
    },
  },
  User: {
    screen: ViewUser,
    navigationOptions: {
      title: 'User Page',
    },
  }
});

export default createAppContainer(App);

ViewUser class displays some info about a user

ViewUser.js
import React from 'react';
import { Text, View, Button, TextInput, Image } from 'react-native';


export default class ViewUser extends React.Component {
  constructor(props) {
    super(props);
    this.auth = 'Bearer ' + props.navigation.state.params.userData.token;
    this.state = {
      user_id: props.navigation.state.params.userData.id,
      user_contact: '',
      user_city: '',
      user_country: '',
      user_image: '',
      user_fn: '',
    };
  };

  componentDidMount() {
    this.getUserData();
  };

  async getUserData() {
    var responseJson = null;
    try {
        responseJson = await( await fetch('http://192.168.43.34:4000/users/getInfo', {
        method: 'GET',
        headers: {
          'Authorization': this.auth
        }
      })).json();
    }
    catch(err) {
      console.log("error", err);
    }
    if(responseJson) {
      console.log("viewuser response " + JSON.stringify(responseJson));
      this.setState({
        user_contact: responseJson.userdata.cell,
        user_fn: responseJson.userdata.name.first + ' ' + responseJson.userdata.name.last,
        user_city: responseJson.userdata.location.city,
        user_country: responseJson.userdata.location.country,
        user_image: responseJson.userdata.picture.medium
      });
    }
  };

  render() {
    const { user_id, user_contact, user_city, user_country, user_image, user_fn } = this.state;
    return (
      <View style={{ flexDirection:'row', backgroundColor:'#628367'}}>
        <View style={{ marginLeft: 35, marginRight: 35, margin: 10, flex: 2 }}>
          <Text>Id: {user_id}</Text>
          <Text>Name: {user_fn}</Text>
          <Text>Phone: {user_contact}</Text>
          <Text>City: {user_city}</Text>
          <Text>Country: {user_country}</Text>
        </View>
        <View>
        { user_image.length == 0? null:
          <Image source={{uri:user_image}} style={{ width:100, height:150, marginLeft: 35, marginRight: 35, margin: 10, flex:1, resizeMode:'contain' }}/> }
        </View>
      </View>
    );
  };
}

Run instructions

Running in Android

cd into project directory (here NcJwtAuthApp)

cd NcJwtAuthApp

Run metro server to serve js

react-native start

Go to project directory in another terminal tab

Enter following run command for Android:

react-native run-android
cl-react-native-jwt-auth

Running in ios

cd into project directory (here NcJwtAuthApp)

cd NcJwtAuthApp

Enter following command :

react-native run-ios

This might take some time


If the app shows error about metro server not configured (check Running an App in iOS), then run metro server in another tab:

react-native start

Reload the app

Re-run react-native run-ios command if reloading doesn't work

cm-react-native-jwt-authentication-as1cm-react-native-jwt-authentication-as2