diff --git a/.env.template b/.env.template
index 66a04343cb9ccba7214a7723bc1f8ff85dd8b500..60b5b73bbf3840016f451029fa443795c9e6a18c 100644
--- a/.env.template
+++ b/.env.template
@@ -245,6 +245,10 @@
 ## Name shown in the invitation emails that don't come from a specific organization
 # INVITATION_ORG_NAME=Vaultwarden
 
+## The number of hours after which an organization invite token, emergency access invite token,
+## email verification token and deletion request token will expire (must be at least 1)
+# INVITATION_EXPIRATION_HOURS=120
+
 ## Per-organization attachment storage limit (KB)
 ## Max kilobytes of attachment storage allowed per organization.
 ## When this limit is reached, organization members will not be allowed to upload further attachments for ciphers owned by that organization.
diff --git a/src/auth.rs b/src/auth.rs
index f99fbd3990439eace49fe1769a7d89e46db9bc6d..92445f525c495c382aa968b7f9926824ec8e3102 100644
--- a/src/auth.rs
+++ b/src/auth.rs
@@ -148,9 +148,10 @@ pub fn generate_invite_claims(
     invited_by_email: Option<String>,
 ) -> InviteJwtClaims {
     let time_now = Utc::now().naive_utc();
+    let expire_hours = i64::from(CONFIG.invitation_expiration_hours());
     InviteJwtClaims {
         nbf: time_now.timestamp(),
-        exp: (time_now + Duration::days(5)).timestamp(),
+        exp: (time_now + Duration::hours(expire_hours)).timestamp(),
         iss: JWT_INVITE_ISSUER.to_string(),
         sub: uuid,
         email,
@@ -185,9 +186,10 @@ pub fn generate_emergency_access_invite_claims(
     grantor_email: Option<String>,
 ) -> EmergencyAccessInviteJwtClaims {
     let time_now = Utc::now().naive_utc();
+    let expire_hours = i64::from(CONFIG.invitation_expiration_hours());
     EmergencyAccessInviteJwtClaims {
         nbf: time_now.timestamp(),
-        exp: (time_now + Duration::days(5)).timestamp(),
+        exp: (time_now + Duration::hours(expire_hours)).timestamp(),
         iss: JWT_EMERGENCY_ACCESS_INVITE_ISSUER.to_string(),
         sub: uuid,
         email,
@@ -211,9 +213,10 @@ pub struct BasicJwtClaims {
 
 pub fn generate_delete_claims(uuid: String) -> BasicJwtClaims {
     let time_now = Utc::now().naive_utc();
+    let expire_hours = i64::from(CONFIG.invitation_expiration_hours());
     BasicJwtClaims {
         nbf: time_now.timestamp(),
-        exp: (time_now + Duration::days(5)).timestamp(),
+        exp: (time_now + Duration::hours(expire_hours)).timestamp(),
         iss: JWT_DELETE_ISSUER.to_string(),
         sub: uuid,
     }
@@ -221,9 +224,10 @@ pub fn generate_delete_claims(uuid: String) -> BasicJwtClaims {
 
 pub fn generate_verify_email_claims(uuid: String) -> BasicJwtClaims {
     let time_now = Utc::now().naive_utc();
+    let expire_hours = i64::from(CONFIG.invitation_expiration_hours());
     BasicJwtClaims {
         nbf: time_now.timestamp(),
-        exp: (time_now + Duration::days(5)).timestamp(),
+        exp: (time_now + Duration::hours(expire_hours)).timestamp(),
         iss: JWT_VERIFYEMAIL_ISSUER.to_string(),
         sub: uuid,
     }
diff --git a/src/config.rs b/src/config.rs
index b8f3246ba31f15fcad02b07887b1a006cad4bb72..3a2cf958b0bc2b8f643087ac4d7e80b52fb1dad2 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -430,6 +430,9 @@ make_config! {
         org_creation_users:     String, true,   def,    "".to_string();
         /// Allow invitations |> Controls whether users can be invited by organization admins, even when signups are otherwise disabled
         invitations_allowed:    bool,   true,   def,    true;
+        /// Invitation token expiration time (in hours) |> The number of hours after which an organization invite token, emergency access invite token,
+        /// email verification token and deletion request token will expire (must be at least 1)
+        invitation_expiration_hours: u32, false, def, 120;
         /// Allow emergency access |> Controls whether users can enable emergency access to their accounts. This setting applies globally to all users.
         emergency_access_allowed:    bool,   true,   def,    true;
         /// Password iterations |> Number of server-side passwords hashing iterations.
@@ -726,6 +729,10 @@ fn validate_config(cfg: &ConfigItems) -> Result<(), Error> {
         _ => err!("Only HTTP 301/302 and 307/308 redirects are supported"),
     }
 
+    if cfg.invitation_expiration_hours < 1 {
+        err!("`INVITATION_EXPIRATION_HOURS` has a minimum duration of 1 hour")
+    }
+
     Ok(())
 }