Skip to content

feat: add AWS SigV4 auth for OpenAI-compatible model providers#17820

Merged
celia-oai merged 11 commits intomainfrom
dev/cc/provider-2
Apr 22, 2026
Merged

feat: add AWS SigV4 auth for OpenAI-compatible model providers#17820
celia-oai merged 11 commits intomainfrom
dev/cc/provider-2

Conversation

@celia-oai
Copy link
Copy Markdown
Collaborator

@celia-oai celia-oai commented Apr 14, 2026

Summary

Add first-class Amazon Bedrock Mantle provider support so Codex can keep using its existing Responses API transport with OpenAI-compatible AWS-hosted endpoints such as AOA/Mantle.

This is needed for the AWS launch path, where provider traffic should authenticate with AWS credentials instead of OpenAI bearer credentials. Requests are authenticated immediately before transport send, so SigV4 signs the final method, URL, headers, and body bytes that reqwest will send.

What Changed

  • Added a new codex-aws-auth crate for loading AWS SDK config, resolving credentials, and signing finalized HTTP requests with AWS SigV4.
  • Added a built-in amazon-bedrock provider that targets Bedrock Mantle Responses endpoints, defaults to us-east-1, supports region/profile overrides, disables WebSockets, and does not require OpenAI auth.
  • Added Amazon Bedrock auth resolution in codex-model-provider: prefer AWS_BEARER_TOKEN_BEDROCK when set, otherwise use AWS SDK credentials and SigV4 signing.
  • Added AuthProvider::apply_auth and Request::prepare_body_for_send so request-signing providers can sign the exact outbound request after JSON serialization/compression.
  • Determine the region by taking the aws.region config first (required for bearer token codepath), and fallback to SDK default region.

Testing

Amazon Bedrock Mantle Responses paths:

  • Built the local Codex binary with cargo build.
  • Verified the custom proxy-backed aws provider using env_key = "AWS_BEARER_TOKEN_BEDROCK" streamed raw responses output with response.output_text.delta, response.completed, and mantle-env-ok.
  • Verified a full codex exec --profile aws turn returned mantle-env-ok.
  • Confirmed the custom provider used the bearer env var, not AWS profile auth: bogus AWS_PROFILE still passed, empty env var failed locally, and malformed env var reached Mantle and failed with 401 invalid_api_key.
  • Verified built-in amazon-bedrock with AWS_BEARER_TOKEN_BEDROCK set passed despite bogus AWS profiles, returning amazon-bedrock-env-ok.
  • Verified built-in amazon-bedrock SDK/SigV4 auth passed with AWS_BEARER_TOKEN_BEDROCK unset and temporary AWS session env credentials, returning amazon-bedrock-sdk-env-ok.

@celia-oai celia-oai force-pushed the dev/cc/provider branch 6 times, most recently from b5c6093 to 30c7e0a Compare April 14, 2026 23:11
@celia-oai celia-oai force-pushed the dev/cc/provider branch 22 times, most recently from d4f7674 to cbe3a00 Compare April 16, 2026 19:22
@celia-oai celia-oai marked this pull request as draft April 20, 2026 22:49
@celia-oai celia-oai changed the base branch from main to dev/cc/new-model-provider April 20, 2026 22:50
@celia-oai celia-oai force-pushed the dev/cc/provider-2 branch 2 times, most recently from ce18907 to ea95994 Compare April 20, 2026 23:19
@celia-oai celia-oai force-pushed the dev/cc/new-model-provider branch 3 times, most recently from ad93f1e to d946bfa Compare April 21, 2026 00:10
Base automatically changed from dev/cc/new-model-provider to main April 21, 2026 00:54
@celia-oai celia-oai force-pushed the dev/cc/provider-2 branch 2 times, most recently from 0a65677 to bc752c5 Compare April 21, 2026 05:35
@celia-oai
Copy link
Copy Markdown
Collaborator Author

not a huge fan of this code that reads region from api key, feels very error prone. so I changed the logic back to reading from config. I can add this back as a fallback if needed.

pub fn region_from_bedrock_bearer_token(token: &str) -> Result<String, AwsAuthError> {
    const PREFIX: &str = "bedrock-api-key-";

    let token_body = token
        .trim()
        .strip_prefix(PREFIX)
        .ok_or_else(|| invalid_bedrock_bearer_token("missing bedrock-api-key prefix"))?;
    let encoded_token = token_body
        .split_once("&Version=")
        .map_or(token_body, |(encoded, _)| encoded);
    let decoded = general_purpose::STANDARD
        .decode(encoded_token)
        .map_err(|_| invalid_bedrock_bearer_token("base64 payload could not be decoded"))?;
    let decoded = String::from_utf8(decoded)
        .map_err(|_| invalid_bedrock_bearer_token("decoded payload is not UTF-8"))?;
    let decoded_url = if decoded.starts_with("http://") || decoded.starts_with("https://") {
        decoded
    } else {
        format!("https://{decoded}")
    };
    let url = Url::parse(&decoded_url)
        .map_err(|_| invalid_bedrock_bearer_token("decoded payload is not a URL"))?;
    let credential = url
        .query_pairs()
        .find_map(|(key, value)| (key == "X-Amz-Credential").then_some(value.into_owned()))
        .ok_or_else(|| invalid_bedrock_bearer_token("missing X-Amz-Credential"))?;
    let mut parts = credential.split('/');
    let _access_key = parts.next();
    let _date = parts.next();
    let region = parts
        .next()
        .filter(|region| !region.trim().is_empty())
        .ok_or_else(|| invalid_bedrock_bearer_token("credential scope is missing region"))?;

    Ok(region.to_string())
}

});
return Arc::new(AmazonBedrockModelProvider {
info: provider_info,
aws,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a bit funky to pull out aws from provider_info that already carries it. non blocking

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the goal is to eventually pull out provider info so I left this shape, but happy to collapse if you think it's better

Comment thread codex-rs/model-provider/src/provider.rs Outdated
}

async fn resolve_auth_method(aws: &ModelProviderAwsAuthInfo) -> Result<BedrockAuthMethod> {
if let Some(token) = bearer_token_from_env() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does amazon sdk not resolve this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nope, this is the only one outside of sdk path because it's bearer token based


async fn context(&self) -> std::result::Result<&AwsAuthContext, AuthError> {
self.context
.get_or_try_init(|| AwsAuthContext::load(self.config.clone()))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we ever create without context?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like with_context always sets a value.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there's some benefit of lazy-loading, so I kept this logic. lmk what you think

Comment thread codex-rs/codex-api/src/auth.rs
Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 98df4aab9d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread codex-rs/model-provider/src/amazon_bedrock/auth.rs
Comment thread codex-rs/model-provider/src/provider.rs
Comment thread codex-rs/model-provider/src/amazon_bedrock/auth.rs
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants