Skip to content

Commit 972adf4

Browse files
bskiser/fix token refresh (#1920)
* chore: add logs for refreshing token * fix: save device registration when launching chat
1 parent 9dd4f27 commit 972adf4

File tree

5 files changed

+63
-9
lines changed

5 files changed

+63
-9
lines changed

crates/chat-cli/src/auth/builder_id.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ use time::OffsetDateTime;
4545
use tracing::{
4646
debug,
4747
error,
48+
trace,
4849
warn,
4950
};
5051

@@ -123,16 +124,26 @@ impl DeviceRegistration {
123124

124125
/// Loads the OIDC registered client from the secret store, deleting it if it is expired.
125126
async fn load_from_secret_store(database: &Database, region: &Region) -> Result<Option<Self>, AuthError> {
127+
trace!(?region, "loading device registration from secret store");
126128
let device_registration = database.get_secret(Self::SECRET_KEY).await?;
127129

128130
if let Some(device_registration) = device_registration {
129131
// check that the data is not expired, assume it is invalid if not present
130132
let device_registration: Self = serde_json::from_str(&device_registration.0)?;
131133

132134
if let Some(client_secret_expires_at) = device_registration.client_secret_expires_at {
133-
if !is_expired(&client_secret_expires_at) && device_registration.region == region.as_ref() {
135+
let is_expired = is_expired(&client_secret_expires_at);
136+
let registration_region_is_valid = device_registration.region == region.as_ref();
137+
trace!(
138+
?is_expired,
139+
?registration_region_is_valid,
140+
"checking if device registration is valid"
141+
);
142+
if !is_expired && registration_region_is_valid {
134143
return Ok(Some(device_registration));
135144
}
145+
} else {
146+
warn!("no expiration time found for the client secret");
136147
}
137148
}
138149

@@ -291,19 +302,25 @@ impl BuilderIdToken {
291302
match token {
292303
Some(token) => {
293304
let region = token.region.clone().map_or(OIDC_BUILDER_ID_REGION, Region::new);
294-
295305
let client = client(region.clone());
296-
// if token is expired try to refresh
306+
297307
if token.is_expired() {
308+
trace!("token is expired, refreshing");
298309
token.refresh_token(&client, database, &region).await
299310
} else {
300311
Ok(Some(token))
301312
}
302313
},
303-
None => Ok(None),
314+
None => {
315+
debug!("secret stored in the database was empty");
316+
Ok(None)
317+
},
304318
}
305319
},
306-
Ok(None) => Ok(None),
320+
Ok(None) => {
321+
debug!("no secret found in the database");
322+
Ok(None)
323+
},
307324
Err(err) => {
308325
error!(%err, "Error getting builder id token from keychain");
309326
Err(err)?

crates/chat-cli/src/database/mod.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ use serde_json::{
2727
};
2828
use settings::Settings;
2929
use thiserror::Error;
30-
use tracing::info;
30+
use tracing::{
31+
info,
32+
trace,
33+
};
3134
use uuid::Uuid;
3235

3336
use crate::cli::ConversationState;
@@ -334,15 +337,18 @@ impl Database {
334337
}
335338

336339
pub async fn get_secret(&self, key: &str) -> Result<Option<Secret>, DatabaseError> {
340+
trace!(key, "getting secret");
337341
Ok(self.get_entry::<String>(Table::Auth, key)?.map(Into::into))
338342
}
339343

340344
pub async fn set_secret(&self, key: &str, value: &str) -> Result<(), DatabaseError> {
345+
trace!(key, "setting secret");
341346
self.set_entry(Table::Auth, key, value)?;
342347
Ok(())
343348
}
344349

345350
pub async fn delete_secret(&self, key: &str) -> Result<(), DatabaseError> {
351+
trace!(key, "deleting secret");
346352
self.delete_entry(Table::Auth, key)
347353
}
348354

crates/fig_auth/src/consts.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use aws_types::region::Region;
22

33
pub(crate) const CLIENT_NAME: &str = "Amazon Q Developer for command line";
44

5-
pub(crate) const OIDC_BUILDER_ID_REGION: Region = Region::from_static("us-east-1");
5+
pub const OIDC_BUILDER_ID_REGION: Region = Region::from_static("us-east-1");
66

77
/// The scopes requested for OIDC
88
///

crates/fig_auth/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pub mod builder_id;
2-
mod consts;
2+
pub mod consts;
33
mod error;
44
pub mod pkce;
55
mod scope;

crates/q_cli/src/cli/mod.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,13 @@ use eyre::{
4646
bail,
4747
};
4848
use feed::Feed;
49-
use fig_auth::builder_id::BuilderIdToken;
49+
use fig_auth::builder_id::{
50+
BuilderIdToken,
51+
DeviceRegistration,
52+
};
53+
use fig_auth::consts::OIDC_BUILDER_ID_REGION;
5054
use fig_auth::is_logged_in;
55+
use fig_auth::pkce::Region;
5156
use fig_auth::secret_store::SecretStore;
5257
use fig_ipc::local::open_ui_element;
5358
use fig_log::{
@@ -71,6 +76,7 @@ use tracing::{
7176
Level,
7277
debug,
7378
error,
79+
warn,
7480
};
7581

7682
use self::integrations::IntegrationsSubcommands;
@@ -380,10 +386,35 @@ impl Cli {
380386
assert_logged_in().await?;
381387
}
382388

389+
// Save credentials from the macOS keychain to sqlite.
390+
// On Linux, this essentially just rewrites to the database.
383391
let secret_store = SecretStore::new().await.ok();
384392
if let Some(secret_store) = secret_store {
385393
if let Ok(database) = database().map_err(|err| error!(?err, "failed to open database")) {
386394
if let Ok(token) = BuilderIdToken::load(&secret_store, false).await {
395+
// Save the device registration. This is required for token refresh to succeed.
396+
if let Some(token) = token.as_ref() {
397+
let region = token.region.clone().map_or(OIDC_BUILDER_ID_REGION, Region::new);
398+
match DeviceRegistration::load_from_secret_store(&secret_store, &region).await {
399+
Ok(Some(reg)) => match serde_json::to_string(&reg) {
400+
Ok(reg) => {
401+
database
402+
.set_auth_value("codewhisperer:odic:device-registration", reg)
403+
.map_err(|err| error!(?err, "failed to write device registration to auth db"))
404+
.ok();
405+
},
406+
Err(err) => error!(?err, "failed to serialize the device registration"),
407+
},
408+
Ok(None) => {
409+
warn!(?token, "no device registration found for token");
410+
},
411+
Err(err) => {
412+
error!(?err, "failed to load device registration");
413+
},
414+
}
415+
}
416+
417+
// Next, save the token.
387418
if let Ok(token) = serde_json::to_string(&token) {
388419
database
389420
.set_auth_value("codewhisperer:odic:token", token)

0 commit comments

Comments
 (0)