diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d03d4fa9d491bbdeb66240931f2e94074a13a73e..583530902065fdf6e6960cb19c7973dededcadab 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,11 +14,20 @@
         android:supportsRtl="true"
         android:theme="@style/Theme.BondoYap"
         tools:targetApi="31">
+
+        <service
+            android:name=".service.jwt.JwtService"
+            android:enabled="true"
+            android:exported="true"
+            android:permission="android.permission.INTERNET">
+        </service>
+
         <activity
             android:name=".ui.login.LoginActivity"
             android:exported="true">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
+
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
diff --git a/app/src/main/java/com/example/bondoyap/ApiClient.kt b/app/src/main/java/com/example/bondoyap/ApiClient.kt
deleted file mode 100644
index d1858bc3d5c3c4d5ec7b2a3de8f17f3427e5f6eb..0000000000000000000000000000000000000000
--- a/app/src/main/java/com/example/bondoyap/ApiClient.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.example.bondoyap
-
-import retrofit2.Call
-import retrofit2.http.Body
-import retrofit2.http.POST
-
-
-object Constants {
-    const val BASE_URL: String = "https://pbd-backend-2024.vercel.app/api/"
-    const val SHARED_PREFS_NAME = "Prefs"
-}
-
-interface ApiClient{
-    @POST("auth/login")
-    fun login(
-        @Body loginRequest: LoginRequest
-    ): Call<LoginResponse>
-
-    @POST("auth/token")
-    fun verifyToken(
-    ): Call<TokenResponse>
-
-    @POST("bill/upload")
-    fun uploadPicture(
-    )
-}
-
-data class LoginRequest(
-    val email: String,
-    val password: String
-)
-
-data class LoginResponse(
-    val token: String
-)
-
-data class TokenResponse(
-    val nim: String,
-    val iat: Number,
-    val exp: Number
-)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoyap/MainActivity.kt b/app/src/main/java/com/example/bondoyap/MainActivity.kt
index 7002b983d3102e2c405b8e123671fa18da86b984..bb0a8bfb7024ffb846255ee25e928a26a381d598 100644
--- a/app/src/main/java/com/example/bondoyap/MainActivity.kt
+++ b/app/src/main/java/com/example/bondoyap/MainActivity.kt
@@ -10,8 +10,9 @@ import androidx.navigation.findNavController
 import androidx.navigation.ui.AppBarConfiguration
 import androidx.navigation.ui.setupActionBarWithNavController
 import androidx.navigation.ui.setupWithNavController
-import com.example.bondoyap.Constants.SHARED_PREFS_NAME
+import com.example.bondoyap.service.api.Constants.SHARED_PREFS_NAME
 import com.example.bondoyap.databinding.ActivityMainBinding
+import com.example.bondoyap.service.jwt.JwtService
 import com.example.bondoyap.ui.login.LoginActivity
 
 class MainActivity : AppCompatActivity() {
@@ -29,6 +30,10 @@ class MainActivity : AppCompatActivity() {
             startActivity(intent)
             finish()
         }
+
+        val serviceIntent = Intent(this, JwtService::class.java)
+        this.startService(serviceIntent)
+
         binding = ActivityMainBinding.inflate(layoutInflater)
         setContentView(binding.root)
 
diff --git a/app/src/main/java/com/example/bondoyap/service/SessionManager.kt b/app/src/main/java/com/example/bondoyap/service/SessionManager.kt
new file mode 100644
index 0000000000000000000000000000000000000000..2a58fbedd688c66addcce7c0d7e46097fd22abd4
--- /dev/null
+++ b/app/src/main/java/com/example/bondoyap/service/SessionManager.kt
@@ -0,0 +1,52 @@
+package com.example.bondoyap.service
+
+import android.content.Context
+import android.content.SharedPreferences
+import com.example.bondoyap.service.api.Constants.SHARED_PREFS_NAME
+import com.example.bondoyap.ui.login.data.model.LoggedInUser
+import com.squareup.moshi.Moshi
+import com.squareup.moshi.JsonAdapter
+import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
+
+class SessionManager(context: Context) {
+
+    private var prefs: SharedPreferences = context.getSharedPreferences(SHARED_PREFS_NAME,
+        Context.MODE_PRIVATE)
+    private val editor: SharedPreferences.Editor = prefs.edit()
+
+
+    private val moshi: Moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
+    private val userAdapter: JsonAdapter<LoggedInUser> = moshi.adapter(LoggedInUser::class.java)
+
+    private fun getUser(): LoggedInUser? {
+        val userJson = prefs.getString("loggedInUser", null)
+        return userJson?.let {
+            userAdapter.fromJson(it)
+        }
+    }
+
+    fun saveExp(exp: Long){
+        editor.putLong("exp", exp)
+        editor.apply()
+    }
+
+    fun hasExp(): Boolean{
+        return getExp().toInt() != -1
+    }
+
+    fun getExp(): Long {
+        return prefs.getLong("exp", -1)
+    }
+
+    fun getToken(): String? {
+        val user = getUser()
+        return user?.let {
+            user.token
+        }
+    }
+
+    fun logout(){
+        editor.clear()
+        editor.apply()
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoyap/service/api/ApiClient.kt b/app/src/main/java/com/example/bondoyap/service/api/ApiClient.kt
new file mode 100644
index 0000000000000000000000000000000000000000..02b03eedad67243043d2ec12012358a46c6ca360
--- /dev/null
+++ b/app/src/main/java/com/example/bondoyap/service/api/ApiClient.kt
@@ -0,0 +1,40 @@
+package com.example.bondoyap.service.api
+
+import android.content.Context
+import com.squareup.moshi.Moshi
+import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
+import okhttp3.OkHttpClient
+import retrofit2.Retrofit
+import retrofit2.converter.moshi.MoshiConverterFactory
+
+class ApiClient {
+    private lateinit var apiService: ApiService
+    fun getApiService(context: Context): ApiService {
+
+        if (!::apiService.isInitialized) {
+
+            val moshi = Moshi.Builder()
+                .add(KotlinJsonAdapterFactory())
+                .build()
+
+            val retrofit = Retrofit.Builder()
+                .baseUrl(Constants.BASE_URL)
+                .client(okhttpClient(context))
+                .addConverterFactory(MoshiConverterFactory.create(moshi))
+                .build()
+
+            apiService = retrofit.create(ApiService::class.java)
+        }
+        return apiService
+    }
+
+    private fun okhttpClient(context: Context): OkHttpClient {
+        return OkHttpClient.Builder()
+            .addInterceptor(AuthInterceptor(context))
+            .build()
+    }
+
+}
+
+
+
diff --git a/app/src/main/java/com/example/bondoyap/service/api/ApiService.kt b/app/src/main/java/com/example/bondoyap/service/api/ApiService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..a7bf474abba94624133338ce218ad87295d7e584
--- /dev/null
+++ b/app/src/main/java/com/example/bondoyap/service/api/ApiService.kt
@@ -0,0 +1,24 @@
+package com.example.bondoyap.service.api
+
+import com.example.bondoyap.service.api.data.LoginRequest
+import com.example.bondoyap.service.api.data.LoginResponse
+import com.example.bondoyap.service.api.data.TokenResponse
+import retrofit2.Call
+import retrofit2.http.Body
+import retrofit2.http.POST
+
+interface ApiService {
+    @POST("auth/login")
+    fun login(
+        @Body loginRequest: LoginRequest
+    ): Call<LoginResponse>
+
+    @POST("auth/token")
+    fun verifyToken(
+        @Body token: String
+    ): Call<TokenResponse>
+
+    @POST("bill/upload")
+    fun uploadPicture(
+    )
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoyap/service/api/AuthInterceptor.kt b/app/src/main/java/com/example/bondoyap/service/api/AuthInterceptor.kt
new file mode 100644
index 0000000000000000000000000000000000000000..62f933c2fb87585dbdccb4095fd668ea970d4d1c
--- /dev/null
+++ b/app/src/main/java/com/example/bondoyap/service/api/AuthInterceptor.kt
@@ -0,0 +1,21 @@
+package com.example.bondoyap.service.api
+
+import android.content.Context
+import com.example.bondoyap.service.SessionManager
+import okhttp3.Interceptor
+import okhttp3.Response
+
+class AuthInterceptor(context: Context) : Interceptor {
+
+    private val sessionManager = SessionManager(context)
+
+    override fun intercept(chain: Interceptor.Chain): Response {
+        val requestBuilder = chain.request().newBuilder()
+
+        sessionManager.getToken()?.let {
+            requestBuilder.addHeader("Authorization", "Bearer $it")
+        }
+
+        return chain.proceed(requestBuilder.build())
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoyap/service/api/Constants.kt b/app/src/main/java/com/example/bondoyap/service/api/Constants.kt
new file mode 100644
index 0000000000000000000000000000000000000000..76fb345217e505ad47427a35808c9e2a256b86ef
--- /dev/null
+++ b/app/src/main/java/com/example/bondoyap/service/api/Constants.kt
@@ -0,0 +1,6 @@
+package com.example.bondoyap.service.api
+
+object Constants {
+    const val BASE_URL: String = "https://pbd-backend-2024.vercel.app/api/"
+    const val SHARED_PREFS_NAME = "BondoYap"
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoyap/service/api/data/LoginRequest.kt b/app/src/main/java/com/example/bondoyap/service/api/data/LoginRequest.kt
new file mode 100644
index 0000000000000000000000000000000000000000..583c050d0c129816df5e0901d18bdc0a60534c14
--- /dev/null
+++ b/app/src/main/java/com/example/bondoyap/service/api/data/LoginRequest.kt
@@ -0,0 +1,6 @@
+package com.example.bondoyap.service.api.data
+
+data class LoginRequest(
+    val email: String,
+    val password: String
+)
diff --git a/app/src/main/java/com/example/bondoyap/service/api/data/LoginResponse.kt b/app/src/main/java/com/example/bondoyap/service/api/data/LoginResponse.kt
new file mode 100644
index 0000000000000000000000000000000000000000..ca1bb881dc6e0eabc38cb64374fd2eee615d6a52
--- /dev/null
+++ b/app/src/main/java/com/example/bondoyap/service/api/data/LoginResponse.kt
@@ -0,0 +1,5 @@
+package com.example.bondoyap.service.api.data
+
+data class LoginResponse(
+    val token: String
+)
diff --git a/app/src/main/java/com/example/bondoyap/service/api/data/TokenResponse.kt b/app/src/main/java/com/example/bondoyap/service/api/data/TokenResponse.kt
new file mode 100644
index 0000000000000000000000000000000000000000..7f8a2be82dbdbfd2846355c965f5072680a02efb
--- /dev/null
+++ b/app/src/main/java/com/example/bondoyap/service/api/data/TokenResponse.kt
@@ -0,0 +1,7 @@
+package com.example.bondoyap.service.api.data
+
+data class TokenResponse(
+    val nim: String,
+    val iat: Long,
+    val exp: Long
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoyap/service/jwt/JwtService.kt b/app/src/main/java/com/example/bondoyap/service/jwt/JwtService.kt
new file mode 100644
index 0000000000000000000000000000000000000000..946a43539a7fc621e1cdf0e928e164eaa3d301b1
--- /dev/null
+++ b/app/src/main/java/com/example/bondoyap/service/jwt/JwtService.kt
@@ -0,0 +1,115 @@
+package com.example.bondoyap.service.jwt
+
+import android.app.Service
+import android.content.Context
+import android.content.Intent
+import android.os.Handler
+import android.os.IBinder
+import android.util.Log
+import android.widget.Toast
+import com.example.bondoyap.service.SessionManager
+import com.example.bondoyap.service.api.ApiClient
+import com.example.bondoyap.service.api.data.TokenResponse
+import com.example.bondoyap.ui.login.LoginActivity
+import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
+
+
+class JwtService : Service() {
+
+    private lateinit var handler : Handler
+
+    private lateinit var session: SessionManager
+
+    private val task = object : Runnable {
+        override fun run() {
+            Log.d("JwtService", "Current Time: ${System.currentTimeMillis()}")
+
+            session =  SessionManager(applicationContext)
+            val token = session.getToken()
+
+            if (token != null) {
+                verifyJwt(applicationContext, token)
+            }
+            // 5 second
+            handler.postDelayed(this, 5000)
+        }
+    }
+
+    private lateinit var apiClient: ApiClient
+
+    override fun onCreate() {
+        super.onCreate()
+        handler = Handler(mainLooper)
+    }
+
+    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+        handler.post(task)
+        return START_STICKY
+    }
+
+    override fun onBind(intent: Intent): IBinder? {
+        return null
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        handler.removeCallbacks(task)
+    }
+
+    fun verifyJwt(context: Context, token: String){
+        if (session.hasExp()) {
+            checkJwt(session.getExp())
+            return
+        }
+        apiClient = ApiClient()
+        apiClient.getApiService(context).verifyToken(token).enqueue(object: Callback<TokenResponse>{
+            override fun onFailure(call: Call<TokenResponse>, t: Throwable) {
+                Log.d("JwtService", "Error Failure")
+            }
+
+            override fun onResponse(call: Call<TokenResponse>, response: Response<TokenResponse>) {
+                Log.d("JwtService", "Getting Response")
+
+                val tokenResponse = response.body()
+
+                if (tokenResponse != null){
+                    Log.d("JwtService", "Updating Exp")
+
+                    session.saveExp(tokenResponse.exp)
+                    checkJwt(tokenResponse.exp)
+                } else {
+                    Log.d("JwtService", "Error response")
+                    Log.d("JwtService", "Error expired?")
+                    handleExpired()
+                }
+
+            }
+        })
+    }
+
+    fun checkJwt(exp: Long) {
+        val currentTimestamp = System.currentTimeMillis() / 1000
+
+        Log.d("JwtService", "exp : ${exp}")
+        Log.d("JwtService", "currentTime : ${currentTimestamp}")
+
+        if (currentTimestamp >= exp) {
+            Log.d("JwtService", "JWT is expired")
+            handleExpired()
+        } else {
+            Log.d("JwtService", "JWT is still valid")
+        }
+    }
+
+    fun handleExpired(){
+        session.logout()
+        Toast.makeText(applicationContext, "Session Expired! \n Logging out ...", Toast.LENGTH_LONG).show()
+
+        val intent = Intent(applicationContext, LoginActivity::class.java)
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
+        startActivity(intent)
+        stopSelf()
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/bondoyap/ui/login/LoginActivity.kt b/app/src/main/java/com/example/bondoyap/ui/login/LoginActivity.kt
index dc379ed4e8b62e97c645bf7be327eab0c35480ad..e64b43e08ad5bb67e76fc8892e9ef61387d0e9ee 100644
--- a/app/src/main/java/com/example/bondoyap/ui/login/LoginActivity.kt
+++ b/app/src/main/java/com/example/bondoyap/ui/login/LoginActivity.kt
@@ -14,7 +14,7 @@ import android.view.inputmethod.EditorInfo
 import android.widget.EditText
 import android.widget.Toast
 import androidx.appcompat.app.AppCompatActivity
-import com.example.bondoyap.Constants.SHARED_PREFS_NAME
+import com.example.bondoyap.service.api.Constants.SHARED_PREFS_NAME
 import com.example.bondoyap.MainActivity
 import com.example.bondoyap.R
 import com.example.bondoyap.databinding.ActivityLoginBinding
diff --git a/app/src/main/java/com/example/bondoyap/ui/login/LoginViewModelFactory.kt b/app/src/main/java/com/example/bondoyap/ui/login/LoginViewModelFactory.kt
index b0e9039da4e6694319d086bdc6fca269138c6c17..0b7abfa109b689c808959179ec0729362d3c2a8d 100644
--- a/app/src/main/java/com/example/bondoyap/ui/login/LoginViewModelFactory.kt
+++ b/app/src/main/java/com/example/bondoyap/ui/login/LoginViewModelFactory.kt
@@ -13,7 +13,7 @@ class LoginViewModelFactory(private val context: Context) : ViewModelProvider.Fa
         if (modelClass.isAssignableFrom(LoginViewModel::class.java)) {
             return LoginViewModel(
                 loginRepository = LoginRepository(
-                    dataSource = LoginDataSource(),
+                    dataSource = LoginDataSource(context),
                     context = context
 
                 )
diff --git a/app/src/main/java/com/example/bondoyap/ui/login/data/LoginDataSource.kt b/app/src/main/java/com/example/bondoyap/ui/login/data/LoginDataSource.kt
index cf54c3009a664f4756b194be6d01189ef6d85582..00f4b562726b80158e1de36da69e93f895b347ed 100644
--- a/app/src/main/java/com/example/bondoyap/ui/login/data/LoginDataSource.kt
+++ b/app/src/main/java/com/example/bondoyap/ui/login/data/LoginDataSource.kt
@@ -1,21 +1,20 @@
 package com.example.bondoyap.ui.login.data
 
-import com.example.bondoyap.ApiClient
-import com.example.bondoyap.Constants
-import com.example.bondoyap.LoginRequest
+import android.content.Context
+import android.util.Log
+import com.example.bondoyap.service.api.ApiClient
+import com.example.bondoyap.service.api.data.LoginRequest
 import com.example.bondoyap.ui.login.data.model.LoggedInUser
-import com.squareup.moshi.Moshi
-import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.withContext
-import retrofit2.Retrofit
-import retrofit2.converter.moshi.MoshiConverterFactory
 import java.io.IOException
 
 /**
  * Class that handles authentication w/ login credentials and retrieves user information.
  */
-class LoginDataSource {
+class LoginDataSource(private val context: Context) {
+
+    private lateinit var apiClient: ApiClient
 
     suspend fun login(email: String, password: String): Result<LoggedInUser> {
         return try {
@@ -35,29 +34,23 @@ class LoginDataSource {
 
     private suspend fun postLogin(email: String, password: String):String {
 
-        val moshi = Moshi.Builder()
-            .add(KotlinJsonAdapterFactory())
-            .build()
-
-        val api = Retrofit.Builder()
-            .baseUrl(Constants.BASE_URL)
-            .addConverterFactory(MoshiConverterFactory.create(moshi))
-            .build()
-
-        val apiClient = api.create(ApiClient::class.java)
+        apiClient = ApiClient()
+        val service = apiClient.getApiService(context)
 
         return withContext(Dispatchers.IO) {
             try {
                 val loginRequest = LoginRequest(email, password)
-                val response = apiClient.login(loginRequest).execute()
+                val response = service.login(loginRequest).execute()
 
                 if (response.isSuccessful) {
                     val loginResponse = response.body()
                     loginResponse?.token ?: throw IOException("Token not received")
                 } else {
+                    Log.d("LoginDataSource", "${response.code()} ${response.message()}")
                     throw IOException("${response.code()} ${response.message()}")
                 }
             } catch (e: Exception) {
+                Log.d("LoginDataSource", "Login failed: ${e.message}")
                 throw IOException("Login failed: ${e.message}")
             }
         }
diff --git a/app/src/main/java/com/example/bondoyap/ui/login/data/LoginRepository.kt b/app/src/main/java/com/example/bondoyap/ui/login/data/LoginRepository.kt
index bcc2777cdcfc8f2fb2f901308341f767067d0a7b..1d7293786899ffa28dc67352cbcd15d0149e34ab 100644
--- a/app/src/main/java/com/example/bondoyap/ui/login/data/LoginRepository.kt
+++ b/app/src/main/java/com/example/bondoyap/ui/login/data/LoginRepository.kt
@@ -3,6 +3,7 @@ package com.example.bondoyap.ui.login.data
 import com.example.bondoyap.ui.login.data.model.LoggedInUser
 import android.content.Context
 import android.content.SharedPreferences
+import com.example.bondoyap.service.api.Constants.SHARED_PREFS_NAME
 import com.squareup.moshi.JsonAdapter
 import com.squareup.moshi.Moshi
 import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
@@ -14,7 +15,7 @@ import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
 
 class LoginRepository(val dataSource: LoginDataSource, context: Context) {
 
-    private val sharedPreferences: SharedPreferences = context.getSharedPreferences("Prefs", Context.MODE_PRIVATE)
+    private val sharedPreferences: SharedPreferences = context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE)
     private val editor: SharedPreferences.Editor = sharedPreferences.edit()
 
     private val moshi: Moshi = Moshi.Builder().add(KotlinJsonAdapterFactory()).build()
diff --git a/app/src/main/java/com/example/bondoyap/ui/settings/SettingsViewModelFactory.kt b/app/src/main/java/com/example/bondoyap/ui/settings/SettingsViewModelFactory.kt
index b3b7f9747a79b29fc94a46c775d0ee604a767c45..ae367283563ca18363bc458743d2df24b2c51472 100644
--- a/app/src/main/java/com/example/bondoyap/ui/settings/SettingsViewModelFactory.kt
+++ b/app/src/main/java/com/example/bondoyap/ui/settings/SettingsViewModelFactory.kt
@@ -13,7 +13,7 @@ class SettingsViewModelFactory(private val context: Context) : ViewModelProvider
         if (modelClass.isAssignableFrom(SettingsViewModel::class.java)) {
             return SettingsViewModel(
                 loginRepository = LoginRepository(
-                    dataSource = LoginDataSource(),
+                    dataSource = LoginDataSource(context),
                     context = context
                 )
             ) as T