mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
refactor: make auth loading async (#19762)
## Summary Auth loading used to expose synchronous construction helpers in several places even though some auth sources now need async work. This PR makes the auth-loading surface async and updates the callers to await it. This is intentionally only plumbing. It does not change how AgentIdentity tokens are decoded, how task runtime ids are allocated, or how JWT signatures are verified. ## Stack 1. **This PR:** [refactor: make auth loading async](https://github.com/openai/codex/pull/19762) 2. [refactor: load AgentIdentity runtime eagerly](https://github.com/openai/codex/pull/19763) 3. [feat: verify AgentIdentity JWTs with JWKS](https://github.com/openai/codex/pull/19764) ## Important call sites | Area | Change | | --- | --- | | `codex-login` auth loading | `CodexAuth` and `AuthManager` construction paths now await auth loading. | | app-server startup | Auth manager construction is awaited during initialization. | | CLI/TUI/exec/MCP/chatgpt callers | Existing auth-loading calls now await the same behavior. | | cloud requirements storage loader | The loader becomes async so it can share the same auth construction path. | | auth tests | Tests that load auth now run in async contexts. | ## Testing Tests: targeted Rust auth test compilation, formatter, scoped Clippy fix, and Bazel lock check.
This commit is contained in:
1 parent
4ed22fc7d2
commit
2009f6e894
25 files changed
+291
-203
No files matched your search
@@ -46,7 +46,7 @@ async fn refresh_token_succeeds_updates_storage() -> Result<()> {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -56,7 +56,7 @@ async fn refresh_token_succeeds_updates_storage() -> Result<()> {
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
ctx.auth_manager
|
||||
.refresh_token_from_authority()
|
||||
@@ -110,7 +110,7 @@ async fn refresh_token_refreshes_when_auth_is_unchanged() -> Result<()> {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -120,7 +120,7 @@ async fn refresh_token_refreshes_when_auth_is_unchanged() -> Result<()> {
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
ctx.auth_manager
|
||||
.refresh_token()
|
||||
@@ -164,7 +164,7 @@ async fn refresh_token_skips_refresh_when_auth_changed() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = MockServer::start().await;
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
@@ -175,7 +175,7 @@ async fn refresh_token_skips_refresh_when_auth_changed() -> Result<()> {
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let disk_tokens = build_tokens("disk-access-token", "disk-refresh-token");
|
||||
let disk_auth = AuthDotJson {
|
||||
@@ -230,7 +230,7 @@ async fn refresh_token_errors_on_account_mismatch() -> Result<()> {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -240,7 +240,7 @@ async fn refresh_token_errors_on_account_mismatch() -> Result<()> {
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let mut disk_tokens = build_tokens("disk-access-token", "disk-refresh-token");
|
||||
disk_tokens.account_id = Some("other-account".to_string());
|
||||
@@ -299,7 +299,7 @@ async fn returns_fresh_tokens_as_is() -> Result<()> {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let stale_refresh = Utc::now() - Duration::days(9);
|
||||
let fresh_access_token = access_token_with_expiration(Utc::now() + Duration::hours(1));
|
||||
let initial_tokens = build_tokens(&fresh_access_token, INITIAL_REFRESH_TOKEN);
|
||||
@@ -310,7 +310,7 @@ async fn returns_fresh_tokens_as_is() -> Result<()> {
|
||||
last_refresh: Some(stale_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let cached_auth = ctx
|
||||
.auth_manager
|
||||
@@ -347,7 +347,7 @@ async fn refreshes_token_when_access_token_is_expired() -> Result<()> {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let fresh_refresh = Utc::now() - Duration::days(1);
|
||||
let expired_access_token = access_token_with_expiration(Utc::now() - Duration::hours(1));
|
||||
let initial_tokens = build_tokens(&expired_access_token, INITIAL_REFRESH_TOKEN);
|
||||
@@ -358,7 +358,7 @@ async fn refreshes_token_when_access_token_is_expired() -> Result<()> {
|
||||
last_refresh: Some(fresh_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let cached_auth = ctx
|
||||
.auth_manager
|
||||
@@ -398,7 +398,7 @@ async fn auth_reloads_disk_auth_when_cached_auth_is_stale() -> Result<()> {
|
||||
|
||||
let server = MockServer::start().await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let stale_refresh = Utc::now() - Duration::days(9);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -408,7 +408,7 @@ async fn auth_reloads_disk_auth_when_cached_auth_is_stale() -> Result<()> {
|
||||
last_refresh: Some(stale_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let fresh_refresh = Utc::now() - Duration::days(1);
|
||||
let disk_tokens = build_tokens("disk-access-token", "disk-refresh-token");
|
||||
@@ -461,7 +461,7 @@ async fn auth_reloads_disk_auth_without_calling_expired_refresh_token() -> Resul
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let stale_refresh = Utc::now() - Duration::days(9);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -471,7 +471,7 @@ async fn auth_reloads_disk_auth_without_calling_expired_refresh_token() -> Resul
|
||||
last_refresh: Some(stale_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let fresh_refresh = Utc::now() - Duration::days(1);
|
||||
let disk_tokens = build_tokens("disk-access-token", "disk-refresh-token");
|
||||
@@ -522,7 +522,7 @@ async fn refresh_token_returns_permanent_error_for_expired_refresh_token() -> Re
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -532,7 +532,7 @@ async fn refresh_token_returns_permanent_error_for_expired_refresh_token() -> Re
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let err = ctx
|
||||
.auth_manager
|
||||
@@ -575,7 +575,7 @@ async fn refresh_token_does_not_retry_after_permanent_failure() -> Result<()> {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -585,7 +585,7 @@ async fn refresh_token_does_not_retry_after_permanent_failure() -> Result<()> {
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let first_err = ctx
|
||||
.auth_manager
|
||||
@@ -642,7 +642,7 @@ async fn refresh_token_reloads_changed_auth_after_permanent_failure() -> Result<
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -652,7 +652,7 @@ async fn refresh_token_reloads_changed_auth_after_permanent_failure() -> Result<
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let first_err = ctx
|
||||
.auth_manager
|
||||
@@ -723,7 +723,7 @@ async fn refresh_token_returns_transient_error_on_server_failure() -> Result<()>
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -733,7 +733,7 @@ async fn refresh_token_returns_transient_error_on_server_failure() -> Result<()>
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let err = ctx
|
||||
.auth_manager
|
||||
@@ -776,7 +776,7 @@ async fn unauthorized_recovery_reloads_then_refreshes_tokens() -> Result<()> {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -786,7 +786,7 @@ async fn unauthorized_recovery_reloads_then_refreshes_tokens() -> Result<()> {
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let disk_tokens = build_tokens("disk-access-token", "disk-refresh-token");
|
||||
let disk_auth = AuthDotJson {
|
||||
@@ -870,7 +870,7 @@ async fn unauthorized_recovery_errors_on_account_mismatch() -> Result<()> {
|
||||
.mount(&server)
|
||||
.await;
|
||||
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let initial_last_refresh = Utc::now() - Duration::days(1);
|
||||
let initial_tokens = build_tokens(INITIAL_ACCESS_TOKEN, INITIAL_REFRESH_TOKEN);
|
||||
let initial_auth = AuthDotJson {
|
||||
@@ -880,7 +880,7 @@ async fn unauthorized_recovery_errors_on_account_mismatch() -> Result<()> {
|
||||
last_refresh: Some(initial_last_refresh),
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&initial_auth)?;
|
||||
ctx.write_auth(&initial_auth).await?;
|
||||
|
||||
let mut disk_tokens = build_tokens("disk-access-token", "disk-refresh-token");
|
||||
disk_tokens.account_id = Some("other-account".to_string());
|
||||
@@ -941,7 +941,7 @@ async fn unauthorized_recovery_requires_chatgpt_auth() -> Result<()> {
|
||||
skip_if_no_network!(Ok(()));
|
||||
|
||||
let server = MockServer::start().await;
|
||||
let ctx = RefreshTokenTestContext::new(&server)?;
|
||||
let ctx = RefreshTokenTestContext::new(&server).await?;
|
||||
let auth = AuthDotJson {
|
||||
auth_mode: Some(AuthMode::ApiKey),
|
||||
openai_api_key: Some("sk-test".to_string()),
|
||||
@@ -949,7 +949,7 @@ async fn unauthorized_recovery_requires_chatgpt_auth() -> Result<()> {
|
||||
last_refresh: None,
|
||||
agent_identity: None,
|
||||
};
|
||||
ctx.write_auth(&auth)?;
|
||||
ctx.write_auth(&auth).await?;
|
||||
|
||||
let mut recovery = ctx.auth_manager.unauthorized_recovery();
|
||||
assert!(!recovery.has_next());
|
||||
@@ -974,7 +974,7 @@ struct RefreshTokenTestContext {
|
||||
}
|
||||
|
||||
impl RefreshTokenTestContext {
|
||||
fn new(server: &MockServer) -> Result<Self> {
|
||||
async fn new(server: &MockServer) -> Result<Self> {
|
||||
let codex_home = TempDir::new()?;
|
||||
|
||||
let endpoint = format!("{}/oauth/token", server.uri());
|
||||
@@ -985,7 +985,8 @@ impl RefreshTokenTestContext {
|
||||
/*enable_codex_api_key_env*/ false,
|
||||
AuthCredentialsStoreMode::File,
|
||||
/*chatgpt_base_url*/ None,
|
||||
);
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Self {
|
||||
codex_home,
|
||||
@@ -1000,13 +1001,13 @@ impl RefreshTokenTestContext {
|
||||
.context("auth.json should exist")
|
||||
}
|
||||
|
||||
fn write_auth(&self, auth_dot_json: &AuthDotJson) -> Result<()> {
|
||||
async fn write_auth(&self, auth_dot_json: &AuthDotJson) -> Result<()> {
|
||||
save_auth(
|
||||
self.codex_home.path(),
|
||||
auth_dot_json,
|
||||
AuthCredentialsStoreMode::File,
|
||||
)?;
|
||||
self.auth_manager.reload();
|
||||
self.auth_manager.reload().await;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,8 @@ async fn auth_manager_logout_with_revoke_uses_cached_auth() -> Result<()> {
|
||||
/*enable_codex_api_key_env*/ false,
|
||||
AuthCredentialsStoreMode::File,
|
||||
/*chatgpt_base_url*/ None,
|
||||
);
|
||||
)
|
||||
.await;
|
||||
save_auth(
|
||||
codex_home.path(),
|
||||
&chatgpt_auth_with_refresh_token("newer-disk-refresh-token"),
|
||||
|
||||
Reference in new issue
Block a user