diff --git a/services/tunnelbroker/src/constants.rs b/services/tunnelbroker/src/constants.rs
--- a/services/tunnelbroker/src/constants.rs
+++ b/services/tunnelbroker/src/constants.rs
@@ -15,6 +15,7 @@
 pub const ENV_FCM_CONFIG: &str = "FCM_CONFIG";
 pub const LOG_LEVEL_ENV_VAR: &str =
   tracing_subscriber::filter::EnvFilter::DEFAULT_ENV;
+pub const FCM_ACCESS_TOKEN_GENERATION_THRESHOLD: u64 = 5 * 60;
 
 pub mod dynamodb {
   // This table holds messages which could not be immediately delivered to
diff --git a/services/tunnelbroker/src/notifs/fcm/token.rs b/services/tunnelbroker/src/notifs/fcm/token.rs
--- a/services/tunnelbroker/src/notifs/fcm/token.rs
+++ b/services/tunnelbroker/src/notifs/fcm/token.rs
@@ -1,3 +1,4 @@
+use crate::constants::FCM_ACCESS_TOKEN_GENERATION_THRESHOLD;
 use crate::notifs::fcm::config::FCMConfig;
 use crate::notifs::fcm::error::Error;
 use crate::notifs::fcm::error::Error::FCMTokenNotInitialized;
@@ -40,6 +41,10 @@
   }
 
   pub async fn get_auth_bearer(&self) -> Result<String, Error> {
+    if self.fcm_token_needs_generation().await {
+      self.generate_fcm_token().await?;
+    }
+
     let bearer = self.token.read().await;
     match &*bearer {
       Some(token) => Ok(format!("{} {}", token.token_type, token.access_token)),
@@ -89,4 +94,39 @@
     let access_token = response.json::<FCMAccessTokenResponse>().await?;
     Ok(access_token)
   }
+
+  async fn fcm_token_needs_generation(&self) -> bool {
+    let token = self.token.read().await;
+    match &*token {
+      None => true,
+      Some(token) => {
+        get_time() - FCM_ACCESS_TOKEN_GENERATION_THRESHOLD
+          >= token.expiration_time
+      }
+    }
+  }
+  async fn generate_fcm_token(&self) -> Result<(), Error> {
+    debug!("Generating FCM access token");
+    let mut token = self.token.write().await;
+
+    let created_at = get_time();
+    let new_jwt_token = self.get_jwt_token(created_at)?;
+    let access_token_response =
+      self.get_fcm_access_token(new_jwt_token).await?;
+
+    *token = Some(FCMAccessToken {
+      access_token: access_token_response.access_token,
+      token_type: access_token_response.token_type,
+      expiration_time: created_at + access_token_response.expires_in,
+    });
+
+    Ok(())
+  }
+}
+
+fn get_time() -> u64 {
+  SystemTime::now()
+    .duration_since(UNIX_EPOCH)
+    .unwrap()
+    .as_secs()
 }