Building and Securing Your First App - Android Tutorial

  • 2019-04-11 02:06 AM
  • 265

You will learn how to develop a simple to-do list Android app from scratch & learn how to integrate your Android application with a backend API.

TL;DR: Here, you will start by scaffolding your app with the help of Android Studio. After that, you will build a list to show to-do items and you will create a form to enable users to update this list. In the end, you will also learn how to secure your to-do app with Auth0. If you need to, you can check the full code developed throughout this tutorial in this GitHub repository.

Android Tutorial: Building and Securing Your First App (Part 1)

Prerequisites

To follow along with this tutorial, there are two things you will need and a third one that you can benefit from. First, you will need Java Development Kit 7 (JDK 7) or higher on your computer. If you don’t have it, follow the instructions here to download a JDK.

Second, you will need Android Studio, the official Integrated Development Environment (IDE) for Android. If you don’t have it yet, you can download Android Studio from this resource.

Lastly, if you have prior knowledge around Java development, you will benefit a lot from it. However, this is not a hard requirement. If you are new to Java (but have experience with some other programming languages), you might still find it easy to follow the instructions here.

Scaffolding an Android App

Scaffolding a new Android application is quite easy. For starters, open the Android Studio and, on the splash screen, click on Start a new Android Studio project. After clicking on it, the IDE will ask you to choose your project. Make sure you are on the Phone and Tablet tab, click on the Empty Activity option, then click on Next.

Using Android Studio to scaffold a new Android project.

After clicking on this button, the IDE will show you a form that you can fill in as follows:

  • Name: “To-Do List”
  • Package name: com.auth0.todo
  • Save location: Use the default value or adjust to your needs.
  • Language: “Java”
  • Minimum API level: “API 21: Android 5.0 (Lollipop)”

From the properties above, there are two items that you can change: name and save location. Apart from that, you can also change the package name, but be aware that this tutorial uses this value multiple times (so, you will have to replace them a lot too). The other two properties, language and minimum API level, must remain untouched. So, leave them like that and click on the Finish button.

Configure the final settings of your new Android project.

After clicking on the finish button, Android Studio will scaffold your new project for you, and it will open its source code on a new window. Now, the next thing you can do is to run your new (and empty) app to confirm that everything is in place. For that, you have two options: you can run the app on a real device (like your Android mobile phone), or you can use an emulator. The latter is the easiest approach but, check this resource if you want to learn how to run it on a real device.

If you opt to use an emulator, you can proceed as follows:

  • In the IDE, click on the green Run button in the toolbar.
  • In the Select Deployment Target window, click Create New Virtual Device.
  • In the Select Hardware screen, select a phone device, such as Nexus 5, and then click Next.
  • In the System Image screen, select the version with the highest API level. If you don’t have that version installed, the IDE will show a Download link. If that is the case, click the link and complete the download.
  • Click Next.
  • On the Android Virtual Device (AVD) screen, leave all the settings alone and click Finish.
  • Back in the Select Deployment Target dialog, select the device you just created and click OK.

Clicking on the OK button will make Android Studio start the emulator (it can take a couple of minutes as it is the first time you are using it) and open the app on it. You should now see “Hello World!” displayed in the app running on the emulator.

Running the Hello World Android app.

Adding Android Material to Your Project

By default, the Android framework provides a bunch of UI components that you can use to build your app. These components are quite flexible and there is nothing wrong on using them. However, as their default appearance is a bit ugly, you will be better off using some more advanced component framework.

In this tutorial, to avoid having to invest too much time on the UI and to avoid ending up with an ugly app, you will use one of the most popular component libraries available: Android Material. This library provides components that adhere to the Material Design visual language that Google created. This visual language allows developers to:

  • rely on classic principles of good design;
  • and to unify the user experience across platforms, devices, and input methods.

To install this library, open the ./app/build.gradle in your project, and update the dependencies section as follows:

// ./app/build.gradle

dependencies {
    // ... leave the rest untouche and add ...
    implementation 'com.google.android.material:material:1.0.0'
}

After adding this dependency to your project, you will need to click the Sync Now link that the IDE shows to download the Material library (if you don’t, you won’t be able to use the Material components in your project). Then, click on the Refactor menu in your IDE (at the horizontal menu at the top) and click on the Migrate to AndroidX option. You will need this to update your app’s dependencies and code to use the new androidx package and the com.google.android.material library.

Lastly, you can open the AndroidManifest.xml file and replace the value that you have on the android:theme property of the application element:

<!-- ./app/src/main/AndroidManifest.xml -->

<manifest ...>

    <application
        ...
        android:theme="@style/Theme.MaterialComponents.Bridge">
        <!-- Main Activity -->
    </application>

</manifest>

The new value you are using is changing the theme (the look and feel) of your app to a darker one.

That’s it for the moment. In the next section, you will use your first Android Material component.

Showing a Static List of To-Do Items

After testing your hello-world app and adding Android Material to your project, it is time to start developing your new app. To begin with, you will remodel the main activity of your Android app to show a list of static to-do items.

An activity is a single, focused thing that the user can do. Almost all activities interact with the user, so the Activity class takes care of creating a window for you in which you can place your UI (User Interface). - Android Docs

In Android, to define how an activity will look like, you will usually use layout resources. These resources are XML files that reside in the ./app/src/main/res/layout/ directory of your application. For example, if you open this directory, you will see a file called activity_main.xml there. Then, if you open the MainActivity class source code (./app/src/main/java/com/auth0/todo/MainActivity.java), you will see that this class calls the setContentView method passing R.layout.activity_main as the parameter.

With that information, the Android framework will know that you want to use the activity_main layout resource (R stands for resource, hence R.layout.activity_main) to set the content view (setContentView) of the MainActivity class. Knowing that, the framework will interpret this file to compose your UI.

Now that you know more about how this process works, open the activity_main.xml file, and replace its code with this:

<!-- ./app/src/main/res/layout/activity_main.xml -->

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ListView
        android:id="@+id/to_do_items"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:divider="@null"
        android:paddingTop="8dp"
        android:paddingBottom="8dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

The only change on this file is that you are adding a component called ListView that has @id/to_do_items as its identifier (note that the + sign after @ is telling Android that you are defining this id here, not using it). Don’t worry about the other properties now. After creating your first Android application, you can learn more about them.

With that in place, you will create a new layout resource that your app will use to show each to-do item in particular. So, create a new file called to_do_item.xml inside ./app/src/main/res/layout/ and add the following code to it:

<!-- ./app/src/main/res/layout/to_do_item.xml -->

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent"
    android:clipToPadding="false"
    android:orientation="vertical"
    android:paddingLeft="16dp"
    android:paddingTop="8dp"
    android:paddingRight="16dp"
    android:paddingBottom="8dp">

    <com.google.android.material.card.MaterialCardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/to_do_message"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="16dp"
            android:textSize="24sp" />
    </com.google.android.material.card.MaterialCardView>
</LinearLayout>

Although verbose, this XML file is quite simple to understand. Here, you are using a LinearLayout component to serve as the parent of another component called MaterialCardView. Then, inside this card view, you are defining a TextView that will receive the description of the to-do item it represents.

Note: The primary reason to nest cards inside LinearLayout is to define some space around (android:padding...) each one of them.

Now, to make your app use this new layout resource, you will need to create an adapter. Adapters, as explained by the official documentation, exist to act as a bridge between view and the underlying data. In this case, you will use an adapter to make your app use the new resource to render to-do items on the ListView you added to the activity_main.xml file.

As you are dealing with to-do items, you will name this adapter ToDoListAdapter. To add this class to the project, create a new package called util inside com.auth0.todo. Then, create the ToDoListAdapter class inside the new package and add the following code to it:

// ./app/src/main/java/com/auth0/todo/util/ToDoListAdapter.java

package com.auth0.todo.util;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.auth0.todo.R;

import java.util.ArrayList;
import java.util.List;

public class ToDoListAdapter extends BaseAdapter {
    private LayoutInflater inflater;
    private List<String> toDoList = new ArrayList<>();

    public ToDoListAdapter(Context context) {
        toDoList.add("My first task");
        toDoList.add("My second task");
        inflater = LayoutInflater.from(context);
    }

    @Override
    public View getView(int position, View view, ViewGroup parent) {
        String message = (String) getItem(position);
        if (view == null) {
            view = inflater.inflate(R.layout.to_do_item, null);
        }

        TextView textView = view.findViewById(R.id.to_do_message);
        textView.setText(message);

        return view;
    }

    @Override
    public Object getItem(int position) {
        return toDoList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getCount() {
        return toDoList.size();
    }
}

As you can see, this class extends BaseAdapter and overrides four of its methods (getView, getItem, getItemId, and getCount) to render the to-do list. To do so, the getView method receives a position parameter and uses it to get the item (getItem) of the to-do list it must render. Then, getView extracts the message of this to-do item and uses it to populate the TextView element (the one you put inside MaterialCardView).

Note: Your app will call getView for each one of the to-do items the adapter holds. The app will know how many items the adapter has through the getCount method and, as explained, will use getItem to get each one in particular.

For now, your adapter is using a static to-do list that contains two items. You are defining this static list on the constructor of the ToDoListAdapter class.

After defining the adapter, you will have to open the MainActivity class and update it as follows:

// ./app/src/main/java/com/auth0/todo/MainActivity.java

// ... other import statements ...
import android.widget.ListView;
import com.auth0.todo.util.ToDoListAdapter;

public class MainActivity extends AppCompatActivity {
    private ToDoListAdapter toDoListAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ... super.onCreate and setContentView ...

        // create and configure the adapter
        this.toDoListAdapter = new ToDoListAdapter(this);
        ListView toDoItemsListView = findViewById(R.id.to_do_items);
        toDoItemsListView.setAdapter(toDoListAdapter);
    }
}

The new version of this class is defining a field that references the ToDoListAdapter class, and it is using the onCreate lifecycle method to create and configure this adapter. As you can see, you are making the ListView element (the one you added to activity_main.xml) use your new adapter (setAdapter(toDoListAdapter)).

After these changes, if you hit the play button again, you will see the new version of your app with a static to-do list (and with a dark theme).

Using Android Material to create a static to-do list Android app.

Allowing Users to Insert To-Do Items

Now that you have built an app capable of showing a list of to-do items, the next logical thing to do is to enhance it to enable users to insert more items. To accomplish this, you will create a new activity that will implement this feature. So, for starters, create a new file called activity_to_do_form.xml inside ./app/src/main/res/layout/ (this will be the layout resource of the activity) and add the following code to it:

<!-- ./app/src/main/res/layout/activity_to_do_form.xml -->

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ToDoFormActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:ems="10"
        android:hint="@string/to_do_message"
        android:inputType="textPersonName"
        app:layout_constraintEnd_toStartOf="@+id/button"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:onClick="addToDoItem"
        android:text="@string/button_insert"
        app:layout_constraintBaseline_toBaselineOf="@+id/editText"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/editText" />
</androidx.constraintlayout.widget.ConstraintLayout>

This layout resource is using a ConstraintLayout to put two elements side by side:

  • an EditText where users will input the description of the new to-do item;
  • a Button that, when clicked, will add the to-do item in the list.

Note that the layout above is using two string resources: @string/to_do_message and @string/button_insert. On Android development, it is a best practice to use String resources to declare static text. So, open the strings.xml file and replace its contents with this:

<!-- ./app/src/main/res/values/strings.xml -->

<resources>
    <string name="app_name">To-Do List</string>
    <string name="to_do_message">Describe your to-do item</string>
    <string name="button_insert">Insert</string>
</resources>

This will make your input text show (while empty) a message saying “Describe your to-do item”, and will add “Insert” as the label of the button.

Next, you will create the activity’s class that will render and handle this layout. In this case, you will create a file called ToDoFormActivity.java inside the com.auth0.todo package and you will add the following code to it:

// ./app/src/main/java/com/auth0/todo/ToDoFormActivity.java

package com.auth0.todo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

import androidx.appcompat.app.AppCompatActivity;

public class ToDoFormActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_to_do_form);
    }

    public void addToDoItem(View view) {
        EditText editText = findViewById(R.id.editText);
        String message = editText.getText().toString();

        Intent returnIntent = new Intent();
        returnIntent.putExtra("item", message);
        setResult(Activity.RESULT_OK, returnIntent);
        finish();
    }
}

