Using Data Store to store Jwt Token in native android development

Introduction

In modern Android development, handling user authentication securely is crucial. JSON Web Tokens (JWT) are a popular method for managing authentication tokens. However, storing these tokens securely is equally important. In this blog, we'll explore how to use Jetpack DataStore to store JWT tokens in a native Android application using the MVVM (Model-View-ViewModel) architecture. By the end, you'll understand when and why to use DataStore for secure token storage and how to implement it in your app.

Prerequisites

Before diving in, ensure you have the following:

  • Basic knowledge of Android development.

  • Familiarity with Kotlin and Android Studio.

  • Understanding of the MVVM architecture.

  • Jetpack DataStore library setup in your project.

Step 1: Setting Up DataStore

First, you need to add the necessary dependencies to your project. Open your build.gradle (Module: app) file and include the following:

dependencies {
    //make sure to get the latest version
    implementation "androidx.datastore:datastore-preferences:1.0.0"
}

Sync your project to ensure the dependencies are downloaded.

Step 2: Creating a DataStore Manager

Create a new Kotlin class DataStoreManager.kt. This class will handle all operations related to DataStore.

import android.content.Context
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

class DataStoreManager(context: Context) {

    private val Context.dataStore by preferencesDataStore("user_prefs")

    companion object {
        val JWT_TOKEN_KEY = stringPreferencesKey("jwt_token")
    }

    suspend fun saveJwtToken(token: String) {
        context.dataStore.edit { preferences ->
            preferences[JWT_TOKEN_KEY] = token
        }
    }

    val jwtToken: Flow<String?> = context.dataStore.data
        .map { preferences ->
            preferences[JWT_TOKEN_KEY]
        }
}

This DataStoreManager class provides two main functionalities:

  1. Saving the JWT Token: The saveJwtToken() function allows you to store the token in DataStore.

  2. Retrieving the JWT Token: The jwtToken flow provides a way to observe changes to the token in DataStore.

Step 3: Integrating DataStore with ViewModel

Next, create a UserViewModel.kt to manage the JWT token within the MVVM architecture.

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch

class UserViewModel(private val dataStoreManager: DataStoreManager) : ViewModel() {

    private val _jwtToken = MutableStateFlow<String?>(null)
    val jwtToken: StateFlow<String?> get() = _jwtToken

    init {
        viewModelScope.launch {
            dataStoreManager.jwtToken.collect {
                _jwtToken.value = it
            }
        }
    }

    fun saveJwtToken(token: String) {
        viewModelScope.launch {
            dataStoreManager.saveJwtToken(token)
        }
    }
}

In this UserViewModel, we're:

  • Collecting the JWT token from DataStoreManager and exposing it via a StateFlow.

  • Providing a method to save the JWT token using DataStoreManager.

Step 4: Using ViewModel in Your Activity or Fragment

Now, let's use the UserViewModel in an activity. For demonstration, we'll store the JWT token when a user logs in and retrieve it later.

import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {

    private val userViewModel: UserViewModel by viewModels {
        UserViewModelFactory(DataStoreManager(applicationContext))
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Saving JWT Token
        val jwtToken = "your_jwt_token_here"
        userViewModel.saveJwtToken(jwtToken)

        // Observing JWT Token
        lifecycleScope.launch {
            userViewModel.jwtToken.collect { token ->
                // Use the JWT token as needed
                println("JWT Token: $token")
            }
        }
    }
}

Conclusion

In this blog, we've walked through how to securely store and retrieve JWT tokens using Jetpack DataStore in a native Android application with MVVM architecture. This approach not only ensures secure token management but also aligns with the modern Android development practices. With DataStore, you can efficiently handle sensitive data like JWT tokens, providing a seamless and secure user experience.

Now, you're ready to integrate this into your Android projects and enhance your app's security!

Happ Coding!