Top of the line Samsung and Apple smartphone models now immune to the deadly USB killer that fries motherboard in seconds

How to build a secure Grails 4 Application using Spring Security Core

How to build a secure Grails 4 Application using Spring Security Core

In this Grails 4 tutorial, we will show you how to build a secure Grails 4 application using Spring Security Core Plugin. We will add the login and register function to the Grails 4 application.

In this Grails 4 tutorial, we will show you how to build a secure Grails 4 application using Spring Security Core Plugin. We will add the login and register function to the Grails 4 application. The purpose of using the Spring Security plugin has simplified the integration of Spring Security Java (we have written this tutorial). The usage of this Grails 4 Spring Security plugin similar to Grails 2 or 3, but there's a lot of updates on the Spring Security code and its dependencies to match the compatibilities.

Table of Contents:

The flow of this tutorial is very simple. We have a secure Product list that only accessible to the authorized user with ROLE_USER and Product CRUD for the user with ROLE_ADMIN. Any access to this Product resource will be redirected to the Login Page as default (if no authorized user). In the login page, there will be a link to the registration page that will register a new user.

The following tools, frameworks, libraries, and dependencies are required for this tutorial:

  1. JDK 8
  2. Grails 4
  3. Grails Spring Security Core Plugin
  4. Terminal or Command Line
  5. Text Editor or IDE

Before starting the main steps, make sure you have downloaded and installed the latest Grails 4. In Mac, we are using the SDKMan. For that, type this command in the Terminal to install SDKMan.

curl -s https://get.sdkman.io | bash

Follow all instructions that showed up during installation. Next, open the new Terminal window or tab then type this command.

source "$HOME/.sdkman/bin/sdkman-init.sh"

Now, you can install Grails 4 using SDKMan.

sdk install grails 4.0.1

Set that new Grails 4 as default. To check the Grails version, type this command.

grails -version
| Grails Version: 4.0.1
| JVM Version: 1.8.0_92
Create Grails 4 Application

Same as previous Grails version, to create a new Grails application, simply type this command.

grails create-app com.djamware.gadgethouse

That command will create a new Grails 4 application with the name "gadgethouse" with the package name "com.djamware". Next, go to the newly created project folder then enter the Grails 4 interactive console.

cd ./gadgethouse
grails

In the Grails interactive console, type this command to run this Grails application for the first time.

grails> run-app

Here's the new Grails 4 look like.

Install Grails Spring Security Core Plugin

Now, we will install and configure Grails Spring Security Core Plugin. For the database, we keep H2 in-memory database (You can change to other relational database configuration). To install the Grails Spring Security Core Plugin, open and edit build.gradle then add this dependency in dependencies array.

compile "org.grails.plugins:spring-security-core:4.0.0.RC2"

Next, stop the running Grails application using this command in the Grails interactive console.

stop-app

Compile the Grails application, to install the Spring Security Core plugin.

compile
Create User, Role, and Product Domain Class

We will use the Grails s2-quickstart command to create User and Role domain class for authentication. Type this command in Grails interactive console.

s2-quickstart com.djamware User Role

That command will create User and Role domain class with the package name "com.djamware". Next, open and edit grails-app/domain/com/djamware/Role.groovy to add default field after the bracket closing when this domain calls.

String toString() {
  authority
}

Next, create a domain class using regular Grails command for Product.

create-domain-class com.djamware.Product

Next, we need to create an additional field in the user domain class. For that, open and edit grails-app/domain/com/djamware/User.groovy then add a fullName field after the password field.

String fullname

Also, add a constraint for that field.

static constraints = {
    password nullable: false, blank: false, password: true
    username nullable: false, blank: false, unique: true
    fullname nullable: false, blank: false
}

Next, open and edit grails-app/domain/com/djamware/Product.groovy then replace that domain class with these Groovy codes.

package com.djamware

class Product {

    String prodCode
    String prodName
    String prodModel
    String prodDesc
    String prodImageUrl
    String prodPrice