Here, on the onCreate method, you are defining that this activity will use the activity_to_do_form layout resource. As this resource has a button that depends on a method called addToDoItem, you are defining it here as well. This method, when triggered, reads the message inserted by the user and send it back to the main activity.

Now you are probably wondering: “What does ‘send it back to the main activity’ really mean?” As you will soon see, the main activity will start this activity through a method called startActivityForResult. By using this method, the activity is telling Android that it wants to create a temporary ToDoFormActivity to get a result back from it (in this case, the message that the user writes on the text field).

To wrap the creation of the new activity, you will need to register it in your app. So, open the AndroidManifest.xml file and update it as follows:

<!-- ./app/src/main/AndroidManifest.xml -->

<manifest ...>

    <application ...>
        <activity android:name=".MainActivity">
        ...
        </activity>

        <!-- NEW: register ToDoFormActivity -->
        <activity android:name=".ToDoFormActivity"></activity>
    </application>

</manifest>

Having done that, open the activity_main.xml file and update it as follows:

<!-- ./app/src/main/res/layout/activity_main.xml -->

<androidx.constraintlayout.widget.ConstraintLayout ...>

    <!-- ... ListView ... -->

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/floatingActionButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="end|bottom"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="16dp"
        android:onClick="openToDoForm"
        android:src="@drawable/ic_add_white_24dp"
        app:layout_constraintBottom_toBottomOf="@id/to_do_items"
        app:layout_constraintEnd_toEndOf="@id/to_do_items" />
</androidx.constraintlayout.widget.ConstraintLayout>

This will add a Floating Action Button (a.k.a, FAB) to your main activity. If you take a close look at the XML you just added, you will see that, among other things, it is defining that this button will call openToDoForm when clicked. Also, the XML is telling Android that it wants to use an icon (android:src) that has the following id: @drawable/ic_add_white_24dp.

So, first, you will create the icon that will appear on the button. To do this, create a file called ic_add_white_24dp.xml inside ./app/src/main/res/drawable/ and insert the following code to it:

<!-- ./app/src/main/res/drawable/ic_add_white_24dp.xml -->

<vector android:height="24dp" android:tint="#FFFFFF"
    android:viewportHeight="24.0" android:viewportWidth="24.0"
    android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
    <path android:fillColor="#FF000000" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
</vector>

This file defines a vector that will draw a plus (+) sign in your button.

Now, you can open the MainActivity class and update it as follows:

// ./app/src/main/java/com/auth0/todo/MainActivity.java

package com.auth0.todo;

// ... other import statements ...
import android.content.Intent;
import android.view.View;

public class MainActivity extends AppCompatActivity {
    // ... ToDoListAdapter and onCreate definition ...

    public void openToDoForm(View view) {
        startActivityForResult(new Intent(this, ToDoFormActivity.class), 1);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 1) {
            if (resultCode == RESULT_OK) {
                String newItem = data.getStringExtra("item");
                this.toDoListAdapter.addItem(newItem);
            }
        }
    }
}

Here, you are adding two new methods:

  • openToDoForm: This method, as mentioned before, will use the startActivityForResult method to start the ToDoFormActivity (and to get a result back from it).
  • onActivityResult: This method will get the value inserted on the ToDoFormActivity and add to the toDoListAdapter instance.

Note: To use startActivityForResult, you have to inform an integer that represents the “operation” you want the new activity to perform. In the code above, you are using 1 to represent this operation. That’s why you check if requestCode == 1 inside the onActivityResult method. Check this resource to learn more about startActivityForResult.

If you recall, your ToDoListAdapter class you created earlier doesn’t have a method called addItem. So, open this class and add the method:

// ./app/src/main/java/com/auth0/todo/util/ToDoListAdapter.java

// ... package definition and import statements ...

public class ToDoListAdapter extends BaseAdapter {
    // ... other fields and methods ...

    public void addItem(String newItem) {
        toDoList.add(newItem);
        notifyDataSetChanged();
    }
}

This change will make your adapter add the new item to the toDoList instance and will make the adapter notify (through the notifyDataSetChanged) the UI about the change. This notification will allow Android to adjust the view accordingly (i.e., create the card for the new item).

With that in place, you have finished creating and integrating the form that will allow users to add new to-do items. So, click on the green play button to reload your app, and test it to see if everything is working as expected.

Creating a new Android activity to allow users to add to-do items to the list.

Note: If you change the orientation of your device (from vertical to horizontal, for example), you might end up losing the new items added to the to-do list. This problem happens because Android reconstructs the view on such scenarios, calling the onCreate lifecycle method again (which ends up creating a new ToDoListAdapter instance). On the second part of this tutorial, you will fix this situation by adding a backend API to support your app.

Securing Android Apps with Auth0

Cool, you now have a simple to-do application that persists items in memory. In the second part of this tutorial, you will learn how to integrate this Android app with a backend API. The idea is to be able to provide a persistent database to your app, so your users can rest assured they will have access to their items even if they lose their phones. However, the best thing you can do now is to learn how to secure your app.

By using Auth0, as you will see, providing means so users can authenticate themselves is quite easy. You will have to start by creating an Auth0 account (or logging into an existing one), then you will have to configure some properties in your Auth0 dashboard, then you will need to make some changes in your code. After that, you will have a consistent, full-featured identity management system that will allow users to sign up, sign in, reset passwords, activate multifactor authentication, and more.

If this sounds interesting, keep reading!

Creating and configuring an Auth0 account

For starters, if you don’t have one yet, you can sign up for a free Auth0 account now (if you already have one, feel free to reuse it). After that, go to the Applications section of your Auth0 dashboard and click on Create Application.

When you click on this button, Auth0 will show you a dialog where it will ask you for two things:

  • Name: Here, you can type an identifier for your application (e.g., “Android To-Do App”).
  • Application Type: Here, you will have to choose “Native”.

After filling in this form, click on the Create button. Doing so will make Auth0 redirect you to the Quick Start section of your new application. From there, head to the Settings section, and search for the Allowed Callback URLs field. In this field, insert the following value:

  • to-do://<YOUR-AUTH0-DOMAIN>/android/com.auth0.todo/callback

