Skip to content

Credentials Injected in ExecutionInterceptor Not Respected by New Auth Scheme #6486

@shorea

Description

@shorea

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

  • Select this option if this issue appears to be a regression.

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)

  1. 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)
Image Image
  1. User interceptor runs (modifyRequest) and modifies the request's credential provider

  2. 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
  3. 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)

  1. Auth scheme setup in beforeExecution
  2. User interceptor runs and modifies request
  3. SigningStage calls signer.sign(request, executionAttributes)
  4. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis issue is a bug.p1This is a high priority issuepotential-regressionMarking this issue as a potential regression to be checked by team memberresponse-requestedWaiting on additional info and feedback. Will move to "closing-soon" in 10 days.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions