Skip to content

AuthTab: Common Infrastructure (feature flag + AuthTabManager + dep bump + parameters), Fixes AB#3533465#2993

Draft
Copilot wants to merge 2 commits intodevfrom
copilot/add-auth-tab-support
Draft

AuthTab: Common Infrastructure (feature flag + AuthTabManager + dep bump + parameters), Fixes AB#3533465#2993
Copilot wants to merge 2 commits intodevfrom
copilot/add-auth-tab-support

Conversation

Copy link
Contributor

Copilot AI commented Mar 4, 2026

Lays the groundwork for AuthTab support — a Chrome 137+ API that delivers auth results via an in-process ActivityResultLauncher callback, eliminating the fragile intent-redirect mechanism used by Custom Tabs. This PR adds the foundational artifacts only; fragment/strategy wiring is a separate PBI.

Changes

  • CommonFlight.ENABLE_AUTH_TAB — New feature flag in CommonFlight.java, defaults to false.

  • AuthTabManager.kt — New class (non-singleton; one per fragment) encapsulating all AuthTab API interactions:

    • isAuthTabSupported(context) — static, wraps CustomTabsClient.isAuthTabSupported() with safe fallback
    • registerLauncher(caller, onResult) — must be called on main thread before fragment CREATED state; returns this for chaining
    • launch(authUrl, redirectScheme) / launchWithHttpsRedirect(authUrl, host, path) — throw IllegalStateException if launcher not registered
    • mapAuthResultToRawResult(authResult) — maps all AuthTabIntent.AuthResult codes to RawAuthorizationResult
    // Usage pattern
    authTabManager
        .registerLauncher(this) { result -> handleResult(result) }
    
    // Later:
    authTabManager.launch(authUri, "msauth")

    Result mapping:

    AuthTabIntent result RawAuthorizationResult
    RESULT_OK + non-null URI fromRedirectUri(uri)
    RESULT_OK + null URI fromException(ClientException("authorization_result_not_found", …))
    RESULT_CANCELED fromResultCode(CANCELLED)
    RESULT_VERIFICATION_FAILED fromException(ClientException("auth_tab_verification_failed", …))
    RESULT_VERIFICATION_TIMED_OUT fromException(ClientException("auth_tab_verification_timed_out", …))
    unknown fromException(ClientException("auth_tab_unknown_result", …))
  • AuthorizationActivityParameters.kt — Added val useAuthTab: Boolean = false (last constructor param, @JvmOverloads-safe) and companion object { const val USE_AUTH_TAB = "com.microsoft.identity.USE_AUTH_TAB" }.

  • gradle/versions.gradlebrowserVersion bumped 1.7.01.9.0 to unlock the AuthTabIntent API. Existing Custom Tabs paths are unaffected.

  • AuthTabManagerTest.kt — 12 Robolectric + MockK tests covering: isAuthTabSupported (true/false/exception), all mapAuthResultToRawResult branches including unknown codes, launch guard, launcher field wiring, and end-to-end callback delivery.

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:

  • dl.google.com
    • Triggering command: /usr/bin/curl curl -s REDACTED (dns block)
    • Triggering command: /usr/bin/wget wget -q -O /tmp/browser-meta.xml REDACTED (dns block)
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Xmx3072m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant (dns block)
  • identitydivision.pkgs.visualstudio.com
    • Triggering command: /usr/lib/jvm/temurin-17-jdk-amd64/bin/java /usr/lib/jvm/temurin-17-jdk-amd64/bin/java --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED --add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.prefs/java.util.prefs=ALL-UNNAMED --add-opens=java.base/java.nio.charset=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED --add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED --add-opens=java.xml/javax.xml.namespace=ALL-UNNAMED -XX:MaxMetaspaceSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Xmx3072m -Dfile.encoding=UTF-8 -Duser.country -Duser.language=en -Duser.variant (dns block)
  • www.puppycrawl.com
    • Triggering command: /opt/hostedtoolcache/CodeQL/2.24.2/x64/codeql/tools/linux64/java/bin/java /opt/hostedtoolcache/CodeQL/2.24.2/x64/codeql/tools/linux64/java/bin/java -jar /opt/hostedtoolcache/CodeQL/2.24.2/x64/codeql/xml/tools/xml-extractor.jar --fileList=/tmp/codeql-scratch-b2678d0398b00160/dbs/java/working/files-to-index17484626772427144413.list --sourceArchiveDir=/tmp/codeql-scratch-b2678d0398b00160/dbs/java/src --outputDir=/tmp/codeql-scratch-b2678d0398b00160/dbs/java/trap/java (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

AuthTab: Common Infrastructure (feature flag + AuthTabManager + dep bump + parameters)

Fixes AB#3533465

Follow .github/copilot-instructions.md strictly.

Objective

Lay the groundwork for AuthTab support by adding the feature flag, the new AuthTabManager class, bumping the androidx.browser dependency to 1.9.0, and adding useAuthTab to AuthorizationActivityParameters.

Why

AuthTab is a new Chrome API (Chrome 137+, androidx.browser:browser:1.9.0) that replaces Custom Tabs for authentication flows. It delivers results via an in-process ActivityResultLauncher callback instead of intent-redirect chains, eliminating the fragile static-field/intent-filter redirect mechanism. This PBI creates the foundational artifacts that the integration PBI will wire into the fragment/strategy classes.

What to build

1. CommonFlight.ENABLE_AUTH_TAB

Add a new enum value to CommonFlight.java in common4j.

File: common4j/src/main/com/microsoft/identity/common/java/flighting/CommonFlight.java

Add the following entry to the enum (follow the existing pattern - each entry has a Javadoc comment, a string key, and a default value):

`java
/**

  • Flight to enable AuthTab for browser-based authentication flows.
  • AuthTab is a Chrome 137+ API that delivers auth results via callback
  • instead of intent redirects. Default: false (feature gated).
    */
    ENABLE_AUTH_TAB("EnableAuthTab", false),
    `

2. AuthTabManager.kt

Create a new Kotlin class.

File: common/src/main/java/com/microsoft/identity/common/internal/ui/browser/AuthTabManager.kt

Package: com.microsoft.identity.common.internal.ui.browser

This class encapsulates all AuthTab API interactions:

  • Companion object method isAuthTabSupported(context: Context): Boolean - Calls CustomTabsClient.isAuthTabSupported(context). Wraps in try/catch returning false on failure. Logs via Logger.warn() on error. Thread-safe, can be called from any thread.

  • Instance field mLauncher: ActivityResultLauncher? - Holds the registered launcher.

  • registerLauncher(caller: ActivityResultCaller, onResult: (RawAuthorizationResult) -> Unit): AuthTabManager - Calls AuthTabIntent.registerActivityResultLauncher(caller) { authResult -> ... }. Inside the lambda, calls mapAuthResultToRawResult(authResult) and invokes onResult. Returns this for chaining. Logs registration. MUST be called on main thread before fragment CREATED state.

  • launch(authUrl: Uri, redirectScheme: String) - Throws IllegalStateException if mLauncher is null. Builds AuthTabIntent.Builder().build() and calls authTabIntent.launch(launcher, authUrl, redirectScheme).

  • launchWithHttpsRedirect(authUrl: Uri, redirectHost: String, redirectPath: String) - Same pattern for HTTPS redirects.

  • mapAuthResultToRawResult(authResult: AuthTabIntent.AuthResult): RawAuthorizationResult - Maps result codes:

    • RESULT_OK with non-null resultUri -> RawAuthorizationResult.fromRedirectUri(uri.toString())
    • RESULT_OK with null resultUri -> RawAuthorizationResult.fromException(ClientException(AUTHORIZATION_RESULT_NOT_FOUND, ...))
    • RESULT_CANCELED -> RawAuthorizationResult(ResultCode.CANCELLED, null)
    • RESULT_VERIFICATION_FAILED -> RawAuthorizationResult.fromException(ClientException("auth_tab_verification_failed", ...))
    • RESULT_VERIFICATION_TIMED_OUT -> RawAuthorizationResult.fromException(ClientException("auth_tab_verification_timed_out", ...))
    • else -> RawAuthorizationResult.fromException(ClientException("auth_tab_unknown_result", ...))

Imports needed:

  • android.net.Uri
  • androidx.activity.result.ActivityResultCaller
  • androidx.activity.result.ActivityResultLauncher
  • androidx.browser.customtabs.AuthTabIntent
  • androidx.browser.customtabs.CustomTabsClient
  • com.microsoft.identity.common.java.providers.RawAuthorizationResult
  • com.microsoft.identity.common.java.exception.ClientException
  • com.microsoft.identity.common.java.exception.ErrorStrings
  • com.microsoft.identity.common.logging.Logger

DO NOT make this a singleton. Each fragment instance gets its own AuthTabManager. DO NOT store Context as a field. Add MIT license header matching the project convention.

3. AuthorizationActivityParameters.kt

File: common/src/main/java/com/microsoft/identity/common/internal/providers/oauth2/AuthorizationActivityParameters.kt

This is a Kotlin data class with a @jvmoverloads constructor. Add a new constructor parameter:

kotlin val useAuthTab: Boolean = false,

Add it at the end of the constructor parameters. Also add a companion object constant:

kotlin companion object { const val USE_AUTH_TAB = "com.microsoft.identity.USE_AUTH_TAB" }

4. versions.gradle - dependency bump

File: gradle/versions.gradle

Change: browserVersion = "1.7.0"
To: browserVersion = "1.9.0"

This is safe and backward-compatible. The new AuthTabIntent class is never referenced unless the feature flag is enabled.

5. Unit tests for AuthTabManager

File: common/src/test/java...


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@github-actions
Copy link

github-actions bot commented Mar 4, 2026

✅ Work item link check complete. Description contains link AB#3533465 to an Azure Boards work item.

@github-actions github-actions bot changed the title [WIP] Add feature flag and AuthTabManager implementation [WIP] Add feature flag and AuthTabManager implementation, Fixes AB#3533465 Mar 4, 2026
…ger, dep bump, parameters

Co-authored-by: shahzaibj <37125644+shahzaibj@users.noreply.github.com>
Copilot AI changed the title [WIP] Add feature flag and AuthTabManager implementation, Fixes AB#3533465 AuthTab: Common Infrastructure (feature flag + AuthTabManager + dep bump + parameters) Mar 4, 2026
@github-actions github-actions bot changed the title AuthTab: Common Infrastructure (feature flag + AuthTabManager + dep bump + parameters) AuthTab: Common Infrastructure (feature flag + AuthTabManager + dep bump + parameters), Fixes AB#3533465 Mar 4, 2026
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.

2 participants