Skip to content

Move auth scheme resolution to pipeline stage from interceptors#6755

Open
S-Saranya1 wants to merge 3 commits intofeature/master/core-interceptors-migrationfrom
somepal/refactor-auth-scheme
Open

Move auth scheme resolution to pipeline stage from interceptors#6755
S-Saranya1 wants to merge 3 commits intofeature/master/core-interceptors-migrationfrom
somepal/refactor-auth-scheme

Conversation

@S-Saranya1
Copy link
Contributor

@S-Saranya1 S-Saranya1 commented Feb 26, 2026

Migrate identity resolution from interceptor to pipeline stage

Note: This PR targets a feature branch. Some tests are failing due to endpoint resolution happening before auth scheme resolution in the pipeline unlike before. This will be addressed in Part 2 (Endpoint Resolution Refactoring).

Motivation and Context

The SDK used ExecutionInterceptor for internal auth scheme resolution logic, but this interface was designed for customer extensibility. The AuthSchemeInterceptor.beforeExecution() resolved identity before customer interceptors ran modifyRequest(), causing credential overrides to be ignored. This refactoring moves
identity resolution to a new AuthSchemeResolutionStage in the request pipeline that runs after all interceptors complete, ensuring credentials injected by users are
respected.

Modifications

  • Added AuthSchemeResolutionStage / AsyncAuthSchemeResolutionStage (runs after interceptors complete)

  • Created IdentityProviderUpdater interface for credential override callback

  • Generate resolveAuthSchemeOptions() in client classes, pass options via ClientExecutionParams

  • Migrated business metrics (SIGV4A_SIGNING, BEARER_SERVICE_ENV_VARS) to AwsExecutionContextBuilder

  • Updated S3 presigner for endpoint-based auth provider

Testing

Existing tests - Verified existing auth tests in codegen-generated-classes-test are passing after refactoring .
IdentityResolutionOverrideTest - Verifies credential injection fix

New tests - Unit tests added for AwsIdentityProviderUpdater and AuthSchemeResolutionStage/ AsyncAuthSchemeResolutionStage

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions. Commit the new file created by the script in .changes/next-release with your changes.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

@S-Saranya1 S-Saranya1 requested a review from a team as a code owner February 26, 2026 16:55
tasks.add(generateModelBasedProvider());
tasks.add(generatePreferenceProvider());
tasks.add(generateAuthSchemeInterceptor());
// AuthSchemeInterceptor removed - auth scheme resolution now happens in client operation methods
Copy link
Contributor

Choose a reason for hiding this comment

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

Are these comments needed? Are they for customers or us and will be removed when merging to master?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, will remove them before merging to master.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1 can we remove them now? (I blame kiro because it really likes adding unnecessary comments, should probably update our guideline)

}
}

private MethodSpec resolveAuthSchemeOptionsMethod() {
Copy link
Contributor

Choose a reason for hiding this comment

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

This method is quite large. Could we try extracting the logic, such as the endpoint-based and non-endpoint-based logic into separate helper methods?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure

poetExtensions.getSyncWaiterInterface());
}

private MethodSpec resolveAuthSchemeOptionsMethod() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we consider to move this method to a utility class to avoid dupilication?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, updated.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1

tasks.add(generateModelBasedProvider());
tasks.add(generatePreferenceProvider());
tasks.add(generateAuthSchemeInterceptor());
// AuthSchemeInterceptor removed - auth scheme resolution now happens in client operation methods
Copy link
Contributor

Choose a reason for hiding this comment

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

+1 can we remove them now? (I blame kiro because it really likes adding unnecessary comments, should probably update our guideline)

List<ClassName> builtInInterceptors = new ArrayList<>();

builtInInterceptors.add(authSchemeSpecUtils.authSchemeInterceptor());
// AuthSchemeInterceptor removed - auth scheme resolution now happens in client operation methods
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

