developers

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

Learn how to integrate your Android application with a backend API.

Apr 10, 201916 min read

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.

Learn how to build and secure Android apps and how to integrate them with backend APIs!

Tweet This

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

I just built my first Android app and made it consume a secure backend API!

Tweet This

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.