Secure User Authentication in Android: A Comprehensive Guide [PART 2]
![Secure User Authentication in Android: A Comprehensive Guide [PART 2]](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1730046620546%2F0c354b05-fa92-4c44-a42f-fd2ec9566df9.png&w=3840&q=75)
Senior Android Engineer from Bangladesh. Love to contribute in Open-Source. Indie Music Producer.
Search for a command to run...
![Secure User Authentication in Android: A Comprehensive Guide [PART 2]](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1730046620546%2F0c354b05-fa92-4c44-a42f-fd2ec9566df9.png&w=3840&q=75)
Senior Android Engineer from Bangladesh. Love to contribute in Open-Source. Indie Music Producer.
No comments yet. Be the first to comment.
In today's mobile-first world, Android app security is more important than ever. Here’s a quick overview of key strategies to protect your apps and users' sensitive data.
Application security is essential for preventing unauthorized access, reverse engineering, and tampering with your Android apps. There are several strategies and tools that developers can employ to protect their applications from these threats. In th...
A practical guide to choosing the right coroutine primitive for your Android/Kotlin projects

This guide explains what Channels are, when to use them, how to use them correctly, and when NOT to use them — in simple, professional language. 1. What problem do Channels solve? In Kotlin coroutines, you often have multiple coroutines running at t...

Learn how to build preview-safe ViewModels in Jetpack Compose using Hilt.

HandlerInterceptor vs Filter in Spring Boot: A Practical Guide with JNDI Injection Prevention

Simple In-Memory Caching: A Tiny Trick with Massive Impact

User authentication is one of the most critical security aspects of any mobile application. Implementing secure authentication methods ensures that users’ data and accounts are protected from unauthorized access. In this article, we will dive deep into several techniques for implementing secure user authentication in Android, including Biometric Authentication (Fingerprint and Face), OAuth 2.0 & OpenID Connect, and Secure Password Storage. We’ll provide real-life examples and Kotlin code snippets for each method to help you integrate them into your Android apps.
Biometric authentication uses physical traits like fingerprints or facial recognition to authenticate users. This provides a more secure and convenient login experience compared to traditional password-based authentication, as biometrics are unique to each individual.
You can integrate the BiometricPrompt API in your Android app to allow users to authenticate using their fingerprint or face. This is particularly useful for apps where convenience and security are essential, such as banking apps, medical records, or any app handling sensitive data.
build.gradle file:implementation 'androidx.biometric:biometric:1.2.0-alpha05'
import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
fun showBiometricPrompt() {
val executor = ContextCompat.getMainExecutor(this)
val biometricPrompt = BiometricPrompt(this, executor, object : BiometricPrompt.AuthenticationCallback() {
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
// Authentication succeeded, proceed with login
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
// Handle error
}
override fun onAuthenticationFailed() {
// Handle failure
}
})
val promptInfo = BiometricPrompt.PromptInfo.Builder()
.setTitle("Biometric Authentication")
.setSubtitle("Use your fingerprint or face to login")
.setNegativeButtonText("Use password")
.build()
biometricPrompt.authenticate(promptInfo)
}
In this example, we use BiometricPrompt to prompt the user to authenticate using a fingerprint or facial recognition. If the biometric data matches, the user is authenticated successfully.
In a banking app, users can log in using their fingerprint or face for quicker access to their accounts, without needing to type a password each time. This not only enhances security but also improves user experience.
OAuth 2.0 and OpenID Connect are widely used frameworks for authentication and authorization, especially when an app needs to interact with external services like Google, Facebook, or custom APIs. OAuth 2.0 allows users to grant access to their data on one service without exposing their credentials, while OpenID Connect adds an identity layer on top of OAuth 2.0 for authentication.
Many apps use OAuth 2.0 to allow users to log in using their Google or Facebook accounts, which not only simplifies the login process but also improves security by avoiding the need for password management.
build.gradle file:implementation 'com.google.android.gms:play-services-auth:20.2.0'
import com.google.android.gms.auth.api.signin.GoogleSignIn
import com.google.android.gms.auth.api.signin.GoogleSignInAccount
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import com.google.android.gms.auth.api.signin.GoogleSignInOptions
import com.google.android.gms.tasks.Task
import android.content.Intent
private lateinit var googleSignInClient: GoogleSignInClient
fun setupGoogleSignIn() {
val gso = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestEmail()
.requestIdToken(getString(R.string.server_client_id)) // For backend verification
.build()
googleSignInClient = GoogleSignIn.getClient(this, gso)
}
fun signInWithGoogle() {
val signInIntent = googleSignInClient.signInIntent
startActivityForResult(signInIntent, RC_SIGN_IN)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RC_SIGN_IN) {
val task: Task<GoogleSignInAccount> = GoogleSignIn.getSignedInAccountFromIntent(data)
handleSignInResult(task)
}
}
private fun handleSignInResult(completedTask: Task<GoogleSignInAccount>) {
try {
val account = completedTask.getResult(ApiException::class.java)
// Signed in successfully, handle account data here
} catch (e: ApiException) {
// Sign-in failed, handle the error
}
}
In this example, Google Sign-In is implemented using OAuth 2.0, where the user can log in using their Google account. The Google ID token can be passed to your server for authentication.
In apps like Instagram, users can log in using their Facebook account via OAuth 2.0. This provides a seamless authentication process and enhances security by offloading password management to a trusted provider.
Storing passwords securely is essential to protect user credentials from being exposed in case of a data breach. Instead of storing plain-text passwords, they should be hashed and salted. Hashing transforms the password into a fixed-length string, while salting adds a random string to each password before hashing it, making it more resistant to attacks like rainbow table attacks.
When a user creates an account in your app, their password should be securely hashed and salted before storing it in the database. This ensures that even if the database is compromised, attackers cannot easily recover the original passwords.
import java.security.SecureRandom
import javax.crypto.SecretKeyFactory
import javax.crypto.spec.PBEKeySpec
import java.util.Base64
fun hashPassword(password: String, salt: ByteArray): String {
val spec = PBEKeySpec(password.toCharArray(), salt, 10000, 256) // 10000 iterations
val factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
val hash = factory.generateSecret(spec).encoded
return Base64.getEncoder().encodeToString(hash)
}
fun generateSalt(): ByteArray {
val random = SecureRandom()
val salt = ByteArray(16)
random.nextBytes(salt)
return salt
}
In this example, PBKDF2 (Password-Based Key Derivation Function 2) is used to securely hash and salt the password. You can also use alternatives like bcrypt or Argon2 for even better security.
fun verifyPassword(inputPassword: String, storedHash: String, salt: ByteArray): Boolean {
val inputHash = hashPassword(inputPassword, salt)
return inputHash == storedHash
}
Here, the input password is hashed again with the same salt, and the resulting hash is compared with the stored hash to verify if the password is correct.
In an e-commerce app, when users create accounts, their passwords should be securely hashed and stored in the database. During login, the app verifies the password by hashing the input again and comparing it with the stored hash, ensuring that user credentials are protected even if the database is compromised.
Implementing secure user authentication is a crucial step in building safe Android applications. The Biometric API enables seamless and secure login experiences using fingerprint or facial recognition. OAuth 2.0 & OpenID Connect simplify user authentication with external services like Google and Facebook while enhancing security with token-based authentication. Finally, securely storing passwords using hashing and salting ensures that even if an attacker gains access to your database, user credentials remain protected.
By following these techniques, you can enhance the security of your Android app and ensure that users' data is kept safe from unauthorized access.
That’s it for today. Happy coding…