.add(".withErrorResponseHandler(errorResponseHandler)\n")
.add(".withRequestConfiguration(clientConfiguration)")
.add(".withMetricCollector(apiCallMetricCollector)\n")
.add(".withAuthSchemeOptions(resolveAuthSchemeOptions($L, $S, clientConfiguration))\n",
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't we need to update codegen fixtures test files, but I don't see the files in this PR

Copy link
Contributor

Choose a reason for hiding this comment

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

I remember we discussed about passing a callback of how to resolve auth scheme options instead because they could also be modified by execution interceptor

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, right. There are a lot of codegen fixture files that we'll need to update again after the endpoints refactoring. I thought maybe we could update them directly before merging to
master. Sure, better to keep these changes. I'll add them.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I remember we discussed about passing a callback of how to resolve auth scheme options instead because they could also be modified by execution interceptor

Oh yeah right, I remember now, I'll update it.

/**
* Records business metrics for auth scheme selection (SigV4a, bearer token).
*/
private static void recordAuthSchemeBusinessMetrics(List<AuthSchemeOption> authSchemeOptions,
Copy link
Contributor

Choose a reason for hiding this comment

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

Question: should we record the metrics in AuthSchemeResolutionStage?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

AuthSchemeResolutionStage happens after ApplyUserAgentStage, so metrics wont get recorded then.

* Pipeline stage that resolves the auth scheme and identity for signing.
*/
@SdkInternalApi
public final class AuthSchemeResolutionStage implements RequestToRequestPipeline {
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add a unit test for this class?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My bad, missed committing the file, added the tests now.

@@ -240,7 +244,7 @@ private List<ExecutionInterceptor> initializeInterceptors() {
List<ExecutionInterceptor> s3Interceptors =
interceptorFactory.getInterceptors("software/amazon/awssdk/services/s3/execution.interceptors");
List<ExecutionInterceptor> additionalInterceptors = new ArrayList<>();
additionalInterceptors.add(new S3AuthSchemeInterceptor());
// S3AuthSchemeInterceptor removed - auth scheme resolution now done inline
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure

poetExtensions.getSyncWaiterInterface());
}

private MethodSpec resolveAuthSchemeOptionsMethod() {
Copy link
Contributor

Choose a reason for hiding this comment

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

+1

Comment on lines +26 to +45
///
/// A container for the identity resolver, signer and auth option that we selected for use with this service call attempt.
/// ## The Hierarchy
/// ```
/// IDENTITY_PROVIDERS (IdentityProviders)
/// └── contains multiple IdentityProvider<T> instances
/// e.g., IdentityProvider<AwsCredentialsIdentity> for AWS credentials
/// e.g., IdentityProvider<TokenIdentity> for bearer tokens
///
/// AUTH_SCHEMES (Map<String, AuthScheme<?>>)
/// └── each AuthScheme knows:
/// - which IdentityProvider type it needs
/// - which HttpSigner to use
///
/// SELECTED_AUTH_SCHEME (SelectedAuthScheme<T>)
/// └── the chosen auth scheme, containing:
/// - identity: CompletableFuture<T> ← the resolved identity!
/// - signer: HttpSigner<T>
/// - authSchemeOption: AuthSchemeOption
/// ```
Copy link
Contributor

Choose a reason for hiding this comment

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

should we use a single/* */ instead of /// on each line?

Copy link
Contributor

@zoewangg zoewangg Feb 27, 2026

Choose a reason for hiding this comment

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

Markdown is much better! 😛 https://openjdk.org/jeps/467

/**
* Apply credential overrides from request configuration.
*/
private IdentityProviders applyCredentialOverrides(SdkRequest request, IdentityProviders base) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This method is identical to AwsIdentityProviderUpdater.update(), should we remove and just call AwsIdentityProviderUpdater.INSTANCE.update()?

@davidh44
Copy link
Contributor

Is AwsExecutionContextBuilder.resolveIdentityProviders() redundant now that we resolve in AwsIdentityProviderUpdater.update() later? Should we just return clientConfig.option(SdkClientOption.IDENTITY_PROVIDERS)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants