Skip to content

Conversation

@melissaahn
Copy link
Contributor

@melissaahn melissaahn commented Nov 4, 2025

Summary

Broker PR: https://github.com/AzureAD/ad-accounts-for-android/pull/3267

Changes related to WebApps getToken are done in this PR, and it also notably contains refactoring (such as moving some files from broker to common) and some additions to core classes such as AccountChooser and AccountChooserActivity.

To optimize the number of IPCs and repeated code, the sub operations will be completed as follows:

  1. Caller calls BrokerMsalController.ExecuteWebAppsRequest.
  2. BrokerMsalController takes a peek at the request.
    • If it is a GetCookies or SignOut request, we will go ahead and call the usual methods to call the ExecuteWebAppsRequestOperation, which will assign the WebAppsGetCookiesSubOperation and WebAppsSignOutSubOperation.
    • If it is GetToken request, we need to deserialize the entire request into a GetToken request object.
      • If we determine that we should force interactive for this request right away:
        1a. we will form the BrokerInteractiveTokenParameters needed and call the BrokerMsalController.acquireTokenInternal method. The parameters will have the BrokerRequestType set to WEB_APPS, and that will serve as a flag to show that this is a WEB_APP flow.
        2a. Eventually, AccountChooserActivity is going to receive these parameters. It is aware that this is a WEB_APP flow because of that flag.
        3a. acquireTokenInternal proceeds as usual. Regardless if it is successful or not, AccountChooser will pass back a custom response to BrokerMsalController already in the protocol format.
        4a. BrokerMSALController will return this response back as-is.
      • If we should first try silent:
        1b. We will call the methods to get to ExecuteWebAppsRequestOperation, which will assign WebAppsGetTokenSubOperation.
        2b. GetTokenSubOperation will preprocess and check for errors. If all is good, it will call SdkOperation.acquireTokenSilent with the necessary parameters.
        3b. If successful, it will send back the expected token response string (the same sort of response which will be sent by AccountChooser). If not, it will send back an error response string.
        4b. If we receive the token response, BrokerMsalController will return the string response as-is. If we receive an error, BrokerMsalController now needs to decide from the initial request if we should fall back to interactive or return an error. In the interactive case, we will run the logic to start an interactive request.
Mermaid-preview

If I try to put this more succinctly:

  • GetCookies and SignOut requests will be taken care of by their respective custom SubOperations.
  • A GetToken interactive request will be taken care of by BrokerMsalController; custom logic was added to the existing AccountChooserActivity to detect the webapp request and return a custom value.
  • A GetToken silent request will be taken care of by its respective custom SubOperation. If this SubOperation returns an error, an interactive request will occur, if possible.

AB#3317102

@melissaahn melissaahn requested a review from Copilot November 4, 2025 12:16
@github-actions
Copy link

github-actions bot commented Nov 4, 2025

❌ Work item link check failed. Description does not contain AB#{ID}.

Click here to Learn more.

* String for broker webapps get contracts result.
*/
public static final String BROKER_WEBAPPS_GET_CONTRACTS_RESULT = "contracts";
public static final String BROKER_WEBAPPS_GET_CONTRACTS_RESULT = "web_apps_contracts";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just making these values more specific

*/
@Nullable
@SerializedName(SerializedNames.WEB_APPS_STATE)
private String mWebAppsState;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

To allow AccountChooserActivity to return a result as a string we can return directly to the caller (without BrokerMsalController interfering too much), we pass the state webapp parameter so that AccountChooserActivity can include it in the result.
I think this is also the more correct approach vs BrkerMsalController injecting it at the end, as the state parameter should be included at the time when the token result is getting created.

final String methodTag = TAG + ":acquireToken";
final AcquireTokenResult result;
try {
final Bundle resultBundle = acquireTokenInternal(parameters);
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 factored out logic into acquireTokenInternal in order to allow executeWebAppsRequest to reuse interactive request logic and get the custom webapp result directly from the bundle. The acquireToken method is not changed otherwise.

@@ -0,0 +1,180 @@
// Copyright (c) Microsoft Corporation.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

One of the classes moved from broker to common.

* Note: This class isn't going to be used until the design for the MATS blob is complete.
* Once that is complete, we will need to pass this data for each error object and getToken suboperation.
*/
data class MatsProperties(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is being created for the future when the design for the MatsProperties schema is complete.

@melissaahn melissaahn requested a review from Copilot November 18, 2025 19:30
Copilot finished reviewing on behalf of melissaahn November 18, 2025 19:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 37 out of 37 changed files in this pull request and generated 19 comments.

}
} else {
envelope = null;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: just initialize with null

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 think though since it's being used in an inner method, if I were to get rid of this else clasue and just init in the beginning with no final, that would not be allowed?

if (resultBundle.containsKey(BROKER_WEB_APPS_ERROR_RESULT)
&& envelope != null) {
final WebAppsGetTokenSubOperationRequest getTokenRequest = envelope.getRequest();
if (canFallbackToInteractiveRequestForWebApp(getTokenRequest, additionalRequiredParams.getCanShowUi())) {
Copy link
Contributor

@mohitc1 mohitc1 Nov 25, 2025

Choose a reason for hiding this comment

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

should all errors fallback to interactive? In normal AT/ATS it's invalid_grant and interaction_required

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 am double checking with the iOS folks as to how it's being done on their side.

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