diff --git a/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt b/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt
index 9205a0e5203c2ed7c4308855c4250e9fdca8cce2..17621db95c5a5dd532e2d6049b3d86e97c4ab279 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationBanner.kt
@@ -1,3 +1,21 @@
+/*
+ * Briar Desktop
+ * Copyright (C) 2021-2022 The Briar Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
 package org.briarproject.briar.desktop.expiration
 
 import androidx.compose.foundation.layout.Arrangement
@@ -5,6 +23,7 @@ import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
 import androidx.compose.material.Icon
 import androidx.compose.material.MaterialTheme
 import androidx.compose.material.Surface
@@ -20,14 +39,10 @@ import androidx.compose.runtime.setValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import org.briarproject.briar.desktop.expiration.ExpirationUtils.getDaysLeft
-import org.briarproject.briar.desktop.expiration.ExpirationUtils.isExpired
+import org.briarproject.briar.desktop.expiration.ExpirationUtils.periodicallyCheckIfExpired
 import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
 import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18nP
 import org.briarproject.briar.desktop.utils.PreviewUtils.preview
-import kotlin.time.Duration.Companion.hours
 
 fun main() = preview {
     Column {
@@ -39,20 +54,15 @@ fun main() = preview {
 fun ExpirationBanner(onExpired: () -> Unit) {
 
     var daysLeft by remember { mutableStateOf(0) }
+    var expired by remember { mutableStateOf(false) }
     LaunchedEffect(Unit) {
-        launch {
-            while (true) {
-                daysLeft = getDaysLeft()
-                if (isExpired()) {
-                    onExpired()
-                    break
-                }
-                delay(1.hours.inWholeMilliseconds)
-            }
-        }
+        periodicallyCheckIfExpired(
+            reportDaysLeft = { daysLeft = it },
+            onExpired = { expired = true; onExpired() },
+        )
     }
 
-    ExpirationBanner(daysLeft)
+    if (!expired) ExpirationBanner(daysLeft)
 }
 
 @Composable
@@ -63,11 +73,14 @@ fun ExpirationBanner(
     modifier = Modifier.fillMaxWidth()
 ) {
     Row(
-        horizontalArrangement = Arrangement.spacedBy(8.dp),
+        horizontalArrangement = Arrangement.spacedBy(24.dp),
         verticalAlignment = Alignment.CenterVertically,
-        modifier = Modifier.padding(8.dp)
+        modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
     ) {
-        Icon(Icons.Filled.Warning, i18n("warning"))
-        Text(i18nP("expiration.banner", daysLeft))
+        Icon(Icons.Filled.Warning, i18n("warning"), Modifier.size(40.dp))
+        Text(
+            text = "${i18nP("expiration.banner.part1", daysLeft)} ${i18n("expiration.banner.part2")}",
+            style = MaterialTheme.typography.body2
+        )
     }
 }
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationUtils.kt b/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationUtils.kt
index 7a51a741e5a4f25c7bf859379cd40c803b0e0be0..d9716edd921d51dcfb78bbf386f16f2490d77ce0 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationUtils.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/expiration/ExpirationUtils.kt
@@ -1,12 +1,55 @@
+/*
+ * Briar Desktop
+ * Copyright (C) 2021-2022 The Briar Project
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
 package org.briarproject.briar.desktop.expiration
 
+import kotlinx.coroutines.delay
 import org.briarproject.briar.desktop.BuildData
 import java.time.Instant
-import java.time.temporal.ChronoUnit
+import kotlin.time.Duration.Companion.days
+import kotlin.time.Duration.Companion.hours
+import kotlin.time.Duration.Companion.milliseconds
 
 object ExpirationUtils {
 
-    fun getDaysLeft() = 90 - ChronoUnit.DAYS.between(Instant.ofEpochMilli(BuildData.GIT_TIME), Instant.now()).toInt()
+    private val EXPIRE_AFTER = BuildData.GIT_TIME + 91.days.inWholeMilliseconds
+    private val CHECK_INTERVAL = 1.hours.inWholeMilliseconds
+
+    // for testing uncomment the following instead
+    // private val EXPIRE_AFTER = Instant.now().toEpochMilli() + 10.seconds.inWholeMilliseconds
+    // private val CHECK_INTERVAL = 1.seconds.inWholeMilliseconds
+
+    private fun getMillisLeft() = (EXPIRE_AFTER - Instant.now().toEpochMilli()).milliseconds
+
+    private fun getDaysLeft() = getMillisLeft().inWholeDays.toInt()
+
+    private fun isExpired() = getMillisLeft() <= 0.milliseconds
 
-    fun isExpired() = getDaysLeft() <= 0
+    suspend fun periodicallyCheckIfExpired(
+        reportDaysLeft: (Int) -> Unit,
+        onExpired: () -> Unit,
+    ) {
+        while (true) {
+            if (isExpired()) {
+                onExpired()
+                break
+            } else reportDaysLeft(getDaysLeft())
+            delay(CHECK_INTERVAL)
+        }
+    }
 }
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt
index 871f581bf6a815b40e2591479fd34cb491b42785..bad371c4c82ef021de02b3bad852bba4d8b0c92e 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorScreen.kt
@@ -56,12 +56,9 @@ import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
 import org.briarproject.briar.desktop.utils.PreviewUtils.preview
 
 fun main() = preview {
-    var error: ErrorSubViewModel.Error by remember { mutableStateOf(ErrorSubViewModel.ExpirationError) }
+    var error: ErrorSubViewModel.Error by remember { mutableStateOf(RegistrationSubViewModel.RegistrationError) }
 
     Row(horizontalArrangement = spacedBy(8.dp)) {
-        Button(onClick = { error = ErrorSubViewModel.ExpirationError }) {
-            Text("Expiration")
-        }
         Button(onClick = { error = RegistrationSubViewModel.RegistrationError }) {
             Text("Registration")
         }
@@ -82,10 +79,34 @@ fun ErrorScreen(viewHolder: ErrorSubViewModel) =
 @Composable
 fun ErrorScreen(
     error: ErrorSubViewModel.Error,
-    onBackButton: () -> Unit,
+    onBackButton: (() -> Unit)?,
+) {
+    val text = when (error) {
+        is RegistrationSubViewModel.RegistrationError -> i18n("startup.failed.registration")
+        is StartupViewModel.StartingError -> {
+            when (error.error) {
+                CLOCK_ERROR -> i18n("startup.failed.clock_error")
+                DB_ERROR -> i18n("startup.failed.db_error")
+                DATA_TOO_OLD_ERROR -> i18n("startup.failed.data_too_old_error")
+                DATA_TOO_NEW_ERROR -> i18n("startup.failed.data_too_new_error")
+                SERVICE_ERROR -> i18n("startup.failed.service_error")
+                else -> ""
+            }
+        }
+    }
+
+    ErrorScreen(text, onBackButton)
+}
+
+@Composable
+fun ErrorScreen(
+    text: String,
+    onBackButton: (() -> Unit)? = null,
 ) = Surface {
-    IconButton(onClick = onBackButton) {
-        Icon(Icons.Filled.ArrowBack, i18n("back"))
+    if (onBackButton != null) {
+        IconButton(onClick = onBackButton) {
+            Icon(Icons.Filled.ArrowBack, i18n("back"))
+        }
     }
 
     Column(
@@ -101,21 +122,6 @@ fun ErrorScreen(
         )
 
         Text(i18n("sorry"), style = MaterialTheme.typography.h5)
-
-        val text = when (error) {
-            is ErrorSubViewModel.ExpirationError -> i18n("startup.failed.expired")
-            is RegistrationSubViewModel.RegistrationError -> i18n("startup.failed.registration")
-            is StartupViewModel.StartingError -> {
-                when (error.error) {
-                    CLOCK_ERROR -> i18n("startup.failed.clock_error")
-                    DB_ERROR -> i18n("startup.failed.db_error")
-                    DATA_TOO_OLD_ERROR -> i18n("startup.failed.data_too_old_error")
-                    DATA_TOO_NEW_ERROR -> i18n("startup.failed.data_too_new_error")
-                    SERVICE_ERROR -> i18n("startup.failed.service_error")
-                    else -> ""
-                }
-            }
-        }
         Text(
             text = text,
             style = MaterialTheme.typography.body1,
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorSubViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorSubViewModel.kt
index e4129ebdea14789586c081e07e4fec3d08f55f96..07a2acc9d3554c851d243f817a2ed7df2376a70a 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorSubViewModel.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/login/ErrorSubViewModel.kt
@@ -21,9 +21,7 @@ package org.briarproject.briar.desktop.login
 class ErrorSubViewModel(
     private val viewModel: StartupViewModel,
     val error: Error,
-    val onBackButton: () -> Unit,
+    val onBackButton: (() -> Unit)?,
 ) : StartupViewModel.SubViewModel {
     sealed interface Error
-
-    object ExpirationError : Error
 }
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt b/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt
index 8cd391466f051952da30243631ce36fcfc5cd03a..247d7451dac89e1e88848651d2d8932e8d261266 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/login/StartupViewModel.kt
@@ -30,7 +30,6 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager
 import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING
 import org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.SUCCESS
 import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent
-import org.briarproject.briar.desktop.expiration.ExpirationUtils.isExpired
 import org.briarproject.briar.desktop.threading.BriarExecutors
 import org.briarproject.briar.desktop.viewmodel.EventListenerDbViewModel
 import org.briarproject.briar.desktop.viewmodel.asState
@@ -62,8 +61,7 @@ constructor(
     val currentSubViewModel = _currentSubViewModel.asState()
 
     private fun decideSubViewModel(): SubViewModel =
-        if (isExpired()) makeError(ErrorSubViewModel.ExpirationError)
-        else if (accountManager.accountExists()) makeLogin()
+        if (accountManager.accountExists()) makeLogin()
         else makeRegistration()
 
     private fun makeLogin() = LoginSubViewModel(
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt b/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt
index 1cc47ade5aab8a7fa3fc1861a967492ce303a1d7..1f2f74cfefaf0358b416333fb040bdb64a2c6a66 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/theme/Theme.kt
@@ -48,11 +48,12 @@ val DarkColors = darkColors(
     secondary = Lime500,
     background = materialDarkBg,
     surface = materialDarkBg,
+    error = briarError,
     onPrimary = Color.White,
     onSecondary = Color.White,
     onBackground = Color.White,
     onSurface = Color.White,
-    error = briarError
+    onError = Color.White,
 )
 val LightColors = lightColors(
     primary = Blue500,
@@ -60,11 +61,12 @@ val LightColors = lightColors(
     secondary = Lime300,
     background = Color.White,
     surface = Color.White,
+    error = briarError,
     onPrimary = Color.White,
     onSecondary = Color.Black,
     onBackground = Color.Black,
     onSurface = Color.Black,
-    error = briarError
+    onError = Color.White,
 )
 
 @Composable
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt b/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt
index ffafaaf8c251f591343708a2121eb0242fef12df..cbd5c1f1af90b17c83e475088f47db2c20798b4b 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/ui/BriarUi.kt
@@ -39,9 +39,11 @@ import org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RU
 import org.briarproject.bramble.api.lifecycle.event.LifecycleEvent
 import org.briarproject.briar.desktop.DesktopFeatureFlags
 import org.briarproject.briar.desktop.expiration.ExpirationBanner
+import org.briarproject.briar.desktop.login.ErrorScreen
 import org.briarproject.briar.desktop.login.StartupScreen
 import org.briarproject.briar.desktop.settings.SettingsViewModel
 import org.briarproject.briar.desktop.theme.BriarTheme
+import org.briarproject.briar.desktop.ui.Screen.EXPIRED
 import org.briarproject.briar.desktop.ui.Screen.MAIN
 import org.briarproject.briar.desktop.ui.Screen.STARTUP
 import org.briarproject.briar.desktop.utils.InternationalizationUtils.i18n
@@ -54,7 +56,8 @@ import javax.inject.Singleton
 
 enum class Screen {
     STARTUP,
-    MAIN
+    MAIN,
+    EXPIRED,
 }
 
 interface BriarUi {
@@ -119,10 +122,11 @@ constructor(
                 val settingsViewModel: SettingsViewModel = viewModel()
                 BriarTheme(isDarkTheme = settingsViewModel.isDarkMode.value) {
                     Column(Modifier.fillMaxSize()) {
-                        ExpirationBanner(onExpired = { screenState = STARTUP })
+                        ExpirationBanner { screenState = EXPIRED; stop() }
                         when (screenState) {
                             STARTUP -> StartupScreen()
                             MAIN -> MainScreen(settingsViewModel)
+                            EXPIRED -> ErrorScreen(i18n("startup.failed.expired"))
                         }
                     }
                 }
diff --git a/src/main/kotlin/org/briarproject/briar/desktop/ui/Constants.kt b/src/main/kotlin/org/briarproject/briar/desktop/ui/Constants.kt
index 67c1b749c3eeeb832aa123b7a3c5ee6ae4631883..d860f80b8f4cdfe80313b67ff66793ca3c6bb38e 100644
--- a/src/main/kotlin/org/briarproject/briar/desktop/ui/Constants.kt
+++ b/src/main/kotlin/org/briarproject/briar/desktop/ui/Constants.kt
@@ -21,7 +21,6 @@ package org.briarproject.briar.desktop.ui
 import androidx.compose.ui.unit.dp
 
 object Constants {
-    val BANNER_HEIGHT = 24.dp
     val HEADER_SIZE = 56.dp
     val COLUMN_WIDTH = 275.dp
     val STARTUP_FIELDS_WIDTH = 400.dp
diff --git a/src/main/resources/strings/BriarDesktop.properties b/src/main/resources/strings/BriarDesktop.properties
index d5ae8d74ef2f875b0eeee2dfa55de3901bc7a1a7..5c4135d1272fae16cdac0940002978367af8f50e 100644
--- a/src/main/resources/strings/BriarDesktop.properties
+++ b/src/main/resources/strings/BriarDesktop.properties
@@ -154,7 +154,8 @@ startup.database.creating=Creating Account...
 startup.database.opening=Decrypting Database...
 startup.database.migrating=Upgrading Database...
 startup.database.compacting=Compacting Database...
-expiration.banner={0, plural, one {This is a test version of Briar that will expire in {0} day. Please update to a newer version in time.} other {This is a test version of Briar that will expire in {0} days. Please update to a newer version in time.}}
+expiration.banner.part1={0, plural, =0 {This is a test version of Briar that will expire today.} one {This is a test version of Briar that will expire tomorrow.} other {This is a test version of Briar that will expire in {0} days.}}
+expiration.banner.part2=Please update to a newer version in time.
 
 # Settings
 settings.title=Settings