Note: You will have to replace <YOUR-AUTH0-DOMAIN> with the value available on the Domain property of your new Auth0 Application (you can find it at the top of the page). Also, if you have chosen to use a package name different than com.auth0.todo, you will have to change that too.

The authentication process at Auth0 happens on a hosted login page. That is, when your app starts the authentication process, it will open the login page in a browser and, after the authentication takes place, will redirect your user back to your app. This redirection works because your app will register a deep link (the one you are adding to the Allowed Callback URLs field) in the Android device. Then, as you will configure Auth0 to call this deep link, the device will know that it has to open your app again (passing any information that the deep link provides).

Therefore, after updating the Allowed Callback URLs field, click on the Save Changes button at the bottom of the page and leave the page open. You will need to copy some values from it in a bit.

Adding and configuring the Auth0 dependency

Having created your Auth0 Application, the next thing you will do is to add and configure the library that will let you secure your Android app with Auth0. To install it, open the build.gradle file and update it as follows:

// ./app/build.gradle

// ... apply plugin ...

android {

    // ... sdk version ...

    defaultConfig {

        // ... other properties ...

        manifestPlaceholders = [auth0Domain: "@string/com_auth0_domain", auth0Scheme: "to-do"]
    }
    // ... buildTypes ...
}

dependencies {
    // ... other dependencies ...
    implementation 'com.auth0.android:auth0:1.15.1'
}

Then, click on the Sync Now link that the IDE shows to download this dependency.

Note: The manifestPlaceholders you added above helps the Auth0 dependency register an intent-filter to capture the result of the authentication process. In other words, when Auth0 redirect your users back to your app (through the deep link you configured previously), the library will intercept this call and do its job.

Now, to configure this dependency with your Auth0 Application properties, you will open and update the strings.xml file. While you are manipulating this file, you can also add two labels that you will use soon:

<!-- ./app/src/main/res/values/strings.xml -->

<resources>
    <!-- ... other resources ... -->
    <string name="login">Log In</string>
    <string name="logout">Log Out</string>
    <string name="com_auth0_client_id"><YOUR_AUTH0_APP_ID></string>
    <string name="com_auth0_domain"><YOUR_AUTH0_DOMAIN></string>
</resources>

As you can see, this change is defining the login and logout labels and two Auth0 properties: com_auth0_client_id and com_auth0_domain. You will need to replace the values you are passing to these properties with the ones that the Auth0 Application exposes. More specifically, you will need to copy Client ID and Domain from your Auth0 Application to replace <YOUR_AUTH0_APP_ID> and <YOUR_AUTH0_DOMAIN> respectively.

Adding a menu to your app

Now that you configured the Auth0 library, the next thing you will do is to add a menu for your app. This will be a dynamic menu that will allow users to either log in or log out (depending, of course, on their current status).

To start defining this menu, create a new directory called menu inside ./app/src/main/res/. Then, create a file called menu.xml inside menu and add the following code to it:

<!-- ./app/src/main/res/menu/menu.xml -->

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/first_action"
        android:title="" />
</menu>

This menu is quite simple. It contains a single item just with an id and an empty title. You will define the title of the menu, along with its behavior, programmatically.

Now, as the menu will only cover two scenarios (login and logout), you will define two menu listeners: LoginListener and LogoutListener. When your users click on the menu, your app will call one of these listeners to either start the authentication process or end the user session.

To define the first listener, create a class called LoginListener inside the com.auth0.todo.util package and add the following code to it:

// ./app/src/main/java/com/auth0/todo/util/LoginListener.java

package com.auth0.todo.util;

import android.view.MenuItem;

import com.auth0.todo.identity.AuthenticationHandler;

public class LoginListener implements MenuItem.OnMenuItemClickListener {
    private AuthenticationHandler authenticationHandler;

    public LoginListener(AuthenticationHandler authenticationHandler) {
        this.authenticationHandler = authenticationHandler;
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        authenticationHandler.startAuthenticationProcess();
        return true;
    }
}

As you can see, this class implements an interface called MenuItem.OnMenuItemClickListener. It also defines a constructor that receives an instance of a class called AuthenticationHandler. You will create this class soon. Lastly, it defines that the onMenuItemClick will trigger a method called startAuthenticationProcess. As its name suggests, this method will start the authentication process.

After defining the login listener, you will create the LogoutListener inside the same package and add the following code to it:

// ./app/src/main/java/com/auth0/todo/util/LogoutListener.java

package com.auth0.todo.util;

import android.view.MenuItem;

import com.auth0.todo.identity.AuthenticationHandler;

public class LogoutListener implements MenuItem.OnMenuItemClickListener {
    private AuthenticationHandler authenticationHandler;

    public LogoutListener(AuthenticationHandler authenticationHandler) {
        this.authenticationHandler = authenticationHandler;
    }

    @Override
    public boolean onMenuItemClick(MenuItem item) {
        authenticationHandler.logout();
        return true;
    }
}

The behavior of this class is quite similar to the other one. The difference is that, instead of starting the authentication process, this class will log the user out.

Handling the authentication process

After defining some important pieces of your menu, the next thing you will do is to create the two central pieces of the identity management solution of your app. For starters, create a package called identity inside com.auth0.todo. Then, inside this package, create a class called AuthenticationHandler with the following code:

// ./app/src/main/java/com/auth0/todo/identity/AuthenticationHandler.java

package com.auth0.todo.identity;

import android.app.Dialog;
import android.content.Intent;
import android.widget.Toast;

import com.auth0.android.Auth0;
import com.auth0.android.authentication.AuthenticationAPIClient;
import com.auth0.android.authentication.AuthenticationException;
import com.auth0.android.authentication.storage.CredentialsManagerException;
import com.auth0.android.authentication.storage.SecureCredentialsManager;
import com.auth0.android.authentication.storage.SharedPreferencesStorage;
import com.auth0.android.callback.BaseCallback;
import com.auth0.android.provider.AuthCallback;
import com.auth0.android.provider.WebAuthProvider;
import com.auth0.android.result.Credentials;
import com.auth0.todo.MainActivity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;

public class AuthenticationHandler implements AuthCallback, BaseCallback<Credentials, CredentialsManagerException> {
    private Auth0 auth0;
    private AuthAwareActivity originalActivity;
    private Class<? extends AuthAwareActivity> nextActivity;
    private SecureCredentialsManager credentialsManager;
    private Credentials credentials;