    static constraints = {
        prodCode nullable: false, blank: false
        prodName nullable: false, blank: false
        prodModel nullable: false, blank: false
        prodDesc nullable: false, blank: false
        prodImageUrl nullable: true
        prodPrice nullable: false, blank: false
    }

    String toString() {
        prodName
    }
}
Create CustomUserDetailsService

Because we have added a field in the previous User domain class, we need to create a custom UserDetails. Create a new Groovy file src/main/groovy/com/djamware/CustomUserDetails.groovy then add these lines of Groovy codes that add full name field to the Grails UserDetails.

package com.djamware

import grails.plugin.springsecurity.userdetails.GrailsUser
import org.springframework.security.core.GrantedAuthority

class CustomUserDetails extends GrailsUser {

   final String fullname

   CustomUserDetails(String username, String password, boolean enabled,
                 boolean accountNonExpired, boolean credentialsNonExpired,
                 boolean accountNonLocked,
                 Collection<GrantedAuthority> authorities,
                 long id, String fullname) {
      super(username, password, enabled, accountNonExpired,
            credentialsNonExpired, accountNonLocked, authorities, id)

      this.fullname = fullname
   }
}

Next, type this command in the Grails interactive console to create a new Grails service.

grails> create-service com.djamware.CustomUserDetails

Open that file then replace all Groovy codes with these codes.

package com.djamware

import grails.plugin.springsecurity.SpringSecurityUtils
import grails.plugin.springsecurity.userdetails.GrailsUserDetailsService
import grails.plugin.springsecurity.userdetails.NoStackUsernameNotFoundException
import grails.gorm.transactions.Transactional
import org.springframework.security.core.authority.SimpleGrantedAuthority
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UsernameNotFoundException

class CustomUserDetailsService implements GrailsUserDetailsService {

   /**
    * Some Spring Security classes (e.g. RoleHierarchyVoter) expect at least
    * one role, so we give a user with no granted roles this one which gets
    * past that restriction but doesn't grant anything.
    */
   static final List NO_ROLES = [new SimpleGrantedAuthority(SpringSecurityUtils.NO_ROLE)]

   UserDetails loadUserByUsername(String username, boolean loadRoles)
         throws UsernameNotFoundException {
      return loadUserByUsername(username)
   }

   @Transactional(readOnly=true, noRollbackFor=[IllegalArgumentException, UsernameNotFoundException])
   UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

      User user = User.findByUsername(username)
      if (!user) throw new NoStackUsernameNotFoundException()

      def roles = user.authorities

      // or if you are using role groups:
      // def roles = user.authorities.collect { it.authorities }.flatten().unique()

      def authorities = roles.collect {
         new SimpleGrantedAuthority(it.authority)
      }

      return new CustomUserDetails(user.username, user.password, user.enabled,
            !user.accountExpired, !user.passwordExpired,
            !user.accountLocked, authorities ?: NO_ROLES, user.id,
            user.fullname)
   }
}

Next, register that new CustomUserDetailsService in the grails-app/conf/spring/resources.groovy.

import com.djamware.UserPasswordEncoderListener
import com.djamware.CustomUserDetailsService
// Place your Spring DSL code here
beans = {
    userPasswordEncoderListener(UserPasswordEncoderListener)
    userDetailsService(CustomUserDetailsService)
}
Override Login Auth View

We will customize the login page to make UI better and add a link to the Register page. For that, create a login folder under views then create an auth.gsp file in that folder. Open and edit grails-app/views/login/auth.gsp then add these lines of GSP HTML tags.

<html>
<head>
    <meta name="layout" content="${gspLayout ?: 'main'}"/>
    <title><g:message code='springSecurity.login.title'/></title>
</head>

