Add NativeAuthRequestInterceptor for custom per-request headers Fixes AB#3600652#3112
Add NativeAuthRequestInterceptor for custom per-request headers Fixes AB#3600652#3112spetrescu84 wants to merge 15 commits into
Conversation
Implement custom HTTP headers request interceptor for native auth CIAM requests, matching the iOS PR (microsoft-authentication-library-for-objc#2862). - Add NativeAuthRequestInterceptor interface for injecting custom x-* headers - Add NativeAuthHeaderValidator to enforce header naming rules - Pass interceptor through the full config propagation chain: OAuth2StrategyParameters → NativeAuthCIAMAuthority → NativeAuthOAuth2Configuration → NativeAuthOAuth2StrategyFactory → all 4 interactors (SignIn, SignUp, ResetPassword, JIT) - Add interceptor field to BaseNativeAuthCommandParameters - Wire interceptor in NativeAuthMsalController.createOAuth2Strategy() - Add unit tests for header validation (11 tests) - Add integration tests for interceptor in SignInInteractor (6 tests) Co-authored-by: Copilot <[email protected]>
|
@copilot resolve the merge conflicts in this pull request |
Co-authored-by: spetrescu84 <[email protected]>
There was a problem hiding this comment.
Pull request overview
Adds a NativeAuthRequestInterceptor extension point that lets applications inject custom x-* HTTP headers (e.g., Akamai/fraud signals) into native-auth (CIAM) network requests. The interceptor is threaded from BaseNativeAuthCommandParameters through OAuth2StrategyParameters → NativeAuthCIAMAuthority → NativeAuthOAuth2Configuration → NativeAuthOAuth2StrategyFactory and into all four interactors (SignIn, SignUp, ResetPassword, JIT). A NativeAuthHeaderValidator enforces the x- prefix and rejects reserved prefixes (x-ms-, x-client-, x-broker-, x-app-).
Changes:
- New
NativeAuthRequestInterceptorinterface andNativeAuthHeaderValidator(with unit tests) for additive, validated headers. - Interceptor field added to
OAuth2StrategyParameters,BaseNativeAuthCommandParameters,NativeAuthOAuth2Configuration, and the four interactors;NativeAuthMsalController.createOAuth2Strategypropagates it; identicalapplyInterceptorHeadershelper duplicated in each interactor. - Integration tests for
SignInInteractor(only) covering merge, null/empty interceptor, reserved-prefix filtering, URL passthrough; changelog entry added.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| common4j/.../providers/NativeAuthRequestInterceptor.kt | New SAM-style interface for per-request additional headers. |
| common4j/.../providers/NativeAuthHeaderValidator.kt | New validator filtering headers by prefix rules. |
| common4j/.../providers/NativeAuthOAuth2Configuration.kt | Adds nullable requestInterceptor config field. |
| common4j/.../providers/NativeAuthOAuth2StrategyFactory.kt | Passes interceptor into all four interactors. |
| common4j/.../providers/interactors/SignInInteractor.kt | Adds interceptor field + applyInterceptorHeaders and applies to 4 calls. |
| common4j/.../providers/interactors/SignUpInteractor.kt | Same interceptor wiring as SignIn (no tests added). |
| common4j/.../providers/interactors/ResetPasswordInteractor.kt | Same interceptor wiring (no tests added). |
| common4j/.../providers/interactors/JITInteractor.kt | Same interceptor wiring (no tests added). |
| common4j/.../authorities/NativeAuthCIAMAuthority.kt | Threads interceptor from strategy params into config; uses fully-qualified type name. |
| common4j/.../providers/oauth2/OAuth2StrategyParameters.java | Adds mRequestInterceptor; introduces dependency from generic OAuth2 layer to nativeauth package. |
| common4j/.../commands/parameters/BaseNativeAuthCommandParameters.java | Adds transient requestInterceptor field (excluded from equals/hash). |
| common/.../controllers/NativeAuthMsalController.kt | Forwards parameters.requestInterceptor into the strategy params builder. |
| common4j/.../NativeAuthHeaderValidatorTest.kt | New unit tests for the prefix validator. |
| common4j/.../SignInInteractorRequestInterceptorTest.kt | New tests for interceptor behavior, only covering SignIn. |
| changelog.txt | Adds entry with empty PR number (#) and misleading "HttpRequest interceptor" wording. |
Comments suppressed due to low confidence (1)
common4j/src/main/com/microsoft/identity/common/java/nativeauth/providers/interactors/SignInInteractor.kt:74
additionalHeadersis invoked from inside the network call path with notry/catcharound it (seeapplyInterceptorHeadersin each interactor). A buggy interceptor implementation that throws (e.g., NPE while computing a fraud signal) will tear down the entire token request with an unrelated exception type that the existing native-auth error mapping is not designed to handle. Consider catchingThrowablefrom the interceptor invocation, logging it, and falling back to no extra headers so an interceptor crash cannot break sign-in/sign-up/reset-password/JIT for end users.
private fun applyInterceptorHeaders(requestUrl: URL, headers: Map<String, String?>): Map<String, String?> {
if (requestInterceptor == null) return headers
val additionalHeaders = requestInterceptor.additionalHeaders(requestUrl) ?: return headers
val validHeaders = NativeAuthHeaderValidator.filterValidHeaders(additionalHeaders)
if (validHeaders.isEmpty()) return headers
val mergedHeaders = headers.toMutableMap()
mergedHeaders.putAll(validHeaders)
return mergedHeaders
}
| @@ -61,6 +62,12 @@ public class OAuth2StrategyParameters { | |||
| @Nullable | |||
| public final List<String> mCapabilities; | |||
|
|
|||
| /** | |||
| * An optional interceptor for injecting custom HTTP headers into native auth requests. | |||
| */ | |||
| @Nullable | |||
| public final transient NativeAuthRequestInterceptor mRequestInterceptor; | |||
Resolved and pushed. I merged |
|
@copilot apply changes based on the comments in this thread |
Applied the linked review-thread updates in Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
- Add SignUpInteractorRequestInterceptorTest (8 tests) - Add ResetPasswordInteractorRequestInterceptorTest (7 tests) - Add JITInteractorRequestInterceptorTest (5 tests) - Expand SignInInteractorRequestInterceptorTest to cover all 7 methods (12 tests) - Total: 43 tests (32 interactor + 11 validator), all passing Co-authored-by: Copilot <[email protected]>
|
❌ Work item link check failed. Description does not contain AB#{ID}. Click here to Learn more. |
|
@copilot apply changes based on the comments in this thread |
Applied. The review-thread items are implemented in the latest commits, including shared interceptor header handling, case-insensitive header normalization/merge behavior, generic OAuth2 interceptor decoupling, and follow-up docs/guards/tests ( |
|
@copilot apply changes based on the comments in this thread |
Applied; the linked review-thread changes are already in the branch via |
| override fun createOAuth2Strategy(parameters: OAuth2StrategyParameters): NativeAuthOAuth2Strategy { | ||
| val config = createNativeAuthOAuth2Configuration(parameters.mChallengeTypes, parameters.mCapabilities) | ||
| if (parameters.mRequestInterceptor != null && parameters.mRequestInterceptor !is NativeAuthRequestInterceptor) { | ||
| Logger.warn(TAG, "Ignoring non-native OAuth2RequestInterceptor for NativeAuthCIAMAuthority.") |
There was a problem hiding this comment.
I think WARN message is misleading the situation.
There was a problem hiding this comment.
I've changed how this works, please take a look
…behavior, add tests - NativeAuthCIAMAuthority: Improve misleading WARN log message to clearly explain that custom headers will not be applied when interceptor type does not match - RequestInterceptorHeaderUtils: Add detailed KDoc explaining case-insensitive merge semantics matching iOS behavior and why reserved SDK headers cannot be overwritten - JITInteractorRequestInterceptorTest: Use 3 base headers (was 2) so null interceptor size assertion is more meaningful - SignUpInteractorRequestInterceptorTest: Add test for reserved header overwrite protection and case-insensitive header merge Co-authored-by: Copilot <[email protected]>
Move shared merge logic tests (reserved filtering, case-insensitive merge, overwrite protection, URL passthrough, null/empty interceptor) out of individual interactor tests into RequestInterceptorHeaderUtilsTest. Each interactor test now only verifies wiring: that the interceptor is called for each public method and that null interceptor passes through unchanged. This eliminates ~370 lines of duplicated test code. Test distribution: - RequestInterceptorHeaderUtilsTest: 9 tests (shared merge contract) - NativeAuthHeaderValidatorTest: 12 tests (validation rules) - 4 interactor tests: 24 tests total (per-method wiring) Co-authored-by: Copilot <[email protected]>
Each interactor method now has both a merge test and a null-interceptor test for full symmetry across SignIn, SignUp, ResetPassword, and JIT. Co-authored-by: Copilot <[email protected]>
Each test now uses the actual production endpoint URL for its method (e.g., /signup/v1.0/challenge for performChallenge) instead of a single shared URL per file. Co-authored-by: Copilot <[email protected]>
Replace all usages of NativeAuthRequestInterceptor in common with the base OAuth2RequestInterceptor type. The NativeAuthRequestInterceptor interface is a public-facing API that customers implement, so it belongs in the MSAL module (com.microsoft.identity.nativeauth package) following the established pattern for public nativeauth types. Common now uses OAuth2RequestInterceptor internally, which is the parent interface with the same contract. Any MSAL-level NativeAuthRequestInterceptor implementation will satisfy this type since it extends OAuth2RequestInterceptor. Co-authored-by: Copilot <[email protected]>
mustafamizrak
left a comment
There was a problem hiding this comment.
Why did you move NativeAuthRequestInterceptor to MSAL module? What are the reasons?
We use NativeAuthRequestInterceptor in public api, that is why we moved it to the main MSAL module. Common core code should not be exposed in the public api. |
Implement custom HTTP headers request interceptor for native auth CIAM requests
API Change: NativeAuthRequestInterceptor moved to MSAL
The
NativeAuthRequestInterceptorinterface has been moved to the MSAL module (com.microsoft.identity.nativeauthpackage) as it is a public-facing type that customers implement. Common now uses the baseOAuth2RequestInterceptortype internally, whichNativeAuthRequestInterceptorextends. This follows the established pattern where public nativeauth types live in MSAL.AB#3600652