diff --git a/app/src/main/java/audio/funkwhale/ffa/repositories/HttpUpstream.kt b/app/src/main/java/audio/funkwhale/ffa/repositories/HttpUpstream.kt
index 08b53ade5c33fd8950685d270cba4dfcb44b8a56..f01c4d384b21b66f8950d8df5ce898e681a16532 100644
--- a/app/src/main/java/audio/funkwhale/ffa/repositories/HttpUpstream.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/repositories/HttpUpstream.kt
@@ -2,12 +2,12 @@ package audio.funkwhale.ffa.repositories
 
 import android.content.Context
 import android.net.Uri
+import android.util.Log
 import audio.funkwhale.ffa.utils.*
 import com.github.kittinunf.fuel.Fuel
 import com.github.kittinunf.fuel.core.FuelError
 import com.github.kittinunf.fuel.core.ResponseDeserializable
 import com.github.kittinunf.fuel.coroutines.awaitObjectResponseResult
-import com.github.kittinunf.fuel.coroutines.awaitObjectResult
 import com.github.kittinunf.result.Result
 import com.google.gson.Gson
 import kotlinx.coroutines.Dispatchers.IO
@@ -33,8 +33,6 @@ class HttpUpstream<D : Any, R : OtterResponse<D>>(
     Progressive
   }
 
-  private val http = HTTP(context, oAuth)
-
   override fun fetch(size: Int): Flow<Repository.Response<D>> = flow<Repository.Response<D>> {
 
     context?.let {
@@ -42,14 +40,13 @@ class HttpUpstream<D : Any, R : OtterResponse<D>>(
 
       val page = ceil(size / AppContext.PAGE_SIZE.toDouble()).toInt() + 1
 
-      val url =
-        Uri.parse(url)
-          .buildUpon()
-          .appendQueryParameter("page_size", AppContext.PAGE_SIZE.toString())
-          .appendQueryParameter("page", page.toString())
-          .appendQueryParameter("scope", Settings.getScopes().joinToString(" "))
-          .build()
-          .toString()
+      val url = Uri.parse(url)
+        .buildUpon()
+        .appendQueryParameter("page_size", AppContext.PAGE_SIZE.toString())
+        .appendQueryParameter("page", page.toString())
+        .appendQueryParameter("scope", Settings.getScopes().joinToString(" "))
+        .build()
+        .toString()
 
       get(it, url).fold(
         { response ->
@@ -88,16 +85,16 @@ class HttpUpstream<D : Any, R : OtterResponse<D>>(
   }
 
   suspend fun get(context: Context, url: String): Result<R, FuelError> {
+    Log.i("HttpUpstream", "get() - url: $url")
     return try {
-      val request = Fuel.get(mustNormalizeUrl(url)).apply {
+      val normalizedUrl = mustNormalizeUrl(url)
+      val request = Fuel.get(normalizedUrl).apply {
         authorize(context, oAuth)
       }
       val (_, response, result) = request.awaitObjectResponseResult(GenericDeserializer<R>(type))
-
       if (response.statusCode == 401) {
-        return retryGet(url)
+        return retryGet(normalizedUrl)
       }
-
       result
     } catch (e: Exception) {
       Result.error(FuelError.wrap(e))
@@ -105,19 +102,15 @@ class HttpUpstream<D : Any, R : OtterResponse<D>>(
   }
 
   private suspend fun retryGet(url: String): Result<R, FuelError> {
+    Log.i("HttpUpstream", "retryGet() - url: $url")
     context?.let {
       return try {
-        return if (http.refresh()) {
-          val request = Fuel.get(mustNormalizeUrl(url)).apply {
-            if (!Settings.isAnonymous()) {
-              header("Authorization", "Bearer ${oAuth.state().accessToken}")
-            }
-          }
-
-          request.awaitObjectResult(GenericDeserializer(type))
-        } else {
-          Result.Failure(FuelError.wrap(RefreshError))
+        oAuth.refreshAccessToken(context)
+        val request = Fuel.get(url).apply {
+          authorize(context, oAuth)
         }
+        val (_, _, result) = request.awaitObjectResponseResult(GenericDeserializer<R>(type))
+        result
       } catch (e: Exception) {
         Result.error(FuelError.wrap(e))
       }
diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/Data.kt b/app/src/main/java/audio/funkwhale/ffa/utils/Data.kt
deleted file mode 100644
index 02c82d606081f4940b158250be89869d2e265c77..0000000000000000000000000000000000000000
--- a/app/src/main/java/audio/funkwhale/ffa/utils/Data.kt
+++ /dev/null
@@ -1,120 +0,0 @@
-package audio.funkwhale.ffa.utils
-
-import android.content.Context
-import audio.funkwhale.ffa.activities.FwCredentials
-import com.github.kittinunf.fuel.Fuel
-import com.github.kittinunf.fuel.core.FuelError
-import com.github.kittinunf.fuel.coroutines.awaitObjectResponseResult
-import com.github.kittinunf.fuel.coroutines.awaitObjectResult
-import com.github.kittinunf.fuel.gson.gsonDeserializerOf
-import com.github.kittinunf.result.Result
-import com.preference.PowerPreference
-import java.io.BufferedReader
-import java.io.File
-import java.nio.charset.Charset
-import java.security.MessageDigest
-
-object RefreshError : Throwable()
-
-class HTTP(
-  val context: Context?,
-  val oAuth: OAuth
-) {
-
-  suspend fun refresh(): Boolean {
-    context?.let {
-      val body = mapOf(
-        "username" to PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS)
-          .getString("username"),
-        "password" to PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS)
-          .getString("password")
-      ).toList()
-
-      val result = Fuel.post(mustNormalizeUrl("/api/v1/token"), body).apply {
-        if (!Settings.isAnonymous()) {
-          authorize(it, oAuth)
-          header("Authorization", "Bearer ${oAuth.state().accessToken}")
-        }
-      }
-        .awaitObjectResult(gsonDeserializerOf(FwCredentials::class.java))
-
-      return result.fold(
-        { data ->
-          PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS)
-            .setString("access_token", data.token)
-
-          true
-        },
-        { false }
-      )
-    }
-    throw IllegalStateException("Illegal state: context is null")
-  }
-
-  suspend inline fun <reified T : Any> get(url: String): Result<T, FuelError> {
-
-    context?.let {
-      val request = Fuel.get(mustNormalizeUrl(url)).apply {
-        if (!Settings.isAnonymous()) {
-          authorize(it, oAuth)
-          header("Authorization", "Bearer ${oAuth.state().accessToken}")
-        }
-      }
-
-      val (_, response, result) = request.awaitObjectResponseResult(gsonDeserializerOf(T::class.java))
-
-      if (response.statusCode == 401) {
-        return retryGet(url)
-      } else {
-        return result
-      }
-    }
-    throw IllegalStateException("Illegal state: context is null")
-  }
-
-  suspend inline fun <reified T : Any> retryGet(
-    url: String
-  ): Result<T, FuelError> {
-    context?.let {
-      val request = Fuel.get(mustNormalizeUrl(url)).apply {
-        if (!Settings.isAnonymous()) {
-          authorize(context,oAuth)
-          header("Authorization", "Bearer ${oAuth.state().accessToken}")
-        }
-      }
-      request.awaitObjectResult(gsonDeserializerOf(T::class.java))
-    }
-    throw IllegalStateException("Illegal state: context is null")
-  }
-}
-
-object FFACache {
-  private fun key(key: String): String {
-    val md = MessageDigest.getInstance("SHA-1")
-    val digest = md.digest(key.toByteArray(Charset.defaultCharset()))
-
-    return digest.fold("", { acc, it -> acc + "%02x".format(it) })
-  }
-
-  fun set(context: Context?, key: String, value: ByteArray) = context?.let {
-    with(File(it.cacheDir, key(key))) {
-      writeBytes(value)
-    }
-  }
-
-  fun get(context: Context?, key: String): BufferedReader? = context?.let {
-    try {
-      with(File(it.cacheDir, key(key))) {
-        bufferedReader()
-      }
-    } catch (e: Exception) {
-      return null
-    }
-  }
-
-  fun delete(context: Context?, key: String) = context?.let {
-    with(File(it.cacheDir, key(key))) {
-      delete()
-    }
-  }
-}
diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt b/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt
index 5ac84d8236e85b7e3447cf5d6b0dbdbec7761c5a..ababd6e91b3cda27da5378420248023d0d80390a 100644
--- a/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/utils/Extensions.kt
@@ -22,8 +22,11 @@ import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 import net.openid.appauth.ClientSecretPost
+import java.text.SimpleDateFormat
+import java.util.*
 import kotlin.coroutines.CoroutineContext
 
+
 inline fun <D> Flow<Repository.Response<D>>.untilNetwork(
   scope: CoroutineScope,
   context: CoroutineContext = Main,
@@ -68,9 +71,8 @@ fun Request.authorize(context: Context, oAuth: OAuth): Request {
     this@authorize.apply {
       if (!Settings.isAnonymous()) {
         oAuth.state().let { state ->
-          val now = SystemClock.currentThreadTimeMillis()
           state.accessTokenExpirationTime?.let {
-            Log.i("Request.authorize()", "Accesstoken expiration: ${it - now}")
+            Log.i("Request.authorize()", "Accesstoken expiration: ${Date(it).format()}")
           }
           val old = state.accessToken
           val auth = ClientSecretPost(oAuth.state().clientSecret)
@@ -100,3 +102,9 @@ fun FuelError.formatResponseMessage(): String {
 
 fun Download.getMetadata(): DownloadInfo? =
   Gson().fromJson(String(this.request.data), DownloadInfo::class.java)
+
+val ISO_8601_DATE_TIME_FORMAT = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
+
+fun Date.format(): String {
+  return ISO_8601_DATE_TIME_FORMAT.format(this)
+}
\ No newline at end of file
diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/FFACache.kt b/app/src/main/java/audio/funkwhale/ffa/utils/FFACache.kt
new file mode 100644
index 0000000000000000000000000000000000000000..446c209269522be3c86c42e157a6590fc00bc44d
--- /dev/null
+++ b/app/src/main/java/audio/funkwhale/ffa/utils/FFACache.kt
@@ -0,0 +1,38 @@
+package audio.funkwhale.ffa.utils
+
+import android.content.Context
+import java.io.BufferedReader
+import java.io.File
+import java.nio.charset.Charset
+import java.security.MessageDigest
+
+object FFACache {
+  private fun key(key: String): String {
+    val md = MessageDigest.getInstance("SHA-1")
+    val digest = md.digest(key.toByteArray(Charset.defaultCharset()))
+
+    return digest.fold("", { acc, it -> acc + "%02x".format(it) })
+  }
+
+  fun set(context: Context?, key: String, value: ByteArray) = context?.let {
+    with(File(it.cacheDir, key(key))) {
+      writeBytes(value)
+    }
+  }
+
+  fun get(context: Context?, key: String): BufferedReader? = context?.let {
+    try {
+      with(File(it.cacheDir, key(key))) {
+        bufferedReader()
+      }
+    } catch (e: Exception) {
+      return null
+    }
+  }
+
+  fun delete(context: Context?, key: String) = context?.let {
+    with(File(it.cacheDir, key(key))) {
+      delete()
+    }
+  }
+}
\ No newline at end of file
diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt b/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt
index 6576dc377b98c59a8ae5dc7305939d67c1cdebc1..b2d6505514cefe18a0ba7da778899672b6f25676 100644
--- a/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/utils/OAuth.kt
@@ -71,6 +71,27 @@ class OAuth(private val authorizationServiceFactory: AuthorizationServiceFactory
     return false
   }
 
+  fun refreshAccessToken(context: Context): Boolean {
+    Log.i("OAuth", "refreshAccessToken()")
+    val state = tryState()
+    return if (state != null) {
+      val refreshRequest = state.createTokenRefreshRequest()
+      val auth = ClientSecretPost(state.clientSecret)
+      runBlocking {
+        service(context).performTokenRequest(refreshRequest, auth) { response, e ->
+          state.apply {
+            Log.i("OAuth", "applying new autState")
+            update(response, e)
+            save()
+          }
+        }
+      }
+      true
+    } else {
+      false
+    }
+  }
+
   private fun doTryRefreshAccessToken(
     state: AuthState,
     context: Context
diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/RefreshError.kt b/app/src/main/java/audio/funkwhale/ffa/utils/RefreshError.kt
new file mode 100644
index 0000000000000000000000000000000000000000..1f572a4139fd570c9b8cf8b7ab9f629eee113a06
--- /dev/null
+++ b/app/src/main/java/audio/funkwhale/ffa/utils/RefreshError.kt
@@ -0,0 +1,4 @@
+package audio.funkwhale.ffa.utils
+
+object RefreshError : Throwable()
+
diff --git a/app/src/main/java/audio/funkwhale/ffa/utils/Util.kt b/app/src/main/java/audio/funkwhale/ffa/utils/Util.kt
index 1a7f62afc5a5586cfaf953a9a6b6032eb49290a1..687b536137dd4806db37c254426b1a002680a5b1 100644
--- a/app/src/main/java/audio/funkwhale/ffa/utils/Util.kt
+++ b/app/src/main/java/audio/funkwhale/ffa/utils/Util.kt
@@ -66,7 +66,6 @@ fun mustNormalizeUrl(rawUrl: String): String {
   val fallbackHost =
     PowerPreference.getFileByName(AppContext.PREFS_CREDENTIALS).getString("hostname")
   val uri = URI(rawUrl).takeIf { it.host != null } ?: URI("$fallbackHost$rawUrl")
-
   return uri.toString()
 }