<body>
    <div class="row">
      <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
        <div class="card card-signin my-5">
          <div class="card-body">
            <h5 class="card-title text-center">Please Login</h5>
            <g:if test='${flash.message}'>
                <div class="alert alert-danger" role="alert">${flash.message}</div>
            </g:if>
            <form class="form-signin" action="${postUrl ?: '/login/authenticate'}" method="POST" id="loginForm" autocomplete="off">
              <div class="form-group">
                  <label for="username">Username</label>
                <input type="text" class="form-control" name="${usernameParameter ?: 'username'}" id="username" autocapitalize="none"/>
              </div>

              <div class="form-group">
                  <label for="password">Password</label>
                <input type="password" class="form-control" name="${passwordParameter ?: 'password'}" id="password"/>
                <i id="passwordToggler" title="toggle password display" onclick="passwordDisplayToggle()">&#128065;</i>
              </div>

              <div class="form-group form-check">
                  <label class="form-check-label">
                      <input type="checkbox" class="form-check-input" name="${rememberMeParameter ?: 'remember-me'}" id="remember_me" <g:if test='${hasCookie}'>checked="checked"</g:if>/> Remember me
                </label>
              </div>
              <button id="submit" class="btn btn-lg btn-primary btn-block text-uppercase" type="submit">Sign in</button>
              <hr class="my-4">
              <p>Don't have an account? <g:link controller="register">Register</g:link></p>
            </form>
          </div>
        </div>
      </div>
    </div>
    <script type="text/javascript">
        document.addEventListener("DOMContentLoaded", function(event) {
            document.forms['loginForm'].elements['username'].focus();
        });
        function passwordDisplayToggle() {
            var toggleEl = document.getElementById("passwordToggler");
            var eyeIcon = '\u{1F441}';
            var xIcon = '\u{2715}';
            var passEl = document.getElementById("password");
            if (passEl.type === "password") {
                toggleEl.innerHTML = xIcon;
                passEl.type = "text";
            } else {
                toggleEl.innerHTML = eyeIcon;
                passEl.type = "password";
            }
        }
    </script>
</body>
</html>

Next, we will make this login page as default or homepage when the application opens in the browser. For that, open and edit grails-app/controllers/UrlMappings.groovy then replace this line.

"/"(view: "index")

With this line.

"/"(controller:'login', action:'auth')
Add User Info and Logout to the Navbar

Now, we have to implement POST logout to the Navbar. This logout button active when the user logged in successfully along with user info. For that, modify grails-app/views/layout/main.gsp then replace all GSP HTML tags with these.

<!doctype html>
<html lang="en" class="no-js">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>
        <g:layoutTitle default="Grails"/>
    </title>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <asset:link rel="icon" href="favicon.ico" type="image/x-ico"/>

    <asset:stylesheet src="application.css"/>

    <g:layoutHead/>
</head>

<body>

<nav class="navbar navbar-expand-lg navbar-dark navbar-static-top" role="navigation">
    <a class="navbar-brand" href="/#"><asset:image src="grails.svg" alt="Grails Logo"/></a>
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarContent" aria-controls="navbarContent" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
    </button>

    <div class="collapse navbar-collapse" aria-expanded="false" style="height: 0.8px;" id="navbarContent">
        <ul class="nav navbar-nav ml-auto">
            <g:pageProperty name="page.nav"/>
            <sec:ifLoggedIn>
              <li class="nav-item dropdown">
                  <a class="nav-link dropdown-toggle" href="#" id="navbardrop" data-toggle="dropdown">
                    <sec:loggedInUserInfo field='fullname'/>
                  </a>
                  <div class="dropdown-menu navbar-dark">
                    <g:form controller="logout">
                      <g:submitButton class="dropdown-item navbar-dark color-light" name="Submit" value="Logout" style="color:gray" />
                    </g:form>
                  </div>
              </li>
            </sec:ifLoggedIn>
        </ul>
    </div>

</nav>

<div class="container">
    <g:layoutBody/>
</div>

