---
title: "Get Started with Jetpack Compose Authentication, Part 1: Jetpack Compose Basics"
description: "Learn how to build a basic app using Android’s Jetpack Compose UI toolkit."
authors:
  - name: "Joey deVilla"
    url: "https://auth0.com/blog/authors/joey-devilla/"
date: "Feb 24, 2023"
category: "Developers,Tutorial,Android"
tags: ["mobile", "authentication", "native"]
url: "https://auth0.com/blog/android-authentication-jetpack-compose-part-1/"
---

# Get Started with Jetpack Compose Authentication, Part 1: Jetpack Compose Basics

With nearly 3 billion users, [almost 70% of the mobile OS market share](https://www.statista.com/statistics/272698/global-market-share-held-by-mobile-operating-systems-since-2009/), and [the majority share of all user-facing operating systems worldwide](https://gs.statcounter.com/os-market-share), Android is the number one operating system in use today. As an Android developer, you have access to the world’s largest customer base, and sooner or later, you’ll write an app that requires the user to log in and out. One of the goals of this tutorial is to show you how to use Auth0 to add authentication to an Android app. You’ll also become familiar with the Auth0 dashboard and learn how to use it to register applications and manage users.

Platforms evolve, and Android is no exception. However, when a platform the size of Android fundamentally changes how you do things, developers who embrace the change early gain a significant advantage. This change is happening now with [Jetpack Compose](https://developer.android.com/jetpack/compose). This tutorial’s secondary goal is to give you an “early adopter” advantage by building a simple login/logout user interface with Jetpack Compose.

> Look for the 🛠 emoji if you’d like to skim through the content while focusing on the build and execution steps.


## Jetpack Compose

<a href="https://developer.android.com/jetpack/compose"><img src="https://images.ctfassets.net/23aumh6u8s0i/4JQe27JmEip0X21uRGa0sr/ae23bfa547ed18a019c6fd92615f1eff/jetpack_compose_icon.png" align="right" alt="Jetpack Compose icon."></a>

Released in July 2021, **Jetpack Compose** (often shortened to **Compose**) is a UI toolkit that thoroughly updates the process of building Android apps. Instead of XML, you use declarative Kotlin code to specify how the UI should look and behave under different states. You don’t have to worry about how the UI moves between those states — Compose takes care of that for you. You'll find Compose familiar if you’re acquainted with declarative web frameworks like React, Angular, or Vue.

The Jetpack Compose approach is a significant departure from Android’s original XML UI toolkit, modeled after old desktop UI frameworks and dates back to 2008. You use a mechanism such as [`findViewById()`](https://wajahatkarim.com/2020/04/evolution-of-finding-views/) or [view binding](https://developer.android.com/topic/libraries/view-binding) to connect UI elements to code. This imperative approach is simple but requires you to define how the program moves between states and how the UI should look and behave in those states.

Jetpack Compose is built with Kotlin, takes advantage of the features and design philosophy of Kotlin language, and is designed for use in applications written in Kotlin. With Compose, you no longer have to context-switch to XML when designing your app’s UI; you now do everything in Kotlin.


## What You’ll Build

You’ll use Auth0 and Jetpack Compose to build a single-screen Android app that allows users to log in and out. I’ve purposely kept it as simple as possible to keep the focus on authentication.

When you launch the completed app, you’ll see a greeting and a _Log In_ button:

![The app’s “Welcome” screen.](https://images.ctfassets.net/23aumh6u8s0i/79V4LEtvxB3v6SmVpFTJiv/6b3e9a97e35320bb7b23921786b624c5/welcome_screen.png)

Pressing the _Log In_ button takes the user to the [Auth0 Universal Login screen](https://auth0.com/docs/login/universal-login). It appears in a web browser view embedded in your app. Here’s what it looks like in an emulator...

![The default Auth0 Universal Login web page, as viewed in an emulator.](https://images.ctfassets.net/23aumh6u8s0i/1wO8fe8gEACROirEUKh0r9/6fea0a9aca8635b929abc273b26b2574/universal_login_-_emulator.png)

...and here’s what it looks like on a device:

![The default Auth0 Universal Login web page, as viewed on a device.](https://images.ctfassets.net/23aumh6u8s0i/3J5tC0kNuWHQDiMYJiTV5n/cdb03cf0ab6c5745fa1f95dde83a5366/universal_login_-_device.png)

When you use Auth0 to add login/logout capability to your apps, you delegate authentication to an Auth0-hosted login page. You've seen this in Google web applications such as Gmail and YouTube. These services redirect you to log in using [accounts.google.com](https://accounts.google.com/). After logging in, Google returns you to the web application as a logged-in user.

> If you’re worried that using Auth0’s Universal Login means that your app’s login screen will be stuck with the default Auth0 “look and feel,” I have good news for you: [you can customize it to match your app or organization’s brand identity.](https://auth0.com/docs/universal-login/new-experience/universal-login-page-templates)

The Universal Login page saves you from having to code an authentication system. It gives your applications a self-contained login box with several features to provide a great user experience.

If the user enters an invalid email address/password combination, it displays an error message and gives them another chance to log in:

![Universal Login displaying the “wrong email or password” message.](https://images.ctfassets.net/23aumh6u8s0i/1XQjDhWtwitjqRe7kESxGo/81a14507b732cac2158e4e414dc9679b/universal_login_-_invalid_email.png)

There are two ways to exit the Universal Login screen. There’s the “unhappy path,” where the user presses the _Cancel_ button at the upper left corner of the screen, which dismisses the Universal Login screen and returns them to the opening screen.

The “happy path” out of the Universal Login appears when the user enters a valid email address/password combination. When this happens, Auth0 authenticates the user, the embedded web view and Universal Login will disappear, and control will return to the app, which will now look like this:

![The app in its “logged in” state, with a title that reads “You’re logged in!”.](https://images.ctfassets.net/23aumh6u8s0i/5gNAhdJeDuRARnH8wTIVc5/aceaf6a3b65365ee9957d1cc47b5ac84/logged_in_screen.png)

Here’s what changed after the user logged in:

* The title text at the top of the screen now says, “You’re logged in!”
* The name, email address, and photo associated with the user’s account appear onscreen.
* A _Log Out_ button appears below the user’s photo.

As you might expect, the user logs out by pressing the _Log Out_ button, which returns them to a slightly different version of the initial screen:

![The app after the user logs out, with a title that reads “You’re logged out.” and a “Log In” button.](https://images.ctfassets.net/23aumh6u8s0i/2aiT1PgALmT39dBRE0ioky/73e5374e0faddfa4a62b56f0a408aa51/logged_out_screen.png)


## What You’ll Need

You’ll need the following to build the app:

### 1. An Auth0 account

The app uses Auth0 to authenticate users, meaning you need an Auth0 account. You can <a href="https://a0.to/blog_signup" data-amp-replace="CLIENT_ID" data-amp-addparams="anonId=CLIENT_ID(cid-scope-cookie-fallback-name)">sign up for a free account</a>, which lets you add login/logout to 10 applications, with support for 7,000 users and unlimited logins — plenty for your prototyping, development, and testing needs.

### 2. An Android development setup

To develop applications for Android, make sure you have the following, in the order given below:

* Any computer running Linux, macOS, or Windows from 2013 or later with at least 8 GB RAM. When it comes to RAM, more is generally better.
* [**Java SE Developer Kit (JDK), version 11 or later.**](https://www.oracle.com/java/technologies/javase-jdk16-downloads.html) You can find out which version is on your computer by opening a command-line interface and entering `java --version`.
* [**Android Studio,**](https://developer.android.com/studio) version 2021.3.1 Patch 1 (also known as “Dolphin”) or later. Jetpack Compose is a recent development, so you should use the most recent stable version of Android Studio.
* **At least one Android SDK (Software Development Kit) platform.** You can confirm that you have one (and install one if you don’t) in Android Studio. Open _Tools_ → _SDK Manager_. You’ll see a list of Android SDK platforms. Select the current SDK (**Android 13.0 (Tiramisu)** at the time of writing), click the _Apply_ button, and click the _OK_ button in the confirmation dialog that appears. Wait for the SDK platform to install and click the _Finish_ button when installation is complete.
* **An Android device, real or virtual:**
    * **Using a physical device:** Connect the device to your computer with a USB cable. Make sure that your device has Developer Options and USB debugging enabled.
    * **Using a virtual device:** Using Android Studio, you can build a virtual device (emulator) that runs on your computer. Here’s my recipe for a virtual device that simulates a current-model inexpensive Android phone:
        1. Open _Tools_ → _AVD Manager_ (AVD is short for “Android Virtual Device”). The _Your Virtual Devices_ window will appear. Click the _Create Virtual Device..._ button.
        2. The _Select Hardware_ window will appear. In the _Phone_ category, select _Pixel 3a_ and click the _Next_ button.
        3. The _System Image_ window will appear, and you’ll see a list of Android versions. Select _S_ (API 31, also known as Android 12.0). If you see a _Download_ link beside R, click it, wait for the OS to download, then click the _Finish_ button. Then click the _Next_ button.
        4. The _Android Virtual Device (AVD)_ window will appear. The _AVD Name_ field should contain _Pixel 3a API 31_, and the two rows below it should have the titles _Pixel 3a_ (a reasonable “representative” phone, released three years ago at the time of writing) and _S_. In the _Startup orientation_ section, select _Portrait_. Click the _Finish_ button.
        5. You will return to the _Your Virtual Devices_ window. The list will now contain _Pixel 3a API 31_, and that device will be available when you run the app.

### 3. A little familiarity with Android/Kotlin development. 

If you’re new to Android development or the Kotlin programming language, you might find [*Android Basics in Kotlin*](https://developer.android.com/courses/android-basics-kotlin/course) to be a good introduction.


## Create a New Jetpack Compose Project

🛠 Launch Android Studio and create a new project. You’ll see this window:

![The first “New Project” window, where the user selects a project template.](https://images.ctfassets.net/23aumh6u8s0i/5qN3ebOxnvuyeH4GGF8wJZ/4b10e1bb41c0490b5a9fcca5c2bc92c8/new_project_window.png)

🛠 Do the following in this window:

* Select _Phone and Tablet_ from the menu on the left side.
* Select _Empty Compose Activity_ from the main list. 
* Click _Next_.

You’ll go to this window:

![The second “New Project” window, where the user enters the name for their project.](https://images.ctfassets.net/23aumh6u8s0i/4jJsyCrnA6Ja8MlgCFfDk1/e0257ab3c99ecb8fa0d742c848a972ab/new_project_window_2.png)

🛠 Do the following in this window:

* Enter `JetpackComposeLogin` into the _Name_ field. The _Package Name_ field should automatically fill itself with `com.auth0.jetpackcomposelogin`. **Make a note of this package name** — you’ll need it later when you register the app with Auth0.
* Select a suitable location to save the project. In the screenshot above, you can see that I simply saved it to the default `AndroidStudioProjects` directory.
* Set the _Minimum SDK_ to _API 24: Android 7.0 (Nougat)_ or later. This version of Android dates back to August 2016 and is above the minimum SDK level Jetpack Compose requires (API 21, also known as Android 5.0 or “Lollipop”). The project should run on most Android devices still in active use.
* Click _Finish_. 

At the end of these steps, Android Studio will generate the project and present you with the app’s main activity file, `MainActivity.kt`.


## Introducing Composable Functions

As with XML-based Android projects (which I’ll call “the old way”), the default `MainActivity.kt` file contains a `MainActivity` class that defines the default main activity’s appearance and behavior. The difference is in *how* it defines that appearance and behavior.


### The `MainActivity` class

Let’s examine the `MainActivity` class. I’ve added some blank lines and comments to make the code a little easier to follow:

```kotlin
// 📄 MainActivity.kt

// (The package and import statements are here)

class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Define which composable function defines the activity’s 
        // overall appearance and behavior
        setContent {

                  // Define the activity’s colors
            JetpackComposeLoginTheme {
                
                // Define additional properties for the activity’s appearance
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    
                      // Define the activity’s layout and behavior
                    Greeting("Android")
                
                } // Surface()
                
            } // JetpackComposeLoginTheme()
            
        } // setContent()
    
    } // onCreate()    
   
} // MainActivity

// (The rest of the file is here)
```

In XML-based Android projects, `MainActivity`’s `onCreate()` method calls `setContentView()` to “inflate” `activity_main.xml`. The XML file defines the activity’s layout, while the code in `MainActivity` defines the activity’s behavior. 

In a Jetpack Compose project, `onCreate()` calls a similarly-named method, `setContent()`, to specify a **composable function** (or **composable** for short) that defines both the activity’s layout and behavior. In this case, that composable function is `Greeting()`, whose appearance is modified by the `JetpackComposeLoginTheme()` and `Surface()` functions containing it.

Before we continue, I’ll need to answer a question you’re probably asking right now.


### What are composable functions?

Composable functions (or composables) are the building blocks of Jetpack Compose. While they’re not the same as views from “the old way” of building Android apps, they fill the same roles and behave similarly. They act as user interface elements or containers for user interface elements, just as views do in traditional Android projects. Think of them as functions that take in data and return UIs.

In mathematics, when you take the result of a function _f()_ and feed it to another function _g()_, you are _composing_ the two functions into a new function _h()_, whose value is _g(f(x))_. In Jetpack Compose, we do something similar — you can feed the UI component that one composable generates into another composable to create a more complex UI component. You do this by nesting composables inside other composables.

Let’s look at the first composable in `MainActivity.kt`. Android Studio creates it as part of the _Empty Compose Activity_ app template. Its name is `Greeting`, and it’s located just after the `MainActivity` class:

```
@Composable
fun Greeting(name: String) {
    Text(text = "Hello $name!")
}
```

The first thing that you should notice is the `@Composable` annotation. This tells the Kotlin compiler that `Greeting` is a composable: function that receives data and generates a UI (or part of one) in response.

Annotating a function with `@Composable` adds a lot of behind-the-scenes behavior to it. Because of this, composables can only be used inside functions marked with the `@Composable` annotation. If you remove the `@Composable` annotation from `Greeting`, Android Studio will present you with the error message “@Composable invocations can only happen from the context of a @Composable function.”

You may have noticed these other things about `Greeting`:

1. **It’s a Kotlin function.** Instead of XML, which can only define the structure of a user interface element or container, you’re looking at  [Turing-complete](https://www.cs.odu.edu/~zeil/cs390/latest/Public/turing-complete/index.html) Kotlin code. This means that you can also use branching, looping, and all the other powers that code grants to define the behavior of user interface elements and containers. Later in this exercise, you’ll use these powers to show and hide UI elements based on whether the user is logged in or out.
3. **It has parameters.** As a function, it has parameters (or, if you prefer, it takes arguments). This makes composables flexible and allows us to pass state to them. If you’re familiar with React, think of composable parameters as “props.”
4. **It’s a Unit function.** In other words, it has no return value. Instead, it causes a user interface element or container to be drawn. Functional programming language purists would call this a side effect; we Jetpack Composers prefer to say that composables **emit** UI elements.
5. **Its name is a CapitalizedNoun.** The convention is that composable function names are nouns capitalized in [PascalCase](https://www.theserverside.com/definition/Pascal-case). It helps distinguish composables from ordinary functions and methods, where the convention is to make their names verbs that use [camelCase capitalization](https://en.wikipedia.org/wiki/Camel_case).

The second function in `MainActivity.kt` appears immediately after `Greeting`. It’s called `DefaultPreview`:

```
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    LoginWithJetpackTheme {
        Greeting("Android")
    }
}
```

`DefaultPreview` has two annotations: `@Composable` and `@Preview`. The `@Preview` annotation tells the Kotlin compiler that this composable creates a UI element or container that _doesn’t_ appear in the running app but as a preview in Android Studio. Preview composables let you preview the UI without requiring you to compile and run the app.

`DefaultPreview` renders the `Greeting` composable in Android Studio’s preview pane. You can open this pane by selecting _Split_ near the upper right corner of the code pane:

![Android Studio window, with instructions pointing to the “Split” button.](https://images.ctfassets.net/23aumh6u8s0i/6CGNd3BbcZXzdS7Hbw5Qhx/6aeb33b2927cb95e3deeb9a59967453d/ui_code_and_preview.png)

Since preview composables are visible only within Android Studio, they’re optional. We’ll ignore them in this tutorial for the sake of brevity.


## Build the App’s User Interface

Let’s take our first step and build the app’s UI...


### Define the app’s string resources

🛠 Open the project’s `strings.xml` file (in Android Studio’s Project pane, you’ll find it in the `/app/res/values` folder; in the filesystem, it’s in `/app/src/main/res/values/`). Replace its contents with this XML:

```xml
<!-- 📄 strings.xml -->

<resources>
    <string name="app_name">Jetpack Compose Login</string>
    <string name="initial_title">Welcome to the app!</string>
    <string name="logged_in_title">You’re logged in!</string>
    <string name="logged_out_title">You’re logged out.</string>
    <string name="log_in_button">Log In</string>
    <string name="log_out_button">Log Out</string>
    <string name="name_label">Name</string>
    <string name="email_label">Email</string>
    <string name="user_icon_url">https://images.ctfassets.net/23aumh6u8s0i/5hHkO5DxWMPxDjc2QZLXYf/403128092dedc8eb3395314b1d3545ad/icon-user.png</string>
</resources>
```

You’ll use these string resources in the app’s user interface. As a general rule, you shouldn’t use string literals in the user interface; instead, you should use string resources.

> String resources are an underappreciated Android feature. They allow us to avoid the problems arising from hard-coded strings, prevent duplication of often-used string values, and simplify internationalization (you can create a string resource file for each language your app supports).


### Add a new view and title to the main activity

🛠 Update the `import` statements to the beginning of `MainActivity.kt` to the following:

```kotlin
// 📄 MainActivity.kt

/// 👇🏽👇🏽👇🏽 Updated code
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
import com.auth0.jetpackcomposelogin.ui.theme.JetpackComposeLoginTheme
/// 👆🏽👆🏽👆🏽
```

🛠 Update the `MainActivity` class by replacing the call to the `Greeting` composable with a call to a new composable called `MainView`:

```kotlin
// 📄 MainActivity.kt

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            JetpackComposeLoginTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colors.background
                ) {
                    /// 👇🏽👇🏽👇🏽 Updated code
                    MainView()
                    /// 👆🏽👆🏽👆🏽
                }
            }
        }
    }
}
```

🛠 Replace the `Greeting` and `DefaultPreview` composables with two new ones: `MainView` and `Title`:

```kotlin
// 📄 MainActivity.kt

/// 👇🏽👇🏽👇🏽 Updated code
// Remove Greeting and DefaultPreview
/// 👆🏽👆🏽👆🏽

/// 👇🏽👇🏽👇🏽 New code
@Composable
fun MainView() {
    Title(
        text = stringResource(R.string.initial_title)
    )
}

@Composable
fun Title(
    text: String,
)
{
    Text(
        text = text,
        style = TextStyle(
            fontFamily = FontFamily.Default,
            fontWeight = FontWeight.Bold,
            fontSize = 30.sp,
        )
    )
}
/// 👆🏽👆🏽👆🏽
```

The `MainView` composable emits the app’s main view, a container for the main view’s UI elements. It contains a call to the `Title` composable, passing it the ID value for the “Welcome to the app!” string resource.

Let’s take a closer look at the `Title` composable:

```kotlin
// 📄 MainActivity.kt

@Composable
fun Title(  // 1
    text: String,
)
{
    Text(  // 2
        text = text,
        style = TextStyle(
            fontFamily = FontFamily.Default,
            fontWeight = FontWeight.Bold,
            fontSize = 30.sp,  // 3
        )
    )
}
```

These notes correspond to the numbered comments in the code above:

1. We’re defining a composable named `Title`, which takes one argument: `text`, a string whose contents will be shown in a large title font.
2. It emits [`Text`](https://foso.github.io/Jetpack-Compose-Playground/foundation/text/), a built-in composable that displays text. We provide it with two arguments:
    * `text`: A string containing the text that `Title` will display.
    * `style`: A [`TextStyle`](https://www.jetpackcompose.net/textstyle-in-jetpack-compose) object that changes the appearance of what `Text` emits. The title will use the default font, in boldface, sized at 30 scale-independent pixels.
3. Note how the font size is specified: `30.sp`. The `fontSize` property expects a `TextUnit` value, and `sp` is an extension property provided by `TextUnit` as syntactic sugar. `30.sp` is much nicer to read than `TextUnit(30, TEXTUNIT_UNIT_SP)`.

> For simplicity’s sake, I’m “hard-coding” the dimensions of UI components in this tutorial.

🛠 Run the app. It should look like this:

![Android emulator showing the running app.](https://images.ctfassets.net/23aumh6u8s0i/BRV1AAqOmFpS0CV1bihfr/c2132fb54aa5ca1fb78576d27aaf8e5f/welcome_to_the_app.png)


### Add the _Log In_ button

Let’s create a composable that will emit the _Log In_ / _Log Out_ button.

🛠 Add the following import statements to the ones near the start of `MainActivity.kt`:

```kotlin
// 📄 MainActivity.kt

import androidx.compose.ui.Alignment
import androidx.compose.material.Button
import androidx.compose.ui.unit.dp
```

🛠 Add the following code after the `Title` composable:

```kotlin
// 📄 MainActivity.kt

@Composable
fun LogButton(  // 1
    text: String,
    onClick: () -> Unit,
) {
    Column(  // 2
        modifier = Modifier
            .fillMaxWidth()
            .padding(20.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
    ) {
        Button(  // 3
            onClick = { onClick() },
            modifier = Modifier
                .width(200.dp)
                .height(50.dp),
            ) {
            Text(  // 4
                text = text,
                fontSize = 20.sp,
            )
        }
    }
}
```

These notes correspond to the numbered comments in the code above:

1. We’re defining a composable named `LogButton`, which takes two arguments:
    * `text`: A string containing the text that the button will display.
    * `onClick`: A function that executes when the user presses the button.
2. [`Column`](https://foso.github.io/Jetpack-Compose-Playground/layout/column/) is a built-in layout composable, which acts as a container for other composables, laying them out vertically in the order in which they appear from the top to bottom. We’re providing it with three arguments:
    * `modifier`: An instance of the `Modifier` class whose methods decorate or add behavior to a composable. We’re calling two methods — `fillMaxWidth()`, which makes the `Column` as wide as its parent allows, and `padding()` to specify 20 device-independent pixels’ worth of padding.
    * We’re setting its `horizontalAlignment` so that it’s centered horizontally.
    * A lambda function that specifies the composables inside the `Column`.
3. [`Button`](https://foso.github.io/Jetpack-Compose-Playground/material/button/) is a built-in UI element composable that emits a standard button. We’re providing it with three arguments:
    * `onClick`: The function that should execute when the user presses the button.
    * `modifier`: We’re using this to specify the button’s dimensions — 200 device-independent pixels wide and 50 device-independent pixels high.
    * A lambda function that specifies the composables inside the `Button`.
4. This `Text` composable defines the text within the button. It takes two arguments:
    * `text`:  A string containing the text to be displayed.
    * `fontSize`: Sets the font size to 20 scale-independent pixels.

🛠 Add the button to the app’s main view by updating the `MainView` composable as shown below:

```kotlin
// 📄 MainActivity.kt

@Composable
fun MainView() {
    Title(
        text = stringResource(R.string.initial_title)
    )
    /// 👇🏽👇🏽👇🏽 New code
    LogButton(
        text = stringResource(R.string.log_in_button),
        onClick = { },
    )
    /// 👆🏽👆🏽👆🏽
}
```

🛠 Run the app. You’ll see this:

![Android emulator showing the running app.](https://images.ctfassets.net/23aumh6u8s0i/7k899Anih7DErM9pYzlS2D/c713a47bf34afc0a730e8fe61d773994/overlapping_title_and_button.png)

As you can see, `LogButton` overlaps `Title`. This happens when you place one UI element composable after another without placing them inside a layout composable. We can fix this by putting them inside a `Column`.

🛠 Update `MainView` as shown below, then rerun the app:

```kotlin
// 📄 MainActivity.kt

@Composable
fun MainView() {
    /// 👇🏽👇🏽👇🏽 New code
    Column(
        modifier = Modifier.padding(20.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
    ) {
    /// 👆🏽👆🏽👆🏽
        Title(
            text = stringResource(R.string.initial_title)
        )
        LogButton(
            text = stringResource(R.string.log_in_button),
            onClick = { },
        )
    /// 👇🏽👇🏽👇🏽 New code
    }
    /// 👆🏽👆🏽👆🏽
}
```

The column you just added has 20 device-independent pixels of padding, its contents are centered horizontally and vertically within `MainView`, and it lays out `Title` and `LogButton` in a vertical line. The result looks much better:

![Android emulator showing the running app.](https://images.ctfassets.net/23aumh6u8s0i/5lfg60Htf4DmGB7MLEdwe6/4ee7fd4937ced3b4e7ac93762e204d47/improved_title_and_button.png)


### Add UI elements to display the user’s name and email address

The app needs UI elements to display the user’s name and email address. Let’s create a composable that takes two string arguments — a label and a corresponding value — and shows them side-by-side, with the label in bold text.

🛠 Add the following code to `MainView.kt` after `Title` and before `LogButton`:

```kotlin
// 📄 MainActivity.kt

@Composable
fun UserInfoRow(
    label: String,
    value: String,
) {
    Row {  // 1
        Text(
            text = label,
            style = TextStyle(
                fontFamily = FontFamily.Default,
                fontWeight = FontWeight.Bold,
                fontSize = 20.sp,
            )
        )
        Spacer( // 2
            modifier = Modifier.width(10.dp),
        )
        Text(
            text = value,
            style = TextStyle(
                fontFamily = FontFamily.Default,
                fontSize = 20.sp,
            )
        )
    }
}
```

This code introduces two new built-in composables, each highlighted by a numbered comment:

1. [`Row`](https://foso.github.io/Jetpack-Compose-Playground/layout/row/): The horizontal counterpart to `Column`. It’s a layout composable that acts as a container for other composables, laying them out horizontally in the order in which they appear from left to right. We’re using it to put the label and value side by side.
2. [`Spacer`](https://foso.github.io/Jetpack-Compose-Playground/foundation/layout/spacer/): A composable that provides space between other composables. We’re using it to make a little horizontal space between the label and the value.

🛠 Update `MainView` to incorporate two instances of `UserInfoRow`: one for the user’s name and one for the user’s email address:

```kotlin
// 📄 MainActivity.kt

@Composable
fun MainView() {
    Column(
        modifier = Modifier.padding(20.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
    ) {
        Title(
            text = stringResource(R.string.initial_title)
        )
        /// 👇🏽👇🏽👇🏽 New code
        UserInfoRow(
            label = stringResource(R.string.name_label),
            value = "Name goes here",
        )
        UserInfoRow(
            label = stringResource(R.string.email_label),
            value = "Email goes here",
        )
        /// 👆🏽👆🏽👆🏽
        LogButton(
            text = stringResource(R.string.log_in_button),
            onClick = { },
        )
    }
}
```

The hard-coded `value` parameters in the two `UserInfoRow` instances are temporary. You’ll replace them with values provided by Auth0 later in this exercise.

🛠 Run the app. You should see this:

![Android emulator showing the running app.](https://images.ctfassets.net/23aumh6u8s0i/3HOj6ov5C4pndWRlJe1HU8/95e549e25e324d6adf9418c1ddb16784/added_name_and_email.png)


### Add a UI element to display the user’s picture

There’s one more UI element to add: one that can take a URL for a picture and display it onscreen. To do this, we’ll use the [Coil](https://coil-kt.github.io/coil/) image loading library, which is “Kotlin-first,” fast, and easy to use. Let’s add Coil to the project.

🛠 Open the app’s `build.gradle` file (in Android Studio’s Project pane, it’s the `build.gradle (Module: JetpackComposeLogin.app)` file under _Gradle Scripts_; in the filesystem, it’s `/app/build.gradle`). Update the `dependencies` section to include the latest version of Coil, as shown below:

```kotlin
// 📄 /app/build.gradle

dependencies {

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation "androidx.compose.ui:ui:$compose_version"
    implementation "androidx.compose.material:material:$compose_version"
    implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
    implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
    implementation 'androidx.activity:activity-compose:1.3.1'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
    debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
    debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"

    /// 👇🏽👇🏽👇🏽 New code
    // Coil image loading library
    // (see https://github.com/coil-kt/coil)
    implementation 'io.coil-kt:coil-compose:+'
    /// 👆🏽👆🏽👆🏽

}
```

> The first set of dependencies listed above was automatically generated by Android Studio and has Android Studio’s choice of dependency versions. I prefer to leave those alone. However, we added the Coil dependency manually. With dependencies that I add myself, I prefer to request the latest version unless there’s a security-related reason to use a specific version.

🛠 This change to the app’s `build.gradle` file will require re-syncing the project with the updated Gradle file. Click the _Sync Now_ link near the top right corner of the code pane to do so:

![Android Studio window, with an arrow instructing the user to click the “Sync Now” button.](https://images.ctfassets.net/23aumh6u8s0i/3wGZdTdzmPqyf8trMkCHle/5ee400ac44e8d9e8b359e1c924208b81/sync_now_1.png)

Android Studio will display the message “Gradle project sync in progress...” for a few moments, and then the sync will complete.

The next step is to give the app permission to access the internet. The coil needs it to download images, and Auth0 will need it to contact its servers. You specify this permission in the app’s manifest file.

🛠 Open the app’s manifest file, `AndroidManifest.xml` (in Android Studio’s Project pane, it’s in the `/app/manifests` folder; in the filesystem, it’s in `/app/src/main/`. Add a `<uses-permission>` XML element for internet access as shown below:

```xml
<!-- 📄 app/manifests/AndroidManifest.xml -->

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.auth0.androidlogin">

    <!-- New code 👇🏽 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- New code 👆🏽 -->

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AndroidLogin"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
```

🛠 Add these `import` statements to the ones near the start of `MainActivity.kt`. The first one imports the `Image` composable, and the second imports Coil’s `rememberAsyncImagePainter()` function, which downloads and stores an image from a URL:

```kotlin
// 📄 MainActivity.kt

import androidx.compose.foundation.Image
import coil.compose.rememberAsyncImagePainter
```

🛠 With the prerequisites out of the way, it’s time to write the composable to display the user’s picture, which is stored online at a specified URL. Add the following code after `UserInfoRow` and before `LogButton`:

```kotlin
// 📄 MainActivity.kt

@Composable
fun UserPicture(  // 1
    url: String,
    description: String,
) {
    Column(  // 2
        modifier = Modifier
            .padding(10.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
    ) {
        Image(  // 3
            painter = rememberAsyncImagePainter(url),
            contentDescription = description,
            modifier = Modifier
                .fillMaxSize(0.5f),
        )
    }
}
```

These notes correspond to the numbered comments in the code above:

1. We’re defining a composable named `UserPicture`, which takes two arguments that will be passed to the `Image` composable contained within this composable.
    * `url`: A string containing the URL for the image to be downloaded and displayed.
    * `description `: A description of the image.
2. This composable uses a `Column` to provide padding and horizontal/vertical center alignment.
3. [`Image`](https://foso.github.io/Jetpack-Compose-Playground/foundation/image/) is a built-in UI element composable that displays an image. We’re providing it with three arguments:
    * `painter`: The image to be displayed by the composable. This should be an instance of a subclass of [`Painter`](https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/painter/Painter), an abstract class representing something that can be drawn, such as a bitmapped graphic, vector graphic, color, or gradient. In this case, we want to download an image from an URL and display it, so we set this value to `rememberAsyncImagePainter(url)`, a Coil method that downloads an image from a URL specified by `UserPicture`’s `url` parameter and returns an `AsyncImagePainter` instance that the composable can display.
    * `contentDescription`: A description of the image that accessibility devices or tools will use. Think of this as Android’s version of “alt text” in HTML.
    * `modifier`: We’re using this to limit the image to half of its maximum possible size on the screen.

🛠 Update `MainView` to incorporate `UserPicture`, placing it below the `UserInfoRow` for the user’s email address and above the _Log In_ button:

```kotlin
// 📄 MainActivity.kt

@Composable
fun MainView() {
    Column(
        modifier = Modifier.padding(20.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
    ) {
        Title(
            text = stringResource(R.string.initial_title)
        )
        UserInfoRow(
            label = stringResource(R.string.name_label),
            value = "Name goes here",
        )
        UserInfoRow(
            label = stringResource(R.string.email_label),
            value = "Email goes here",
        )
        /// 👇🏽👇🏽👇🏽 New code
        UserPicture(
            url = "https://images.ctfassets.net/23aumh6u8s0i/5hHkO5DxWMPxDjc2QZLXYf/403128092dedc8eb3395314b1d3545ad/icon-user.png",
            description = "Description goes here",
        )
        /// 👆🏽👆🏽👆🏽
        LogButton(
            text = stringResource(R.string.log_in_button),
            onClick = { },
        )
    }
}
```

We’re breaking Android’s “don’t use string literals in the user interface, use string resources” rule in setting the `url` property in the call to `UserPicture`. Once again, this temporary measure lets us display a placeholder graphic where the user’s picture will eventually go.

🛠 Run the app. You should see this:

![Android emulator showing the running app.](https://images.ctfassets.net/23aumh6u8s0i/1y2TGfGYnit9ilrcRaujit/6fd60df076852502a40795f60851d33b/added_picture.png)

With `UserPicture`, you’ve added all the UI elements to the app. It’s time to make the app respond to the user, which requires adding behavior and state.


## Add Behavior and State to the App

In this part of the exercise, we’ll add behavior to the app by making it respond to the user’s button presses. When launched, the app should show this screen:

![The starter app’s initial screen.](https://images.ctfassets.net/23aumh6u8s0i/7qcOWtHV0oc7TsMMmW9hAe/950c653c8ee01fb6e4b1e4accdd7bbd1/starter_app_1.png)

When the user presses the _Log In_ button, the app should show the “logged in” screen. The user should see “Welcome to the app!” as the title, with placeholder values for the user’s name, email address, and picture. The button should say _Log Out_:

![The starter app’s “logged in” screen.](https://images.ctfassets.net/23aumh6u8s0i/5K43qiQNl3p8FRqgw4vqlx/fdcc2c975b882cfa82aa2a54710cd964/starter_app_2.png)

When the user presses the _Log Out_ button, they return to the initial page. The title changes to “You’re logged out,” and the button’s text changes to “Log In.”

![The starter app’s “logged out” screen.](https://images.ctfassets.net/23aumh6u8s0i/7zEy9wmk0DA5M1JfaecTPY/622a48f14893d4aaacac157a26f278e0/starter_app_3.png)


### Preserve and observe (or: Keep track of the app’s state)

To add behavior to the app, it needs to be aware of its state. We’ll need two variables to store the state:

* `userIsAuthenticated`: a boolean value that is `true` if the user is logged in. This will determine which screen the user sees — the “logged out” screen or the “logged in” one. Its initial value is `false`.
* `appJustLaunched`: a boolean that is `true` if the app has just been launched and the user has not logged in since launch. This will determine the title the user sees on the “logged out” screen: “Welcome to the app!” or “You’re logged out.” This variable’s initial value is `true`.

In a Jetpack Compose-based application, the UI reacts to changes in the state, which means it reacts to changes in the variables. When `userIsAuthenticated`’s value changes to `true`, the app should present the “logged in” screen, complete with the user’s name, email address, and picture, along with the _Log Out_ button. When `userIsAuthenticated`’s value changes to `false`, the app should display the “logged out” screen with only the greeting title and the _Log In_ button.

This “reactive UI” approach presents two requirements for state variables:

*  In a Jetpack Compose activity, the UI is defined by composable functions located  _outside_ the activity class. Any state variables inside those functions go out of scope as soon as the functions finish executing. There needs to be a way for a composable to remember the values of state variables when it’s called again.
* There also needs to be a way to specify which variables are part of the state so that Jetpack Compose can observe them for changes and call the necessary composables to update the UI (a process called **recomposing** or **recomposition**) when their values change.

Jetpack Compose provides two mechanisms that allow us to meet these challenges.


#### Preserving state with `remember`

The `remember` API allows composables to remember values between calls. It has this syntax...

```kotlin
remember { thing }
```

...where `thing` is an object — mutable or immutable — whose value should be stored in the composable between calls to it.


#### Observing state with `mutableStateOf()`

The `mutableStateOf()` function creates an instance of `MutableState<T>`, an object containing a value of type `T` that Jetpack Compose watches for changes. Here’s an example:

```kotlin
var userIsAuthenticated = mutableStateOf(false)
```

The code above declares a variable, `userIsAuthenticated`, as one that Jetpack Compose should watch for changes. It also sets the variable’s initial value to `false`, which causes Kotlin to infer that `userIsAuthenticated`’s type is `MutableState<Boolean>`. You access this boolean value via `userIsAuthenticated`’s `value` property. For example, this code changes `userIsAuthenticated`’s value to `false`:

```kotlin
userIsAuthenticated.value = false
```

We can use Kotlin’s `by` keyword and [delegated properties](https://kotlinlang.org/docs/delegated-properties.html#observable-properties) when declaring a state variable to make it easier to get and set its value. If we declare `userIsAuthenticated` this way...

```kotlin
var userIsAuthenticated by mutableStateOf(false)
```

...then we can change the value contained within `userIsAuthenticated` using the simpler syntax:

```kotlin
userIsAuthenticated = false
```

#### Declaring preserved and observed state variables

A state variable needs to be both _preserved_ and _observed_. We can combine both `remember` and `mutableStateOf()` to create such variables.

Here’s how we’d declare `userIsAuthenticated` and `appJustLaunched` as state variables:

```kotlin
var userIsAuthenticated by remember { mutableStateOf(false) }
var appJustLaunched by remember { mutableStateOf(true) }
```

Let’s put this to use.


### Add state to `MainView`

🛠 Add these `import` statements to the ones near the start of `MainActivity.kt`. These will add support for the delegated properties of `mutableStateOf()`, `remember`, and `mutableStateOf()`:

```kotlin
// 📄 MainActivity.kt

import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
```

🛠 Add the `userIsAuthenticated` and `appJustLaunched` state variables to `MainView` by declaring them at the start of the composable:

```kotlin
// 📄 MainActivity.kt

@Composable
fun MainView() {
    /// 👇🏽👇🏽👇🏽 New code
    var userIsAuthenticated by remember { mutableStateOf(false) }
    var appJustLaunched by remember { mutableStateOf(true) }
    /// 👆🏽👆🏽👆🏽

    // (The rest of the code goes here)
```

🛠 Update the rest of `MainView` so that `userIsAuthenticated` and `appJustLaunched` determine what the app shows onscreen. `MainView` should look like this:

```kotlin
// 📄 MainActivity.kt

@Composable
fun MainView() {
    var userIsAuthenticated by remember { mutableStateOf(false) }
    var appJustLaunched by remember { mutableStateOf(true) }

    Column(
        modifier = Modifier.padding(20.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center,
    ) {
        /// 👇🏽👇🏽👇🏽 1. Updated code
        // Title
        // -----
        val title = if (userIsAuthenticated) {
            stringResource(R.string.logged_in_title)
        } else {
            if (appJustLaunched) {
                stringResource(R.string.initial_title)
            } else {
                stringResource(R.string.logged_out_title)
            }
        }
        Title(
            text = title
        )
        /// 👆🏽👆🏽👆🏽
        /// 👇🏽👇🏽👇🏽 2. New code
        // User info
        // ---------
        if (userIsAuthenticated) {
        /// 👆🏽👆🏽👆🏽
            UserInfoRow(
                label = stringResource(R.string.name_label),
                value = "Name goes here",
            )
            UserInfoRow(
                label = stringResource(R.string.email_label),
                value = "Email goes here",
            )
            UserPicture(
                url = stringResource(R.string.user_icon_url),
                description = "Description goes here",
            )
        /// 👇🏽👇🏽👇🏽 3. New code
        }
        /// 👆🏽👆🏽👆🏽
        /// 👇🏽👇🏽👇🏽 4. New code
        // Button
        // ------
        val buttonText: String
        val onClickAction: () -> Unit
        if (userIsAuthenticated) {
            buttonText = stringResource(R.string.log_out_button)
            onClickAction = {
                userIsAuthenticated = false
                appJustLaunched = false
            }
        } else {
            buttonText = stringResource(R.string.log_in_button)
            onClickAction = {
                userIsAuthenticated = true
            }
        }
        /// 👆🏽👆🏽👆🏽
        LogButton(
            /// 👇🏽👇🏽👇🏽 5. Updated code
            text = buttonText,
            onClick = onClickAction,
            /// 👆🏽👆🏽👆🏽
        )
    }
}
```

These notes correspond to the numbered “New code” and “Updated code” comments above:

1. This code determines the title shown onscreen:
    * If the user is logged out and has never logged in during this session, the title is “Welcome to the app!”. 
    * If the user is logged in, the title is “You’re logged in!” 
    * If the user is logged out after having logged in, the title is “You’re logged out.”
2. This `if` statement ensures that the user’s name, email address, and picture are displayed only if the user is logged in.
3. This is the closing parenthesis for the `if` statement above.
4. This sets up two values that determine the button's text (“Log In” or “Log Out”) and action based on whether the user is logged in.
5. This uses the two values above to compose the button.

🛠 Run the app. You can now press the _Log In_ button to go to the “logged in” screen and the _Log Out_ button to go to the “logged out” screen. You’ve added behavior and state management to the app!

In [Part Two of this tutorial](https://auth0.com/blog/android-authentication-jetpack-compose-2/), you’ll improve the architecture with a ViewModel and add Auth0 authentication to the app.