    AuthenticationHandler(AuthAwareActivity originalActivity) {
        this.originalActivity = originalActivity;

        // configuring Auth0
        auth0 = new Auth0(originalActivity);
        auth0.setOIDCConformant(true);
        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
        credentialsManager = new SecureCredentialsManager(originalActivity, client, new SharedPreferencesStorage(originalActivity));
    }

    public void startAuthenticationProcess() {
        WebAuthProvider.init(auth0)
                .withScheme("to-do")
                .withScope("openid profile email offline_access")
                .withAudience("https://to-dos-api")
                .start(originalActivity, this);
    }

    public void logout() {
        credentialsManager.clearCredentials();
        originalActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                String message = "See you soon!";
                Toast.makeText(originalActivity, message, Toast.LENGTH_SHORT).show();
                originalActivity.refreshMenu();

                if (originalActivity instanceof MainActivity) return;
                originalActivity.startActivity(new Intent(originalActivity, MainActivity.class));
            }
        });
    }

    void refreshCredentials(Class<? extends AuthAwareActivity> nextActivity) {
        this.nextActivity = nextActivity;
        credentialsManager.getCredentials(this);
    }

    public String getAccessToken() {
        return credentials.getAccessToken();
    }

    public boolean hasValidCredentials() {
        boolean hasValidCredentials = this.credentialsManager.hasValidCredentials();
        if (hasValidCredentials && credentials == null) {
            refreshCredentials(null);
        }
        return hasValidCredentials;
    }

    @Override
    public void onFailure(@NonNull final Dialog dialog) {
        originalActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                dialog.show();
            }
        });
    }

    @Override
    public void onFailure(AuthenticationException exception) {
        new AlertDialog.Builder(originalActivity)
                .setTitle("Authentication Error")
                .setMessage(exception.getMessage())
                .show();
    }

    @Override
    public void onSuccess(@NonNull Credentials credentials) {
        credentialsManager.saveCredentials(credentials);
        this.credentials = credentials;
        if (nextActivity == null) {
            originalActivity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    originalActivity.refreshMenu();
                }
            });
            return;
        }
        originalActivity.startActivity(new Intent(originalActivity, nextActivity));
    }

    @Override
    public void onFailure(CredentialsManagerException error) {
        startAuthenticationProcess();
    }
}

Don’t get scared by the verbosity of this class, nor by the errors that the IDE shows regarding not knowing what AuthAwareActivity stands for (you will create this class soon). The AuthenticationHandler class is a bit big, but it is easy to demystify. Here you can check a list with the most important details that you must be aware of:

  • This class implements the AuthCallback interface to be able to decide what to do in case of failure or success. If you take a close look, you will see that the interface defines (and this class implements) three methods: two onFailure and one onSuccess. You will read about them in a bit.

  • This class implements the BaseCallback interface. This is needed because you want this class to call the SecureCredentialsManager that Auth0 provides to get the credentials (if any) of the current user. This process is done inside the refreshCredentials method that the AuthAwareActivity implements.

  • This class defines a method called startAuthenticationProcess that initiates the authentication process. That is, this method opens the Auth0 hosted login page in a browser so users can choose how they want to sign in or sign up.

  • This class defines a method called logout that, when requested, clears user credentials and that makes sure they are sent back to the main activity (it wouldn’t make sense letting unauthenticated users add new to-do items, right?).

  • This class defines a method called getAccessToken that returns an access token that the app can use to communicate with a backend API. You will use this method (and learn more about access tokens) on the second part of the tutorial while integrating the app with the backend.

  • This class defines a method called hasValidCredentials that verifies if the user has valid credentials or not. What is interesting here is that, if the user doesn’t have valid credentials, this method calls the refreshCredentials to get new ones.

As you can see, this class will do the heavy lifting for you when it comes to authentication and identity management.

Now, you will create another important class: AuthAwareActivity. Create this class inside the com.auth0.todo.identity package and add the following code to it:

// ./app/src/main/java/com/auth0/todo/identity/AuthAwareActivity.java

package com.auth0.todo.identity;

import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

import com.auth0.todo.R;
import com.auth0.todo.util.LoginListener;
import com.auth0.todo.util.LogoutListener;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public abstract class AuthAwareActivity extends AppCompatActivity {
    protected AuthenticationHandler authenticationHandler;
    protected Menu menu;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        this.authenticationHandler = new AuthenticationHandler(this);

    }

    public void refreshMenu() {
        MenuItem firstOption = menu.findItem(R.id.first_action);

        // reconfiguring button
        if (!authenticationHandler.hasValidCredentials()) {
            firstOption.setTitle(R.string.login);
            firstOption.setOnMenuItemClickListener(new LoginListener(authenticationHandler));
        } else {
            firstOption.setTitle(R.string.logout);
            firstOption.setOnMenuItemClickListener(new LogoutListener(authenticationHandler));
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);

        this.menu = menu;
        refreshMenu();

        return true;
    }
}

The main purpose of creating this class is to define a common behavior for the activities of your Android app. In this case, you are defining that you want all the subclasses of this class (you will refactor your two activities soon to extends this one) to create an instance of AuthenticationHandler. Also, you are defining that these activities will have a menu that shows either a login or a logout button depending on the result of a call to hasValidCredentials.

Wrapping up the integration with Auth0

To wrap things up, the last thing you will have to do is to refactor your two activities to extend the AuthAwareActivity class. First, you can open the ToDoFormActivity class and update it as follows:

// ./app/src/main/java/com/auth0/todo/ToDoFormActivity.java

// ... package definition and other import statements ...

import com.auth0.todo.identity.AuthAwareActivity;

public class ToDoFormActivity extends AuthAwareActivity {
    // ... leave the body of the class untouched ...
}

Then, open the MainActivity class and change it as follows:

// ./app/src/main/java/com/auth0/todo/MainActivity.java

// ... package definition and other import statements ...

import com.auth0.todo.identity.AuthAwareActivity;

public class MainActivity extends AuthAwareActivity {

    // ... leave the rest untouched ...

    public void openToDoForm(View view) {
        if (authenticationHandler.hasValidCredentials()) {
            startActivityForResult(new Intent(this, ToDoFormActivity.class), 1);
        }
    }

    // ... leave the rest untouched ...

}

Here, besides changing the base class of the MainActivity one, you are also changing the behavior of the floating action button to block unauthenticated users from accessing the new item form.

Note: As you are replacing AppCompatActivity with AuthAwareActivity on the two classes above, you can also remove the import statement that references the former.

After making these final changes, you are ready to take your secured Android application for a spin. So, click on the green play button to load the new version of your app, then click on the login menu to start the authentication process. If you sign in successfully, you will be able to use the new item form again.

Securing Android app with Auth0.

Recap and Next Steps

In the first part of this tutorial, you started by learning how to scaffold a simple hello-world Android application. After that, you enhanced this app to show a to-do list, and you added a form to enable users to update this list. In the end, you learned how to secure your application with Auth0.

This setup gives you a solid basis for the next part of this tutorial. There, you will learn how to integrate your app with a backend API to make things even more interesting. By doing that, your app will become more resilient (as the user data will stay live on the backend API), and you will learn cool things like issuing HTTP requests from your Android app.

Android Tutorial: Building and Securing Your First App (Part 2)

TL;DR: In the second part of this tutorial, you will learn how to integrate your Android application with a backend API. For starters, you will spin up a simple REST API (you will have different alternatives to achieve that), then you will adjust your app to replace the static to-do list with one provided by this API. In the end, you will leverage the app integration with Auth0 to make it use a private (also referred to as secured) endpoint to persist new to-do items. You can find the final code developed in this article in the following GitHub repository: Android Tutorial, Part 2: Building and Securing Your First App.

Previously, on Part 1

In the first part of this tutorial, you started by scaffolding a new Android project with the help of Android Studio, then you configured your app to use the Android Material component library to enhance the User Interface (UI). After that, you learned how to show a static list of to-do items in your app and how to create a form to enable users to insert new items. In the end, you learned how to handle user registration and authentication in your Android app with Auth0.

If you haven’t followed the instructions on the previous part, you can fork and clone this GitHub repository to get a copy of the app created there. However, before proceeding, make sure you follow the instructions on the Creating and configuring an Auth0 account and Adding and configuring the Auth0 dependency sections to configure the app with your Auth0 properties.

Spinning Up a Backend API

In this section, you will spin up a backend API locally to support your Android app. This API will provide to your app two endpoints:

  • a public one that returns a list of to-do items;
  • and a private one that allows authenticated users to add new items to this list.

With this API, you will have the opportunity to learn how to handle these two different types of endpoints (public and private) in your Android app.

To run this API, you have two alternatives. You can either clone a GitHub repository and use Node.js to run the API, or you can use Docker to fetch an image from Docker Hub and run it in a container. Feel free to choose the alternative that suits your better.

Using Node.js and NPM to run the backend API

If you prefer to run the API with Node.js, you will have to clone this GitHub repository, then you will have to use NPM to install its dependencies and run it in your machine. The following commands will help you achieve that:

# clone the repository
git clone https://github.com/auth0-blog/to-dos-api-express.git

# move into it
cd to-dos-api-express

# install the dependencies
npm install

# run it locally
npm start

Note: As this project depends on an in-memory MongoDB database to run, the npm install command might take a few seconds to download this database and complete the operation.

Using Docker to run the backend API

If you prefer using Docker instead of Node.js and NPM, you can use the following command to create a containerized instance of the backend API:

# use docker to run the backend API
docker run -p 3001:3001 -d --name to-dos-api auth0blog/to-dos-api-express

Note: To run the command above, you will need Docker installed in your machine. If you don’t have this tool yet and would prefer using this approach, check this resource.

This command will download this Docker image and use it to run a container called to-dos-api that listens on port 3001.

Testing the backend API

After following the instructions above to run the backend API, you can issue HTTP requests to the public endpoint to test if everything is working as expected. For example, if you are on Unix-like systems (e.g., Ubuntu, Fedora, or Mac OS), you can issue the following curl command to test the API:

# issuing a GET HTTP request to the public endpoint
curl localhost:3001

If you prefer using a graphical HTTP client (like Postman or Insomnia), you will have to configure it to issue a GET HTTP request to http://localhost:3001.

Issuing a GET HTTP request to the backend API.

Consuming Backend APIs in Android Apps

After spinning up the backend API, you are ready to start working on your Android app again. In this section, you will replace the static to-do list that your app loads with one provided by the API. To issue requests to your API, you will use a popular Android HTTP library called Volley.

So, back on Android Studio, you will open the build.gradle file and update it as follows:

// ./app/build.gradle

dependencies {
    // ... leave the rest untouched and add ...
    implementation 'com.android.volley:volley:1.1.1'
}

Then, you will click on the Sync Now link that the IDE shows to download Volley. After that, you will open the AndroidManifest.xml file and update it as follows:

<!-- ./app/src/main/AndroidManifest.xml -->

<manifest ...>

    <uses-permission android:name="android.permission.INTERNET" />

    <application
        ...
        android:usesCleartextTraffic="true">
        <!-- activities definition -->
    </application>

</manifest>

You are making two changes in this file:

  • First, you are adding a setting (uses-permission) that tells the Android device that your app needs INTERNET to function.
  • Second, you are adding a property (usesCleartextTraffic) to your app definition to tell the Android device that your app is allowed to use insecure HTTP connections. Without this configuration, you would need to use HTTPS in your backend API while testing the application.

Note: It is highly recommended that you do not publish a production-ready Android app with the usesCleartextTraffic="true" property. To release secure applications, you must ensure that your backend APIs can handle HTTPS connections and that your apps use them.

After making these adjustments to your app, the next thing you will do is to create an entity model to represent the to-do item returned by the backend API. To do so, create a new class called ToDoItem inside the com.auth0.todo package and add the following code to it:

// ./app/src/main/java/com/auth0/todo/ToDoItem.java

package com.auth0.todo;

public class ToDoItem {
    private final String id;
    private final String message;

    ToDoItem(String _id, String message) {
        this.id = _id;
        this.message = message;
    }

    public String getId() {
        return id;
    }

    public String getMessage() {
        return message;
    }
}

As you can see, the to-do items that the API return are quite simple. They have only two properties: id and message. The id property is the identifier of an item on the backend API, and the message property is the description of this item. You will use this entity to parse the results returned by the API and, on the next section, to serialize data while pushing new items to it.

With that in place, the next thing you will have to do is to open the ToDoListAdapter class and replace its code with this:

// ./app/src/main/java/com/auth0/todo/util/ToDoListAdapter.java

package com.auth0.todo.util;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.auth0.todo.R;
import com.auth0.todo.ToDoItem;

import java.util.ArrayList;
import java.util.List;

public class ToDoListAdapter extends BaseAdapter {
    private LayoutInflater inflater;
    private List<ToDoItem> toDoList = new ArrayList<>();

    public ToDoListAdapter(Context context) {
        inflater = LayoutInflater.from(context);
    }

    @Override
    public View getView(int position, View view, ViewGroup parent) {
        ToDoItem toDoItem = (ToDoItem) getItem(position);
        if (view == null) {
            view = inflater.inflate(R.layout.to_do_item, null);
        }

        TextView textView = view.findViewById(R.id.to_do_message);
        textView.setText(toDoItem.getMessage());

        return view;
    }

    @Override
    public Object getItem(int position) {
        return toDoList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getCount() {
        return toDoList.size();
    }

    public void setToDoList(List<ToDoItem> toDoList) {
        this.toDoList = toDoList;
        notifyDataSetChanged();
    }
}

The changes you are making here are related to replacing String with the new entity class (i.e., with ToDoItem). You need this because, instead of handling lists of strings, your app will now handle lists of instances of this entity class.

Lastly, open the MainActivity class and replace its code with this:

// ./app/src/main/java/com/auth0/todo/MainActivity.java

package com.auth0.todo;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;

import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonArrayRequest;
import com.android.volley.toolbox.Volley;
import com.auth0.todo.identity.AuthAwareActivity;
import com.auth0.todo.util.ToDoListAdapter;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

import androidx.appcompat.app.AlertDialog;

public class MainActivity extends AuthAwareActivity implements Response.Listener<JSONArray>, Response.ErrorListener {
    private ToDoListAdapter toDoListAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // create and configure the adapter
        this.toDoListAdapter = new ToDoListAdapter(this);
        ListView microPostsListView = findViewById(R.id.to_do_items);
        microPostsListView.setAdapter(toDoListAdapter);

        // issue the request
        String url = "http://10.0.2.2:3001";
        RequestQueue queue = Volley.newRequestQueue(this);
        JsonArrayRequest microPostsRequest = new JsonArrayRequest(url, this, this);
        queue.add(microPostsRequest);
    }

    @Override
    public void onResponse(JSONArray response) {
        try {
            List<ToDoItem> toDoItems = new ArrayList<>(response.length());
            for (int i = 0; i < response.length(); i++) {
                JSONObject item = response.getJSONObject(i);
                String id = item.getString("_id");
                String message = item.getString("message");

                toDoItems.add(new ToDoItem(id, message));
            }
            toDoListAdapter.setToDoList(toDoItems);
        } catch (JSONException error) {
            new AlertDialog.Builder(this)
                    .setTitle("Error")
                    .setMessage(error.toString())
                    .show();
        }
    }

    @Override
    public void onErrorResponse(VolleyError error) {
        toDoListAdapter.setToDoList(new ArrayList<ToDoItem>());
        new AlertDialog.Builder(this)
                .setTitle("Error")
                .setMessage(error.getMessage())
                .show();
    }

    public void openToDoForm(View view) {
        if (authenticationHandler.hasValidCredentials()) {
            startActivity(new Intent(this, ToDoFormActivity.class));
        }
    }
}

The list below summarizes the changes made here:

  • You are making this class implement two Volley interfaces: Response.Listener<JSONArray> and Response.ErrorListener. By implementing these interfaces, you make this class capable of handling successful and unsuccessful responses sent by the API.

  • You are making this class use Volley to issue an HTTP request to the http://10.0.2.2:3001 URL. Your app will issue this request when Android uses this class to create an activity (onCreate(Bundle savedInstanceState)). As described on the Set up Android Emulator networking resource, you can use the 10.0.2.2 IP address to make an app on an Android emulator communicate with the development machine (3001 is the port of the backend API in your machine). As such, if you are using a real device, you will have to replace this IP address.

  • You are implementing the onResponse method (which is defined by the Response.Listener interface) to transform the response sent by the API into a list of to-do items (List<ToDoItem>). Then, you are using this list to update the toDoListAdapter, which ends up updating the UI as well.

  • You are implementing the onErrorResponse method (which is defined by the Response.ErrorListener interface) to handle errors that occur while issuing requests to the API. In this case, you are clearing up the toDoListAdapter (which removes all items from the UI) and showing a quick error message (with the help of the AlertDialog class) describing the problem.

  • You are changing the way your app starts the ToDoFormActivity class. Now, instead of expecting a result back from this activity, you will let it work detached from the MainActivity. By doing that, when your users finish using the ToDoFormActivity, your app will recreate the MainActivity and will fetch a new (and up-to-date) to-do list.

After changing the MainActivity class, you are ready to see the new version of your app in action. So, click on the green play button and wait until the IDE finishes building and running the app. If everything works as expected, you will see your new app running on the Android device and showing a single to-do item: “Buy pizza!”.

Android app using volley to consume a public endpoint.

Consuming Private Endpoints in Android Apps

After learning how to make your Android app consume a public endpoint, the next thing you will do is to learn how to integrate it with a private/secure endpoint. As you are already using Auth0 to secure your app, you will use this service to secure your backend API as well. Then, you will use access tokens to secure the communication (the HTTP requests) between the two parties: the app and the API.

An access token is a credential that can be used by an application to access an API. They inform the API that the bearer of the token has been authorized to access the API. - Access Tokens

Registering the API on Auth0

While integrating the Android app with Auth0, you needed to create a representation of the app in your Dashboard. Now, you will need to do a similar process, but this time you will register the backend API.

To do so, open the APIs section on your Auth0 dashboard and click on the Create API button. Then, fill in the form presented by Auth0 as follows:

  • Name: Enter a friendly name to your API (e.g., “To-Do API”)
  • Identifier: Enter https://to-dos-api. Auth0 recommends using an URL-like identifier, but this doesn’t need to be a real URL.
  • Signing Algorithm: Leave this field as RS256.

After that, click on the Create button to finish the process.

Running a secure backend API

Now that you have your API registered in your Auth0 dashboard, you will need to run another version of the backend API you started earlier. This new version was configured to secure the endpoint that accepts new to-do items. So, if you are running the backend API with Node.js, stop the server (Ctrl + C), and issue the following commands to start the new version:

# checkout the auth0 branch
git checkout auth0

# install the new dependencies
npm install

# set your env variables
export AUTH0_DOMAIN=...
export AUTH0_API=...

# run the application
npm start

Note that you must use your Auth0 properties to set the environment variables defined above. More specifically, set AUTH0_DOMAIN to the domain you chose while creating your Auth0 account (or tenant) (e.g., blog-samples.auth0.com), and AUTH0_API to the identifier of the API you just created (i.e., https://to-do-api).

On the other hand, if you decided to use Docker to run your backend API, you will have to run the following commands:

# stop and remove the to-dos instance
docker rm -f to-dos

# set your env variables
AUTH0_DOMAIN=...
AUTH0_API=...

# run the auth0 version of the image
docker run \
  -p 3001:3001 \
  -e "AUTH0_DOMAIN="$AUTH0_DOMAIN \
  -e "AUTH0_API="$AUTH0_API \
  --name to-dos \
  -d auth0blog/to-dos-api-express:auth0

Just like on the Node.js alternative, use your Auth0 properties to set the environment variables defined above. That is, set AUTH0_DOMAIN to the domain you chose while creating your Auth0 account (or tenant) (e.g., blog-samples.auth0.com), and AUTH0_API with the identifier of the API you just created (i.e., https://to-do-api).

After running the new version of the backend API, you can test it to see if it is working. If you are on a Unix-like system, you can check the API with the following commands:

# issue a GET request
curl http://localhost:3001

# issue a POST request
curl -X POST -H 'Content-Type: application/json' -d '{
  "message": "Buy some milk."
}' http://localhost:3001/

If everything works as expected, the first command will get you a list of to-do items, just like before. However, the second request will not work. As the new version of the API is restricting access to the POST endpoint, you will need access tokens to be able to insert items again. Luckily, you already configured your Android app to get these tokens when your users log in.

Note: If you would like to learn how to build the backend API you are using, check this resource: Node.js and Express Tutorial: Building and Securing RESTful APIs.

Adding new to-do items to the secure API

With the new backend API up and running, you can head back to your Android project and adjust it to send new to-do items to the API. There, open the ToDoFormActivity class and replace its code with this:

// ./app/src/main/java/com/auth0/todo/ToDoFormActivity.java

package com.auth0.todo;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;

import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.JsonObjectRequest;
import com.android.volley.toolbox.Volley;
import com.auth0.todo.identity.AuthAwareActivity;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import androidx.appcompat.app.AlertDialog;

public class ToDoFormActivity extends AuthAwareActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_to_do_form);
    }

    public void addToDoItem(View view) {
        EditText editText = findViewById(R.id.editText);
        String message = editText.getText().toString();

        try {
            final Context context = this;
            JSONObject newPost = new JSONObject();
            newPost.put("message", message);

            String url = "http://10.0.2.2:3001";
            JsonObjectRequest postRequest = new JsonObjectRequest(Request.Method.POST, url, newPost,
                    new Response.Listener<JSONObject>() {
                        @Override
                        public void onResponse(JSONObject response) {
                            startActivity(new Intent(context, MainActivity.class));
                        }
                    },
                    new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            new AlertDialog.Builder(context)
                                    .setTitle("Error")
                                    .setMessage(error.getMessage())
                                    .show();
                        }
                    }
            ) {
                @Override
                public Map<String, String> getHeaders() {
                    Map<String, String> headers = new HashMap<>();
                    headers.put("Authorization", "Bearer " + authenticationHandler.getAccessToken());
                    return headers;
                }
            };

            // Add the request to the RequestQueue.
            RequestQueue queue = Volley.newRequestQueue(context);
            queue.add(postRequest);
        } catch (JSONException e) {
            System.out.println(e.getMessage());
        }
    }
}

The new version of this file updates the implementation of the addToDoItem method to use Volley to issue a request to the backend API. As you can see, this method creates an instance of the JSONObject class and adds an attribute called message to it (this attribute gets the value that the user inputs on the text field). Then, this method uses JsonObjectRequest to issue a POST HTTP request to your backend API with the JSONObject instance.

Note: Just like the one that the MainActivity issues, this request is aiming at the http://10.0.2.2:3001 URL (which is the IP address of the host machine that is running the Android emulator). So, if you are not using an emulator (i.e., if you are using a real device), make sure you replace this URL accordingly.

If everything works as expected, Volley will call the onResponse implementation you defined, which will make your app send the user back to the main activity. If an error occurs, Volley will call the onErrorResponse implementation, which will show a new AlertDialog with the error message.

What is important to notice in that the JsonObjectRequest you are creating is overriding (@Override) the getHeaders method to add the access token (authenticationHandler.getAccessToken()) in the Authorization header. As explained in Auth0’s documentation:

Access tokens should be used as a Bearer credential and transmitted in an HTTP Authorization header to the API. - Access Tokens

With that in place, you can rerun your Android app. After using your app to log in, by clicking on the + floating button you will be able to use the ToDoFormActivity to add new items to the backend API.

Conclusion

Bingo! You just learned how to build and secure Android apps with ease. In this series, you started from scratch, creating a brand new Android project. Then you went all the way to make an app that allows users to log in and that communicates with a secure backend API to persist data. With this setup, you are ready to move on and start building amazing and production-ready apps.

Thanks for reading ❤
If you liked this post, share it with all of your programming buddies!
Follow me on Facebook | Twitter

Learn More

The Complete React Native and Redux Course
iOS 12 & Swift - The Complete iOS App Development Bootcamp
Xamarin Forms: Build Native Cross-platform Apps with C#
Android Studio for beginners
Create a File Storage Mobile App with NativeScript 5
Creating an iOS app with user presence using Node.js and Swift
Cross-platform iOS & Android development with Xamarin

Originally published by Bruno Krebs at https://auth0.com

Suggest