diff --git a/README.md b/README.md index fd42762..b2fdfc3 100644 --- a/README.md +++ b/README.md @@ -64,10 +64,14 @@ let client = TAuthClient::new( ## Start Login -Redirect the user to `client.auth_url(None)` from your web handler. +Redirect the user to `client.auth_url(None, session_id)` from your web handler. The `session_id` is a `u64` you generate (e.g. from the current time in milliseconds) — it is passed through the TAuth flow and returned in the callback so you can correlate the login with a pending session. ```rust -let login_url = client.auth_url(None); +let session_id = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis() as u64) + .unwrap_or(0); +let login_url = client.auth_url(None, session_id); ``` The URL includes: @@ -75,6 +79,7 @@ The URL includes: - `identifier`: your app identifier - `redirect`: your callback URL - `public_key`: your app MTP public key bundle +- `sessionId`: the session ID you generated, passed through to the callback - `challenge`: optional caller-supplied challenge ## Handle Callback diff --git a/example/backend/src/main.rs b/example/backend/src/main.rs index df46454..44ac4be 100644 --- a/example/backend/src/main.rs +++ b/example/backend/src/main.rs @@ -103,7 +103,11 @@ impl AppState { } async fn login(State(state): State) -> Redirect { - Redirect::temporary(&state.tauth.auth_url(None)) + let session_id = std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .map(|d| d.as_millis() as u64) + .unwrap_or(0); + Redirect::temporary(&state.tauth.auth_url(None, session_id)) } async fn callback(State(state): State, uri: axum::http::Uri) -> Result { diff --git a/src/lib.rs b/src/lib.rs index 4514353..63fe2fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -231,17 +231,18 @@ impl TAuthClient { } } - pub fn generate_link(&self, challenge: Option<&str>) -> String { - self.auth_url(challenge) + pub fn generate_link(&self, challenge: Option<&str>, session_id: u64) -> String { + self.auth_url(challenge, session_id) } - pub fn auth_url(&self, challenge: Option<&str>) -> String { + pub fn auth_url(&self, challenge: Option<&str>, session_id: u64) -> String { let mut link = self.frontend_url.clone(); { let mut pairs = link.query_pairs_mut(); pairs.append_pair("identifier", &self.identifier); pairs.append_pair("redirect", self.redirect_url.as_str()); pairs.append_pair("public_key", &self.public_key()); + pairs.append_pair("sessionId", &session_id.to_string()); if let Some(challenge) = challenge { pairs.append_pair("challenge", challenge); } @@ -500,7 +501,7 @@ mod tests { ) .unwrap(); - let link = Url::parse(&client.generate_link(Some("abc123"))).unwrap(); + let link = Url::parse(&client.generate_link(Some("abc123"), 42)).unwrap(); assert_eq!( link.query_pairs() .find(|(key, _)| key == "identifier") @@ -515,6 +516,13 @@ mod tests { .1, "abc123" ); + assert_eq!( + link.query_pairs() + .find(|(key, _)| key == "sessionId") + .unwrap() + .1, + "42" + ); assert!( link.query_pairs() .any(|(key, value)| key == "public_key" && !value.is_empty())