diff --git a/src/api/identity.rs b/src/api/identity.rs index 92b6c1e4..6c9008d8 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -433,7 +433,7 @@ async fn _password_login( let twofactor_token = twofactor_auth(&mut user, &data, &mut device, ip, client_version, conn).await?; - let auth_tokens = auth::AuthTokens::new(&device, &user, AuthMethod::Password, data.client_id); + let auth_tokens = auth::AuthTokens::new(&device, &user, AuthMethod::Password, data.client_id, None); authenticated_response(&user, &mut device, auth_tokens, twofactor_token, &now, conn, ip).await } diff --git a/src/auth.rs b/src/auth.rs index e10de615..20191c91 100644 --- a/src/auth.rs +++ b/src/auth.rs @@ -1129,13 +1129,13 @@ impl AuthMethod { } } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub enum TokenWrapper { Access(String), Refresh(String), } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct RefreshJwtClaims { // Not before pub nbf: i64, @@ -1175,7 +1175,7 @@ impl AuthTokens { } // Create refresh_token and access_token with default validity - pub fn new(device: &Device, user: &User, sub: AuthMethod, client_id: Option) -> Self { + pub fn new(device: &Device, user: &User, sub: AuthMethod, client_id: Option, existing_refresh_claims: Option<&RefreshJwtClaims>) -> Self { let time_now = Utc::now(); let access_claims = LoginJwtClaims::default(device, user, &sub, client_id); @@ -1186,7 +1186,7 @@ impl AuthTokens { *DEFAULT_REFRESH_VALIDITY }; - let refresh_claims = RefreshJwtClaims { + let default_refresh_claims = RefreshJwtClaims { nbf: time_now.timestamp(), exp: (time_now + validity).timestamp(), iss: JWT_LOGIN_ISSUER.to_string(), @@ -1195,6 +1195,13 @@ impl AuthTokens { token: None, }; + let refresh_claims = if CONFIG.disable_refresh_token_renewal() { + // Use existing_refresh_claims if passed and config is enabled + existing_refresh_claims.cloned().unwrap_or(default_refresh_claims) + } else { + default_refresh_claims + }; + Self { refresh_claims, access_claims, @@ -1232,14 +1239,14 @@ pub async fn refresh_tokens( let auth_tokens = match refresh_claims.sub { AuthMethod::Sso if CONFIG.sso_enabled() && CONFIG.sso_auth_only_not_session() => { - AuthTokens::new(&device, &user, refresh_claims.sub, client_id) + AuthTokens::new(&device, &user, refresh_claims.sub.clone(), client_id, Some(&refresh_claims)) } AuthMethod::Sso if CONFIG.sso_enabled() => { sso::exchange_refresh_token(&device, &user, client_id, refresh_claims).await? } AuthMethod::Sso => err!("SSO is now disabled, Login again using email and master password"), AuthMethod::Password if CONFIG.sso_enabled() && CONFIG.sso_only() => err!("SSO is now required, Login again"), - AuthMethod::Password => AuthTokens::new(&device, &user, refresh_claims.sub, client_id), + AuthMethod::Password => AuthTokens::new(&device, &user, refresh_claims.sub.clone(), client_id, Some(&refresh_claims)), _ => err!("Invalid auth method, cannot refresh token"), }; diff --git a/src/config.rs b/src/config.rs index 1b6d3183..27f3faf9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -706,6 +706,10 @@ make_config! { /// Note that the checkbox would still be present, but ignored. disable_2fa_remember: bool, true, def, false; + /// Disable refresh token renewal |> If true, disables sliding window for refresh token expiry. + /// This only renews the token on a full login (Password (+2FA), SSO, etc.) forcing a full reauth every 30 days (90 for the native app) + disable_refresh_token_renewal: bool, true, def, false; + /// Disable authenticator time drifted codes to be valid |> Enabling this only allows the current TOTP code to be valid /// TOTP codes of the previous and next 30 seconds will be invalid. authenticator_disable_time_drift: bool, true, def, false; diff --git a/src/sso.rs b/src/sso.rs index 789f0a3b..552ec6d6 100644 --- a/src/sso.rs +++ b/src/sso.rs @@ -377,7 +377,7 @@ pub fn create_auth_tokens( _create_auth_tokens(device, refresh_token, access_claims, access_token) } else { - Ok(AuthTokens::new(device, user, AuthMethod::Sso, client_id)) + Ok(AuthTokens::new(device, user, AuthMethod::Sso, client_id, None)) } }