<div class="footer row" role="contentinfo">
    <div class="col">
        <a href="http://guides.grails.org" target="_blank">
            <asset:image src="advancedgrails.svg" alt="Grails Guides" class="float-left"/>
        </a>
        <strong class="centered"><a href="http://guides.grails.org" target="_blank">Grails Guides</a></strong>
        <p>Building your first Grails app? Looking to add security, or create a Single-Page-App? Check out the <a href="http://guides.grails.org" target="_blank">Grails Guides</a> for step-by-step tutorials.</p>

    </div>
    <div class="col">
        <a href="http://docs.grails.org" target="_blank">
            <asset:image src="documentation.svg" alt="Grails Documentation" class="float-left"/>
        </a>
        <strong class="centered"><a href="http://docs.grails.org" target="_blank">Documentation</a></strong>
        <p>Ready to dig in? You can find in-depth documentation for all the features of Grails in the <a href="http://docs.grails.org" target="_blank">User Guide</a>.</p>

    </div>

    <div class="col">
        <a href="https://grails-slack.cfapps.io" target="_blank">
            <asset:image src="slack.svg" alt="Grails Slack" class="float-left"/>
        </a>
        <strong class="centered"><a href="https://grails-slack.cfapps.io" target="_blank">Join the Community</a></strong>
        <p>Get feedback and share your experience with other Grails developers in the community <a href="https://grails-slack.cfapps.io" target="_blank">Slack channel</a>.</p>
    </div>
</div>

<div id="spinner" class="spinner" style="display:none;">
    <g:message code="spinner.alt" default="Loading&hellip;"/>
</div>

<asset:javascript src="application.js"/>

</body>
</html>

As you see, there are built in Grails Spring Security TagLib sec:ifLoggedIn and <sec:loggedInUserInfo field='fullname'/>. The <sec:loggedInUserInfo field='fullname'/> only working when you implementing CustomUserDetailsService.

Create Register Controller and View

Back to the Grails interactive console to create a controller for the Register page.

grails> create-controller com.djamware.Register

Open and edit that Groovy file then replace all Groovy codes with these codes that have 2 methods of Register landing page and register action.

package com.djamware

import grails.validation.ValidationException
import grails.gorm.transactions.Transactional
import grails.plugin.springsecurity.annotation.Secured
import com.djamware.User
import com.djamware.Role
import com.djamware.UserRole

@Transactional
@Secured('permitAll')
class RegisterController {

    static allowedMethods = [register: "POST"]

    def index() { }

    def register() {
        if(!params.password.equals(params.repassword)) {
            flash.message = "Password and Re-Password not match"
            redirect action: "index"
            return
        } else {
            try {
                def user = User.findByUsername(params.username)?: new User(username: params.username, password: params.password, fullname: params.fullname).save()
                def role = Role.get(params.role.id)
                if(user && role) {
                    UserRole.create user, role

                    UserRole.withSession {
                      it.flush()
                      it.clear()
                    }

                    flash.message = "You have registered successfully. Please login."
                    redirect controller: "login", action: "auth"
                } else {
                    flash.message = "Register failed"
                    render view: "index"
                    return
                }
            } catch (ValidationException e) {
                flash.message = "Register Failed"
                redirect action: "index"
                return
            }
        }
    }
}

Next, add the index.gsp inside grails-app/views/register/. Open and edit that file then add these lines of GSP HTML tags.

<html>
<head>
    <meta name="layout" content="${gspLayout ?: 'main'}"/>
    <title>Register</title>
</head>

<body>
    <div class="row">
    <div class="col-sm-9 col-md-7 col-lg-5 mx-auto">
      <div class="card card-signin my-5">
        <div class="card-body">
          <h5 class="card-title text-center">Register Here</h5>
                    <g:if test='${flash.message}'>
                        <div class="alert alert-danger" role="alert">${flash.message}</div>
                    </g:if>
              <form class="form-signin" action="register" method="POST" id="loginForm" autocomplete="off">
                      <div class="form-group">
                          <label for="role">Role</label>
              <g:select class="form-control" name="role.id"
                    from="${com.djamware.Role.list()}"
                    optionKey="id" />
                </div>

            <div class="form-group">
                    <label for="username">Username</label>
              <input type="text" placeholder="Your username" class="form-control" name="username" id="username" autocapitalize="none"/>
            </div>

            <div class="form-group">
                          <label for="password">Password</label>
              <input type="password" placeholder="Your password" class="form-control" name="password" id="password"/>
            </div>

            <div class="form-group">
                          <label for="password">Re-Enter Password</label>
              <input type="password" placeholder="Re-enter password" class="form-control" name="repassword" id="repassword"/>
            </div>

                      <div class="form-group">
                          <label for="username">Full Name</label>
              <input type="text" placeholder="Your full name" class="form-control" name="fullname" id="fullname" autocapitalize="none"/>
            </div>

            <button id="submit" class="btn btn-lg btn-primary btn-block text-uppercase" type="submit">Register</button>
            <hr class="my-4">
            <p>Already have an account? <g:link controller="login" action="auth">Login</g:link></p>
          </form>
        </div>
      </div>
    </div>
  </div>
    <script type="text/javascript">
        document.addEventListener("DOMContentLoaded", function(event) {
            document.forms['loginForm'].elements['username'].focus();
        });
    </script>
</body>
</html>
Create the Secure Product CRUD Scaffolding

Now, we will make Product CRUD scaffolding and make them secured and accessible to ROLE_USER and ROLE_ADMIN. To create CRUD scaffolding, simply run this command inside Grails interactive console.

grails>generate-all com.djamware.Product

That command will generate controller, service, and view for a Product domain class. Next, open and edit grails-app/controllers/ProductController.groovy then add the Secure annotation like these.

package com.djamware

import grails.validation.ValidationException
import static org.springframework.http.HttpStatus.*
import grails.plugin.springsecurity.annotation.Secured

class ProductController {

    ProductService productService

    static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]

    @Secured(['ROLE_ADMIN', 'ROLE_USER'])
    def index(Integer max) {
        params.max = Math.min(max ?: 10, 100)
        respond productService.list(params), model:[productCount: productService.count()]
    }

    @Secured(['ROLE_ADMIN', 'ROLE_USER'])
    def show(Long id) {
        respond productService.get(id)
    }

    @Secured('ROLE_ADMIN')
    def create() {
        respond new Product(params)
    }

    @Secured('ROLE_ADMIN')
    def save(Product product) {
        if (product == null) {
            notFound()
            return
        }

        try {
            productService.save(product)
        } catch (ValidationException e) {
            respond product.errors, view:'create'
            return
        }

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.created.message', args: [message(code: 'product.label', default: 'Product'), product.id])
                redirect product
            }
            '*' { respond product, [status: CREATED] }
        }
    }

    @Secured('ROLE_ADMIN')
    def edit(Long id) {
        respond productService.get(id)
    }

    @Secured('ROLE_ADMIN')
    def update(Product product) {
        if (product == null) {
            notFound()
            return
        }

        try {
            productService.save(product)
        } catch (ValidationException e) {
            respond product.errors, view:'edit'
            return
        }

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.updated.message', args: [message(code: 'product.label', default: 'Product'), product.id])
                redirect product
            }
            '*'{ respond product, [status: OK] }
        }
    }

    @Secured('ROLE_ADMIN')
    def delete(Long id) {
        if (id == null) {
            notFound()
            return
        }

        productService.delete(id)

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.deleted.message', args: [message(code: 'product.label', default: 'Product'), id])
                redirect action:"index", method:"GET"
            }
            '*'{ render status: NO_CONTENT }
        }
    }

    protected void notFound() {
        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.not.found.message', args: [message(code: 'product.label', default: 'Product'), params.id])
                redirect action: "index", method: "GET"
            }
            '*'{ render status: NOT_FOUND }
        }
    }
}

Next, we will make Product controller as a default landing page after succeful login. For that, open and edit grails-app/conf/application.groovy then add this configuration.

grails.plugin.springsecurity.successHandler.defaultTargetUrl = '/product'
Run and Test Grails 4 Spring Security Core

Now, we will run and test the Grails 4 Spring Security Core application. In the Grails interactive console run this command.

grails>run-app

