Describe the bug
Credentials injected via ExecutionInterceptor using request override configuration are not respected when using the new auth scheme (SRA). The same credentials ARE respected when using the legacy Aws4Signer.
This indicates that the new auth scheme resolves credentials too early in the request lifecycle, before interceptors have a chance to modify them.
Regression Issue
Expected Behavior
The request should fail with an authentication error:
Exception in thread "main" software.amazon.awssdk.services.appconfig.model.AppConfigException:
The security token included in the request is invalid.
This is the expected behavior because the invalid credentials (akid/skid) should be used for signing.
Current Behavior
Without legacy signer override:
- The request SUCCEEDS despite invalid credentials being injected
- This indicates the injected credentials are being IGNORED
- The SDK uses the default credentials from the environment/chain instead
With legacy signer override (.signer(Aws4Signer.create())):
- The request FAILS as expected with authentication error
- This indicates the injected credentials ARE being respected
Reproduction Steps
AppConfigClient client = AppConfigClient.builder()
.overrideConfiguration(o -> o.addExecutionInterceptor(new ExecutionInterceptor() {
@Override
public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
if (context.request() instanceof AwsRequest awsRequest) {
return awsRequest.toBuilder()
.overrideConfiguration(o -> o
.signer(Aws4Signer.create()) // <-- Only works when this line is present
.credentialsProvider(() -> AwsBasicCredentials.create("akid", "skid")))
.build();
}
return ExecutionInterceptor.super.modifyRequest(context, executionAttributes);
}
}))
.build();
client.listApplications(ListApplicationsRequest.builder().build());
Possible Solution
No response
Additional Information/Context
Root Cause Analysis
New Auth Scheme Flow (Broken)
AppConfigAuthSchemeInterceptor.beforeExecution (generated class) resolves the identity early:
CompletableFuture<? extends T> identity = identityProvider.resolveIdentity(...)
SelectedAuthScheme selectedAuthScheme = new SelectedAuthScheme<>(identity, signer, authOption);
executionAttributes.putAttribute(SELECTED_AUTH_SCHEME, selectedAuthScheme);
- See screenshots of debugger below for evidence credentials are being resolved early (used origAkid to scrub my real credentials)
-
User interceptor runs (modifyRequest) and modifies the request's credential provider
-
The identity is already resolved and stored in SelectedAuthScheme. When credentials are updated via AwsSignerExecutionAttribute.AWS_CREDENTIALS, the write mapping creates a new SelectedAuthScheme but:
- The auth scheme interceptor may have already copied the old identity reference
- The signing stage uses the identity that was resolved in step 1
- Location:
core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsSignerExecutionAttribute.java:208-224
-
SigningStage.sraSignRequest uses the pre-resolved identity:
T identity = CompletableFutureUtils.joinLikeSync(identityFuture);
- Location:
core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/SigningStage.java:91-92
Legacy Signer Flow (Works)
- Auth scheme setup in
beforeExecution
- User interceptor runs and modifies request
SigningStage calls signer.sign(request, executionAttributes)
BaseAws4Signer.sign() calls extractSignerParams() at signing time:
Aws4SignerParams signingParams = extractSignerParams(Aws4SignerParams.builder(), executionAttributes)
.build();
- This reads from
AwsSignerExecutionAttribute.AWS_CREDENTIALS AT SIGNING TIME
- Location:
core/auth/src/main/java/software/amazon/awssdk/auth/signer/internal/BaseAws4Signer.java:34-38
- Location:
core/auth/src/main/java/software/amazon/awssdk/auth/signer/internal/AbstractAws4Signer.java:413-419
Key Difference
Legacy signer: Reads credentials from ExecutionAttributes at signing time (lazy evaluation)
New auth scheme: Resolves credentials in beforeExecution before interceptors run (eager evaluation)
Impact
This breaks any use case where:
- Credentials need to be determined based on the request content
- Credentials are dynamically injected in interceptors
- Per-request credential override is needed after the request is created
Examples:
- Assume-role workflows that determine role based on request parameters
- Multi-tenant applications that select credentials based on request context
- Testing scenarios that inject mock credentials
Workaround
Force the use of the legacy signer by setting it in the request override configuration:
.overrideConfiguration(o -> o
.signer(Aws4Signer.create()) // Force legacy signer
.credentialsProvider(customProvider))
Note: This workaround uses deprecated APIs and may not work long-term.
AWS Java SDK version used
2.34.9
JDK version used
Java17
Operating System and version
AL2
Describe the bug
Credentials injected via
ExecutionInterceptorusing request override configuration are not respected when using the new auth scheme (SRA). The same credentials ARE respected when using the legacyAws4Signer.This indicates that the new auth scheme resolves credentials too early in the request lifecycle, before interceptors have a chance to modify them.
Regression Issue
Expected Behavior
The request should fail with an authentication error:
This is the expected behavior because the invalid credentials (
akid/skid) should be used for signing.Current Behavior
Without legacy signer override:
With legacy signer override (
.signer(Aws4Signer.create())):Reproduction Steps
Possible Solution
No response
Additional Information/Context
Root Cause Analysis
New Auth Scheme Flow (Broken)
AppConfigAuthSchemeInterceptor.beforeExecution(generated class) resolves the identity early:User interceptor runs (
modifyRequest) and modifies the request's credential providerThe identity is already resolved and stored in
SelectedAuthScheme. When credentials are updated viaAwsSignerExecutionAttribute.AWS_CREDENTIALS, the write mapping creates a newSelectedAuthSchemebut:core/auth/src/main/java/software/amazon/awssdk/auth/signer/AwsSignerExecutionAttribute.java:208-224SigningStage.sraSignRequestuses the pre-resolved identity:core/sdk-core/src/main/java/software/amazon/awssdk/core/internal/http/pipeline/stages/SigningStage.java:91-92Legacy Signer Flow (Works)
beforeExecutionSigningStagecallssigner.sign(request, executionAttributes)BaseAws4Signer.sign()callsextractSignerParams()at signing time:AwsSignerExecutionAttribute.AWS_CREDENTIALSAT SIGNING TIMEcore/auth/src/main/java/software/amazon/awssdk/auth/signer/internal/BaseAws4Signer.java:34-38core/auth/src/main/java/software/amazon/awssdk/auth/signer/internal/AbstractAws4Signer.java:413-419Key Difference
Legacy signer: Reads credentials from ExecutionAttributes at signing time (lazy evaluation)
New auth scheme: Resolves credentials in
beforeExecutionbefore interceptors run (eager evaluation)Impact
This breaks any use case where:
Examples:
Workaround
Force the use of the legacy signer by setting it in the request override configuration:
Note: This workaround uses deprecated APIs and may not work long-term.
AWS Java SDK version used
2.34.9
JDK version used
Java17
Operating System and version
AL2