Clerk helps developers build user management. We provide streamlined user experiences for your users to sign up, sign in, and manage their profile.
Clerk is Hiring!
Would you like to work on Open Source software and help maintain this repository? Apply today!
- Android API Level 24 (Android 7.0) or higher
- Kotlin 2.2.0 or higher
- Java 17 or higher
- Android Gradle Plugin 8.11.0 or higher
- Sign up for an account
- Create an application in your Clerk dashboard
- Copy your Publishable Key from the API Keys section
Add the Clerk Android SDK to your project following the installation instructions below.
Configure Clerk in your application class with your publishable key.
Use Clerk's authentication methods to enable sign-up, sign-in, and user management.
The Clerk Android SDK is distributed via Maven Central.
First, ensure you have added mavenCentral to your project's build.gradle(.kts)
:
repositories {
mavenCentral()
}
Add the Clerk SDK to your application's dependencies:
dependencies {
implementation 'com.clerk:clerk-android:0.1.0'
}
Kotlin DSL:
dependencies {
implementation("com.clerk:clerk-android:0.1.0")
}
π‘ Tip: Check Maven Central for the latest version.
Before using any part of the SDK, you must call Clerk.initialize()
in your Application class with your publishable key and application context:
import com.clerk.Clerk
class YourApplication : Application() {
override fun onCreate() {
super.onCreate()
Clerk.initialize(
context = this,
publishableKey = "pk_test_..." // Your publishable key from Clerk Dashboard
)
}
}
Don't forget to register your Application class in AndroidManifest.xml
:
<application
android:name=".YourApplication"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<!-- ... -->
</application>
Now you can conditionally render content based on the user's session:
import com.clerk.Clerk
if (Clerk.user != null) {
Text("Hello, ${Clerk.user?.firstName ?: "User"}")
} else {
Text("You are signed out")
}
All authentication functions follow a consistent parameter pattern where function parameters are exposed as data classes named after the function itself (e.g., SignUp.Create
parameters are SignUp.SignUpCreateParams
).
import com.clerk.SignUp
// Create a sign up
SignUp.create(SignUp.CreateParams.Standard(emailAddress = "user@example.com"))
.onSuccess { signUp ->
// Check if the SignUp needs the email address verified and send an OTP code via email
if (signUp.unverifiedFields.contains("email_address")) {
signUp.prepareVerification(SignUp.PrepareVerificationParams.EMAIL_CODE)
.onSuccess {
// OTP sent successfully
}
.onFailure {
// Handle error
}
}
}
.onFailure { error ->
// Handle sign-up creation error
Log.e("Clerk", "Sign-up failed: ${error.message}")
}
// After collecting the OTP from the user
Clerk.signUp?.attemptVerification(SignUp.AttemptVerificationParams.EmailCode(code = "123456"))
.onSuccess {
// User is signed in successfully
}
import com.clerk.SignIn
var signIn: SignIn? = null
// Create the sign in
SignIn.create(SignIn.CreateParams.Strategy.EmailCode("email@example.com"))
.onSuccess {
signIn = it
// OTP code sent to email
}
// After collecting the OTP code from the user, attempt verification
signIn?.attemptFirstFactor(SignIn.AttemptFirstFactorParams.Strategy.EmailCode("123456"))
.onSuccess {
// User signed in successfully
}
Clerk handles the OAuth flow and deep linking automatically:
import com.clerk.SignIn
import com.clerk.network.model.oauth.OAuthProvider
// This will open the OAuth provider's sign-in page
SignIn.authenticateWithRedirect(OAuthProvider.GOOGLE)
.onSuccess {
// OAuth flow initiated successfully
}
SignIn.authenticateWithGoogleOneTap()
.onSuccess {
// Google One Tap sign-in successful
}
.onFailure { error ->
Log.e("Clerk", "Google One Tap failed: ${error.message}")
}
import com.clerk.passkeys.CredentialType
SignIn.authenticateWithGoogleCredentialManager(
credentialTypes = listOf(
CredentialType.PASSKEY,
CredentialType.PASSWORD,
CredentialType.GOOGLE
)
)
.onSuccess {
// Authentication successful
}
.onFailure { error ->
Log.e("Clerk", "Credential Manager auth failed: ${error.message}")
}
import com.clerk.SignIn
// Create a sign in and send an OTP code to verify the user owns the email
SignIn.create(SignIn.CreateParams.Strategy.EmailCode("user@example.com"))
.onSuccess { signIn ->
// After collecting the OTP code from the user, attempt verification
signIn.attemptFirstFactor(SignIn.AttemptFirstFactorParams.Strategy.ResetPasswordEmailCode("123456"))
.onSuccess { verifiedSignIn ->
// Set a new password to complete the process
verifiedSignIn.resetPassword(
password = "newSecurePassword123!",
signOutOfOtherSessions = true
)
.onSuccess {
// Password reset successful
}
}
}
Clerk.signOut()
.onSuccess {
// User signed out successfully
}
.onFailure { error ->
Log.e("Clerk", "Sign out failed: ${error.message}")
}
import com.clerk.User
Clerk.user.update(
User.UpdateParams(firstName = "Walter", lastName = "Johnson"))
.onSuccess {
updatedUser -> // User updated
}
// After getting a java.io.File object to upload
val imageFile: File = // ... your image file
Clerk.user.setProfileImage(file = imageFile)
.onSuccess {
// Profile image updated successfully
}
import com.clerk.PhoneNumber
lateinit var newPhoneNumber: PhoneNumber
// Create a new phone number on the user's account
Clerk.user.createPhoneNumber("+15555550100")
.onSuccess { phoneNumber ->
newPhoneNumber = phoneNumber
// Use the returned resource to send an OTP
newPhoneNumber.prepareVerification()
}
// After collecting the OTP code from the user, attempt verification
newPhoneNumber.attemptVerification(code = "123456")
.onSuccess {
// Phone number verified and added successfully
}
.onFailure { error ->
Log.e("Clerk", "Phone verification failed: ${error.message}")
}
import com.clerk.User
import com.clerk.network.model.oauth.OAuthProvider
Clerk.user.createExternalAccount(
User.CreateExternalAccountParams(provider = OAuthProvider.GOOGLE)
).onSuccess { externalAccount ->
externalAccount.reauthorize()
}
// Get the current session token for API calls
Clerk.session.fetchToken().jwt.let { token ->
// Use the token in your API requests
val headers = mutableMapOf<String, String>()
headers["Authorization"] = "Bearer $token"
// Make your authenticated API call
// ...
}
"Clerk not initialized" error:
- Make sure you've called
Clerk.initialize()
in your Application class - Verify your Application class is registered in
AndroidManifest.xml
- Check that your publishable key is correct
OAuth deep linking not working:
- Verify your configuration in the Clerk Dashboard
ProGuard/R8 issues:
- The SDK includes ProGuard rules automatically
- If you encounter issues, check the
proguard-rules.pro
file in the SDK
- π Documentation
- π¬ Discord Community
- π§ Support
- π Report Issues
Feature | Android Support | Notes |
---|---|---|
Email/Phone/Username Authentication | β | Full support |
Email Code Verification | β | OTP via email |
SMS Code Verification | β | OTP via SMS |
Multi-Factor Authentication (TOTP / SMS) | β | TOTP and SMS |
Sign in / Sign up with OAuth | β | Google, GitHub, Apple, etc. |
Native Sign in with Google | β | Google One Tap |
Session Management | β | Full session lifecycle |
Forgot Password | β | Email-based reset |
User Management | β | Profile, phone, email management |
Passkeys | β | WebAuthn support |
Enterprise SSO (SAML) | β | Enterprise authentication |
Device Attestation | β | Android Play Integrity |
Multi-Session Applications | β | Coming soon |
Organizations | β | Coming soon |
Prebuilt UI Components | β | Coming soon |
Magic Links | β | Planned |
Web3 Wallet | β | Planned |
We welcome contributions! Please see our Contributing Guidelines for details.
- Clone the repository
- Open in Android Studio
- Sync project with Gradle files
- Run tests:
./gradlew test
This project is licensed under the MIT license.
See LICENSE for more information.
Made with β€οΈ by Clerk