Open the browser then go to http://localhost:8080 and you will see this page.




That it's, the Grails 4 Tutorial: Spring Security Core Login Example. You can find the full working source code in our GitHub.

Thanks!

Building and Securing Your First App - Android Tutorial

Building and Securing Your First App - Android Tutorial

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.

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.

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.

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:

  • 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)”

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.

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:

  • 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)”

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](https://github.com/material-components/material-components-android/blob/master/docs/getting-started.md#1-depend-on-our-library "androidx") package and the [com.google.android.material](https://github.com/material-components/material-components-android/blob/master/docs/getting-started.md#1-depend-on-our-library "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:





    <application
        ...
        android:theme="@style/Theme.MaterialComponents.Bridge">
        
    




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:




<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" />




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:




<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" />
    



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.

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
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 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).

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
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).

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:




<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" />



This layout resource is using a [ConstraintLayout](https://developer.android.com/training/constraint-layout "ConstraintLayout") to put two elements side by side:

  • 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)”

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:




    To-Do List
    Describe your to-do item
    Insert



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:





    
        
        ...
        

        
        
    




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





    

    <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" />



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:



<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">
    



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:

  • 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)”

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
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.

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

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: “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)”

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:

  • 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)”

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
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.

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
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:




    
    Log In
    Log Out
    
    



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 and 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:




    <item
        android:id="@+id/first_action"
        android:title="" />



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 {
    private Auth0 auth0;
    private AuthAwareActivity originalActivity;
    private Class 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 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:

  • 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)”

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.

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
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.

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:

  • 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)”

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


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

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


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
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](http://localhost:3001 "http://localhost:3001").

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:





    

    <application
        ...
        android:usesCleartextTraffic="true">
        
    




You are making two changes in this file:

  • 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)”

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
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 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 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, 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 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());
        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:

  • 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)”

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!”.

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 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

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: “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)”

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](https://to-do-api "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](https://to-do-api "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.

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

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() {
                        @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 getHeaders() {
                    Map 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.

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
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:

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
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!

My Android app not supporting Android version 9

I have made an android app which uses webView. Everything was fine until I tried my app on Android P. On Android "P" the app is directly showing the error page that the app can't use Internet connection even though it is ON.

I have made an android app which uses webView. Everything was fine until I tried my app on Android P. On Android "P" the app is directly showing the error page that the app can't use Internet connection even though it is ON.

Android Manifest File:

    <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.xxx.xxxxx.xxxxx">
&lt;!-- android:roundIcon="@mipmap/ic_launcher_round" --&gt;

&lt;uses-permission android:name="android.permission.INTERNET" /&gt;
&lt;uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY"/&gt;
&lt;uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /&gt;
&lt;uses-permission android:name="android.permission.CAMERA" /&gt;

&lt;application
    android:allowBackup="true"
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:hardwareAccelerated="true"
    android:supportsRtl="true"
    android:theme="@style/AppTheme"&gt;
    &lt;activity android:name="com.xxxxx.xxxxx.xxxxxx.MainActivity"&gt;
        &lt;intent-filter&gt;
            &lt;action android:name="android.intent.action.MAIN" /&gt;

            &lt;category android:name="android.intent.category.LAUNCHER" /&gt;
        &lt;/intent-filter&gt;
    &lt;/activity&gt;
&lt;/application&gt;

</manifest>

Gradle File:

    apply plugin: 'com.android.application'

android {
compileSdkVersion 28
defaultConfig {
applicationId "com.xxx.xxx.xxx"
minSdkVersion 19
targetSdkVersion 28
versionCode 3
versionName "3.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:design:28.0.0'
}

On Getting error in Android P, directly this section is being accessed:

public void onReceivedError(WebView view, int errorCode,
String description, String failingUrl) {
// You can redirect to your own page instead getting the default error page

            super.onReceivedError(view, errorCode, description, failingUrl);
            String path = Uri.parse("file:///android_asset/error.html").toString();
            webView.loadUrl("about:blank");
            view.loadUrl(path);
        }