diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 4efe4428e03b11a08b97f6e7e4cdb673a9813256..ca5df445a52388c9d83cb80c05d09a5edf4ea87e 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -44,6 +44,7 @@ android {
 }
 
 dependencies {
+    implementation("androidx.security:security-crypto:1.1.0-alpha06")
     implementation("androidx.core:core-splashscreen:1.0.1")
     implementation("com.android.volley:volley:1.2.1")
     implementation("androidx.core:core-ktx:1.12.0")
diff --git a/app/src/main/java/com/example/nerbos/repository/TransactionRepository.kt b/app/src/main/java/com/example/nerbos/repository/TransactionRepository.kt
index 378a6f2e1af9fda80cf7a9e5d2f51c5367ce8c23..e98414fcb27871c393616626711cf0f9c3eaac44 100644
--- a/app/src/main/java/com/example/nerbos/repository/TransactionRepository.kt
+++ b/app/src/main/java/com/example/nerbos/repository/TransactionRepository.kt
@@ -4,7 +4,6 @@ import androidx.lifecycle.LiveData
 import com.example.nerbos.model.Transaction
 import com.example.nerbos.data.TransactionDao
 import com.example.nerbos.model.TransactionCategory
-import com.example.nerbos.service.Authentication
 
 class TransactionRepository(private val transactionDao: TransactionDao) {
     var readAllData: LiveData<List<Transaction>>? = null
diff --git a/app/src/main/java/com/example/nerbos/service/Authentication.kt b/app/src/main/java/com/example/nerbos/service/Authentication.kt
index ca362b71f0e9ecefbb3d227e2b12bc23aaee4016..5dd7f05369dc0c7d8ff4630ab5a4ae1046b009c2 100644
--- a/app/src/main/java/com/example/nerbos/service/Authentication.kt
+++ b/app/src/main/java/com/example/nerbos/service/Authentication.kt
@@ -3,12 +3,18 @@ package com.example.nerbos.service
 import android.content.Context
 import android.content.Intent
 import android.content.SharedPreferences
+import android.security.keystore.KeyGenParameterSpec
+import android.security.keystore.KeyProperties
 import com.android.volley.Request
 import com.android.volley.toolbox.JsonObjectRequest
 import com.android.volley.toolbox.Volley
 import com.example.nerbos.LoginActivity
 import com.example.nerbos.R
 import org.json.JSONObject
+import java.security.KeyPairGenerator
+import java.security.KeyStore
+import javax.crypto.Cipher
+import android.util.Base64
 
 interface AuthCallback {
     fun onSuccess() {
@@ -23,6 +29,34 @@ interface AuthCallback {
 }
 
 class Authentication(private val context: Context) {
+    private val keyStore: KeyStore = KeyStore.getInstance(context.getString(R.string.android_key_store))
+        .apply {
+            load(null)
+        }
+
+    private fun generateKeyPair() {
+        // Generate key pair
+        val keyPairGenerator = KeyPairGenerator.getInstance(
+            KeyProperties.KEY_ALGORITHM_RSA, context.getString(R.string.android_key_store)
+        )
+        keyPairGenerator.initialize(
+            KeyGenParameterSpec.Builder(
+                context.getString(R.string.key_alias),
+                KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
+            ).apply {
+                setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
+                setDigests(KeyProperties.DIGEST_SHA256)
+                setUserAuthenticationRequired(false)
+            }.build()
+        )
+        keyPairGenerator.generateKeyPair()
+    }
+
+    private fun checkKeyPair() {
+        if (!keyStore.containsAlias(context.getString(R.string.key_alias))) {
+            generateKeyPair()
+        }
+    }
 
     // Service: API Authentication for login and token checking
     fun login(email: String, password: String, callback: AuthCallback) {
@@ -48,7 +82,7 @@ class Authentication(private val context: Context) {
             },
             { error ->
                 // handle error
-                callback.onError(error.message ?: "Wrong email or password")
+                callback.onError(error.message ?: context.getString(R.string.wrong_credentials))
             }
         )
 
@@ -57,40 +91,54 @@ class Authentication(private val context: Context) {
 
 
     private fun saveToken(token: String) {
-        val sharedPreferences : SharedPreferences =
-            context.getSharedPreferences(context.getString(R.string.preferences), Context.MODE_PRIVATE)
-        val editor = sharedPreferences.edit()
-        editor.putString(context.getString(R.string.token), token)
-        editor.apply()
-    }
+        checkKeyPair()
+        // get public key from key store
+        val privateKeyEntry = keyStore.getEntry(context.getString(R.string.key_alias), null) as KeyStore.PrivateKeyEntry
+        val publicKey = privateKeyEntry.certificate.publicKey
 
-    private fun saveEmail(email: String) {
+        // initialize cipher with public key
+        val cipher = Cipher.getInstance(context.getString(R.string.cipher_transformation))
+        cipher.init(Cipher.ENCRYPT_MODE, publicKey)
+
+        // encrypt token
+        val encryptedToken = cipher.doFinal(token.toByteArray())
+
+        // save encrypted token to shared preferences
+        val encryptedTokenString = Base64.encodeToString(encryptedToken, Base64.DEFAULT)
         val sharedPreferences : SharedPreferences =
             context.getSharedPreferences(context.getString(R.string.preferences), Context.MODE_PRIVATE)
         val editor = sharedPreferences.edit()
-        editor.putString(context.getString(R.string.email), email)
+        editor.putString(context.getString(R.string.token), encryptedTokenString)
         editor.apply()
     }
 
-    fun getEmail(): String {
-        val sharedPreferences : SharedPreferences =
+    fun getToken(): String {
+        checkKeyPair()
+        // get encrypted token from shared preferences
+        val sharedPreferences: SharedPreferences =
             context.getSharedPreferences(context.getString(R.string.preferences), Context.MODE_PRIVATE)
-        // if no email in shared preferences, return default value
-        return sharedPreferences.getString(context.getString(R.string.email), "13521000@std.stei.itb.ac.id") ?: ""
-    }
+        val encryptedTokenString = sharedPreferences.getString(context.getString(R.string.token), "") ?: ""
+        if (encryptedTokenString == "") {
+            return ""
+        }
 
-    fun getNim(): Int {
-        val email = getEmail().split("@")[0]
-        return email.toInt()
-    }
+        // get private key from key store
+        val privateKeyEntry = keyStore.getEntry(context.getString(R.string.key_alias), null) as KeyStore.PrivateKeyEntry
+        val privateKey = privateKeyEntry.privateKey
 
-    internal fun getToken(): String {
-        val sharedPreferences : SharedPreferences =
-            context.getSharedPreferences(context.getString(R.string.preferences), Context.MODE_PRIVATE)
-        return sharedPreferences.getString(context.getString(R.string.token), "") ?: ""
+        // initialize cipher with private key
+        val cipher = Cipher.getInstance(context.getString(R.string.cipher_transformation))
+        cipher.init(Cipher.DECRYPT_MODE, privateKey)
+
+        // decrypt token
+        val encryptedToken = Base64.decode(encryptedTokenString, Base64.DEFAULT)
+        val decryptedToken = cipher.doFinal(encryptedToken)
+        return String(decryptedToken, Charsets.UTF_8)
     }
 
+
     fun checkToken(callback: AuthCallback) {
+        checkKeyPair()
         val token = getToken()
         if (token.isNotEmpty()) {
             val request = object : JsonObjectRequest(
@@ -111,11 +159,10 @@ class Authentication(private val context: Context) {
                 }) {
                 override fun getHeaders(): MutableMap<String, String> {
                     val headers = HashMap<String, String>()
-                    headers["Authorization"] = "Bearer $token"
+                    headers[context.getString(R.string.authorization)] = context.getString(R.string.bearer) + " " + token
                     return headers
                 }
             }
-
             Volley.newRequestQueue(context).add(request)
         }
     }
@@ -134,4 +181,25 @@ class Authentication(private val context: Context) {
         intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
         context.startActivity(intent)
     }
+
+    // Save and get email from shared preferences
+    private fun saveEmail(email: String) {
+        val sharedPreferences : SharedPreferences =
+            context.getSharedPreferences(context.getString(R.string.preferences), Context.MODE_PRIVATE)
+        val editor = sharedPreferences.edit()
+        editor.putString(context.getString(R.string.email), email)
+        editor.apply()
+    }
+
+    fun getEmail(): String {
+        val sharedPreferences : SharedPreferences =
+            context.getSharedPreferences(context.getString(R.string.preferences), Context.MODE_PRIVATE)
+        // if no email in shared preferences, return default value
+        return sharedPreferences.getString(context.getString(R.string.email), context.getString(R.string.default_email)) ?: ""
+    }
+
+    fun getNim(): Int {
+        val email = getEmail().split("@")[0]
+        return email.toInt()
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 4850983e3b3a6d9ef0f9a0685b30a9efdcb5edb7..891f9fa2132678e79ff4dad7c11e5aed1d8996ce 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -14,9 +14,16 @@
     <string name="login_password_placeholder">Password</string>
     <string name="error_login">Error</string>
     <string name="error_fields">Please fill out all the fields</string>
+    <string name="wrong_credentials">Wrong email or password</string>
     <string name="email">email</string>
     <string name="password">password</string>
     <string name="token">token</string>
+    <string name="key_alias">key13521000</string>
+    <string name="cipher_transformation">RSA/ECB/PKCS1Padding</string>
+    <string name="android_key_store">AndroidKeyStore</string>
+    <string name="default_email">13521000@std.stei.itb.ac.id</string>
+    <string name="authorization">Authorization</string>
+    <string name="bearer">Bearer</string>
 
     <string name="preferences">NosPreferences</string>