Skip to content

Commit 5bc0990

Browse files
[dtokenz] Add timeout to interactive auth (#4)
Originally, the "interactive" flag was only intended for foregrounded processes, so timing out the interactive authentication was intended to be done from the calling application. This isn't always desired, and if a user closes the opened tab on a background process, the background process will just hang forever, both holding the port open, and also not making any progress. This just adds a configurable timeout with a default of two minutes, after which the process will return an error and the server will shutdown
1 parent 07c681c commit 5bc0990

File tree

4 files changed

+33
-4
lines changed

4 files changed

+33
-4
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "dtokenz"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
edition = "2024"
55

66
license = "MIT"

src/authorized_user.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use base64::Engine;
1818
use futures::future::BoxFuture;
1919
use futures::{FutureExt, TryFutureExt};
2020
use google_cloud_auth::credentials::Credentials;
21-
use itertools::Itertools;
21+
use itertools::{Either, Itertools};
2222
use rand::Rng;
2323
use sha2::Digest;
2424
use std::fmt::{Debug, Formatter};
@@ -469,7 +469,31 @@ impl AuthorizedUser {
469469
}
470470

471471
// Wait for the auth code
472-
let auth_code = rx.await.context("Failed to receive auth code")??;
472+
let timeout_handle = tokio::time::sleep(config.interactive_auth_timeout);
473+
474+
let callback_result = tokio::select! {
475+
_ = timeout_handle => {
476+
Either::Left(config.interactive_auth_timeout)
477+
},
478+
res = rx => {
479+
Either::Right(res)
480+
}
481+
};
482+
let auth_code = match callback_result {
483+
Either::Right(res) => res.context("Failed to receive auth code")??,
484+
Either::Left(timeout) => {
485+
// Shutdown of the webserver is handled by the scopeguard above.
486+
write_message_to_user(&format!(
487+
"Authentication operation timed out after {} seconds",
488+
timeout.as_secs()
489+
));
490+
491+
return Err(anyhow::anyhow!(
492+
"Authentication timed out after {} seconds",
493+
timeout.as_secs()
494+
));
495+
}
496+
};
473497

474498
// Exchange the code for a token
475499
let client = reqwest::Client::new();

src/config.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ pub struct DtokenzConfig {
1919
///
2020
/// Defaults to [`crate::authorized_user::default_oauth_callback_handler`]
2121
pub oauth_callback_handler: OAuthCallback,
22+
/// How long to wait for a user to complete the interactive authentication flow before aborting.
23+
///
24+
/// Defaults to 2 minutes.
25+
pub interactive_auth_timeout: std::time::Duration,
2226
}
2327

2428
impl Default for DtokenzConfig {
@@ -27,6 +31,7 @@ impl Default for DtokenzConfig {
2731
interactive: true,
2832
interactive_auth_message: None,
2933
oauth_callback_handler: crate::authorized_user::default_oauth_callback_handler.into(),
34+
interactive_auth_timeout: std::time::Duration::from_mins(2),
3035
}
3136
}
3237
}

0 commit comments

Comments
 (0)