Android Quickstart
Before you start
Example repository
Enable Native API
In the Clerk Dashboard, navigate to the Native applications page and enable the Native API. This is required to integrate Clerk in your native application or browser extension.
Create a new Android app
-
If you don't already have an Android app, create a new project in Android Studio using the Empty Activity template. This tutorial uses
MyClerkAppas the app name. If your app has a different name, be sure to update any code examples accordingly to match your app's name. -
Open the
app/build.gradle.ktsfile and ensure that your project's minimum SDK version is set to 24 or higher, and that your project's Java version is set to 17 or higher, as these are the minimum requirements for the Clerk Android SDK. -
In
app/build.gradle.kts, add the following libraries to yourdependenciesblock:-
The Clerk Android SDK. Check the GitHub release page for the latest version. The SDK is split into two packages:
com.clerk:clerk-android-api- The core Clerk SDK for authentication and user management.com.clerk:clerk-android-ui- The Clerk UI components for authentication and user management.
-
Android's Lifecycle ViewModel Compose library.
dependencies { ... // Only if you're using the Clerk API without the Clerk UI components implementation("com.clerk:clerk-android-api:<latest-version>") implementation("com.clerk:clerk-android-ui:<latest-version>") implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.9.2") ... }
-
-
Sync your project to apply the changes after adding the dependencies.
Initialize Clerk
In app/src/main/java/com/example/myclerkapp/, create a Kotlin class named MyClerkApp. Add the following code to:
- Create a subclass of
Applicationnamed after your application (e.g.,MyClerkApp). - In this subclass, override the
onCreate()method and callClerk.initialize()to initialize the Clerk Android SDK with your application context (this) and Clerk .
- Create a subclass of
Applicationnamed after your application (e.g.,MyClerkApp). - In this subclass, override the
onCreate()method and callClerk.initialize()to initialize the Clerk Android SDK with your application context (this) and Clerk .
To find your Publishable Key:
- In the Clerk Dashboard, navigate to the API keys page.
- Copy your Clerk Publishable Key. It's prefixed with
pk_test_for development instances andpk_live_for production instances.
package com.example.myclerkapp
import android.app.Application
import com.clerk.api.Clerk
class MyClerkApp: Application() {
override fun onCreate() {
super.onCreate()
Clerk.initialize(
this,
publishableKey = "YOUR_PUBLISHABLE_KEY"
)
}
}Configure the AndroidManifest.xml
In app/src/main/AndroidManifest.xml, add the following configuration:
-
Inside the root
<manifest>tag, add the following line to enable internet permission on your Android device.<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.INTERNET"/> ... </manifest> -
Inside the
<application>tag, add the following line to use theMyClerkAppclass as the entry point for app-level configuration.<application android:name=".MyClerkApp"> ... </application>
Listen for SDK initialization and authentication events
Let's start building out your home page.
In your app/src/main/java/com/example/myclerkapp/ directory, create a Kotlin class named MainViewModel with the following code. MainViewModel is a ViewModel that sets the state as Loading when the Clerk SDK is initializing, SignedIn when the user is signed in, or SignedOut when the user is signed out. The Clerk SDK initialization is non-blocking. Therefore, it's recommended to listen for the SDK to emit a success from Clerk's isInitialized global object to know when it's ready to use.
package com.example.myclerkapp
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.clerk.api.Clerk
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.launchIn
class MainViewModel: ViewModel() {
private val _uiState = MutableStateFlow<MainUiState>(MainUiState.Loading)
val uiState = _uiState.asStateFlow()
init {
combine(Clerk.isInitialized, Clerk.userFlow) { isInitialized, user ->
_uiState.value = when {
!isInitialized -> MainUiState.Loading
user != null -> MainUiState.SignedIn
else -> MainUiState.SignedOut
}
}
.launchIn(viewModelScope)
}
}
sealed interface MainUiState {
data object Loading : MainUiState
data object SignedIn : MainUiState
data object SignedOut : MainUiState
}Conditionally render content
Now that you're listening for initialization and authentication events, set up your UI to react to them. In your MainActivity.kt, add the following code. This will show a loading indicator while the Clerk SDK is initializing, and a signed in or signed out experience based on the user's authentication state.
package com.example.myclerkapp
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val viewModel: MainViewModel by viewModels()
val state by viewModel.uiState.collectAsStateWithLifecycle()
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
when (state) {
MainUiState.Loading -> CircularProgressIndicator()
MainUiState.SignedOut -> Text("You're signed out")
MainUiState.SignedIn -> Text("You're signed in")
}
}
}
}
}Choose an authentication approach
Choose hosted authentication for the fastest setup, native components for a prebuilt Jetpack Compose experience, or a custom flow for complete control over the UI.
Hosted authentication opens Account Portal in a browser authentication session. Account Portal supports the sign-in and sign-up methods enabled for your Clerk application.
In the Clerk Dashboard, navigate to the Native applications page and add your app's namespace and package name. Production instances use them to validate the default callback to your app, so add them before you create a production build.
In MainActivity.kt, add the imports shown below. Then, inside setContent, replace the Box you added in the previous step with the following code. After authentication, the SDK updates Clerk.userFlow with the signed-in user.
import androidx.compose.material3.Button
import androidx.compose.runtime.rememberCoroutineScope
import com.clerk.api.Clerk
import com.clerk.api.auth.HostedAuthMode
import com.clerk.api.network.serialization.onFailure
import kotlinx.coroutines.launch
val scope = rememberCoroutineScope()
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
when (state) {
MainUiState.Loading -> CircularProgressIndicator()
MainUiState.SignedOut -> Button(
onClick = {
scope.launch {
Clerk.auth.startHostedAuth(mode = HostedAuthMode.SIGN_UP).onFailure {
// The user dismissed the browser, or authentication failed.
}
}
},
) {
Text("Sign up")
}
MainUiState.SignedIn -> Text("You're signed in")
}
}Clerk's AuthView handles sign-in and sign-up flows without custom forms.
In MainActivity.kt, import AuthView and UserButton. Then, inside setContent, replace the Box you added in the previous step with the following code:
import com.clerk.ui.auth.AuthView
import com.clerk.ui.userbutton.UserButton
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
when (state) {
MainUiState.Loading -> CircularProgressIndicator()
MainUiState.SignedOut -> AuthView()
MainUiState.SignedIn -> UserButton()
}
}Custom flows use the Clerk API with your own Jetpack Compose views. The following example builds an email and password sign-up view, then renders it when the user is signed out.
Create a Kotlin class named SignUpViewModel with the following code. It allows users to sign up using their email address and password, and sends an email verification code to confirm their email address.
package com.example.myclerkapp
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.clerk.api.Clerk
import com.clerk.api.network.serialization.errorMessage
import com.clerk.api.network.serialization.onFailure
import com.clerk.api.network.serialization.onSuccess
import com.clerk.api.signup.SignUp
import com.clerk.api.signup.attemptVerification
import com.clerk.api.signup.prepareVerification
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
class SignUpViewModel : ViewModel() {
private val _uiState = MutableStateFlow<SignUpUiState>(SignUpUiState.SignedOut)
val uiState = _uiState.asStateFlow()
fun signUp(email: String, password: String) {
viewModelScope.launch {
SignUp.create(SignUp.CreateParams.Standard(emailAddress = email, password = password))
.onSuccess {
if (it.status == SignUp.Status.COMPLETE) {
_uiState.value = SignUpUiState.Success
} else {
_uiState.value = SignUpUiState.NeedsVerification
it.prepareVerification(SignUp.PrepareVerificationParams.Strategy.EmailCode())
}
}
.onFailure {
// See https://clerk.com/docs/guides/development/custom-flows/error-handling
// for more info on error handling
Log.e("SignUpViewModel", it.errorMessage, it.throwable)
}
}
}
fun verify(code: String) {
val inProgressSignUp = Clerk.auth.currentSignUp ?: return
viewModelScope.launch {
inProgressSignUp
.attemptVerification(SignUp.AttemptVerificationParams.EmailCode(code))
.onSuccess { _uiState.value = SignUpUiState.Success }
.onFailure {
// See https://clerk.com/docs/guides/development/custom-flows/error-handling
// for more info on error handling
Log.e("SignUpViewModel", it.errorMessage, it.throwable)
}
}
}
sealed interface SignUpUiState {
data object SignedOut : SignUpUiState
data object Success : SignUpUiState
data object NeedsVerification : SignUpUiState
}
}Then, create a SignUpView file with the following code to use the SignUpViewModel.
package com.example.myclerkapp
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.material3.TextField
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun SignUpView(viewModel: SignUpViewModel = viewModel()) {
val state by viewModel.uiState.collectAsState()
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(24.dp, Alignment.CenterVertically)
) {
Text("Sign Up")
if (state is SignUpViewModel.SignUpUiState.NeedsVerification) {
var code by remember { mutableStateOf("") }
TextField(value = code, onValueChange = { code = it })
Button(onClick = { viewModel.verify(code) }) { Text("Verify") }
} else {
var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
TextField(value = email, onValueChange = { email = it }, placeholder = { Text("Email") })
TextField(
value = password,
placeholder = { Text("Password") },
onValueChange = { password = it },
visualTransformation = PasswordVisualTransformation(),
)
Button(onClick = { viewModel.signUp(email, password) }) { Text("Sign Up") }
}
}
}Then, in your MainActivity file, render SignUpView when the user isn't signed in.
package com.example.myclerkapp
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.viewModels
import androidx.compose.runtime.getValue
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.lifecycle.compose.collectAsStateWithLifecycle
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val viewModel: MainViewModel by viewModels()
val state by viewModel.uiState.collectAsStateWithLifecycle()
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
when (state) {
MainUiState.Loading -> CircularProgressIndicator()
MainUiState.SignedOut -> SignUpView()
MainUiState.SignedIn -> Text("You're signed in")
}
}
}
}
}See the Android authentication reference for the other strategies available through Clerk.auth.
Run your project
In Android Studio, select Run ▶︎ to build and launch the app.
Create your first user
Once the app launches successfully, select Sign up and complete the authentication flow to create your first user.
Next steps
Explore the most relevant next steps for your SDK using the following guides.
Prebuilt views
Learn how to quickly add authentication to your app using Clerk's suite of views.
Customization with ClerkTheme
Learn how to customize Clerk views using ClerkTheme.
Add native Sign in with Google
Learn how to add native Sign in with Google to your Clerk apps on Android platforms.
Clerk Android SDK reference
Learn about the Clerk Android SDK and how to integrate it into your app.
Feedback
Last updated on