OfficeDev / office-js

A repo and NPM package for Office.js, corresponding to a copy of what gets published to the official "evergreen" Office.js CDN, at https://appsforoffice.microsoft.com/lib/1/hosted/office.js.
https://learn.microsoft.com/javascript/api/overview
Other
690 stars 95 forks source link

Office API messageParent Outlook on android doesn't work #4763

Open barp opened 3 months ago

barp commented 3 months ago

Provide required information needed to triage your issue

I am trying to implement SSO sign in on outlook addin using office API displayDialogAsync. The implementation works without any issue on iOS version of the addin but on android nothing works correctly.

The code that redirects to the login page is the following and is mostly copied from the example code: https://github.com/OfficeDev/Office-Add-in-samples/blob/main/Samples/auth/Office-Add-in-Microsoft-Graph-React/utilities/office-apis-helpers.ts

let loginDialog: Office.Dialog;
const dialogLoginUrl: string =
  location.protocol +
  "//" +
  location.hostname +
  (location.port ? ":" + location.port : "") +
  "/login/login.html";

export const signInO365 = (
  setToken: (x: string, access: string) => void,
  setUserName: (x: string) => void,
  displayError: (x: string) => void
) => {
  if (!Office.context.requirements.isSetSupported("DialogAPI", "1.1")) {
    displayError("DialogAPI not supported");
    return;
  }
  const options = { height: 40, width: 30 };
  console.log("Opening dialog");
  Office.context.ui.displayDialogAsync(dialogLoginUrl, options, (result) => {
    console.log("Dialog created.", result.value);
    if (result.status === Office.AsyncResultStatus.Failed) {
      displayError(`${result.error.code} ${result.error.message}`);
    } else {
      loginDialog = result.value;
      loginDialog.addEventHandler(
        Office.EventType.DialogMessageReceived,
        processLoginMessage
      );
      loginDialog.addEventHandler(
        Office.EventType.DialogEventReceived,
        processLoginDialogEvent
      );
    }
  });

  const processLoginMessage = (
    arg:
      | {
          message: string;
          origin: string | undefined;
        }
      | { error: number }
  ) => {
    console.log("Got message from dialog.");
    if ("error" in arg) {
      throw new Error("Error in processLoginMessage.");
    }
    // Confirm origin is correct.
    if (arg.origin !== window.location.origin) {
      throw new Error("Incorrect origin passed to processLoginMessage.");
    }

    const messageFromDialog = JSON.parse(arg.message);
    if (messageFromDialog.status === "success") {
      // We now have a valid access token.
      loginDialog.close();
      setToken(messageFromDialog.token, messageFromDialog.accessToken);
      setUserName(messageFromDialog.userName);
    } else {
      // Something went wrong with authentication or the authorization of the web application.
      loginDialog.close();
      displayError(messageFromDialog.result);
    }
  };

  const processLoginDialogEvent = (
    arg:
      | {
          message: string;
          origin: string | undefined;
        }
      | { error: number }
  ) => {
    console.log("Got message from dialog.");
    processDialogEvent(arg, displayError);
  };
};

const processDialogEvent = (
  arg:
    | {
        message: string;
        origin: string | undefined;
      }
    | { error: number },
  displayError: (x: string) => void
) => {
  if ("error" in arg) {
    switch (arg.error) {
      case 12002:
        displayError(
          "The dialog box has been directed to a page that it cannot find or load, or the URL syntax is invalid."
        );
        break;
      case 12003:
        displayError(
          "The dialog box has been directed to a URL with the HTTP protocol. HTTPS is required."
        );
        break;
      case 12006:
        // 12006 means that the user closed the dialog instead of waiting for it to close.
        // It is not known if the user completed the login or logout, so assume the user is
        // logged out and revert to the app's starting state. It does no harm for a user to
        // press the login button again even if the user is logged in.
        break;
      default:
        displayError("Unknown error in dialog box.");
        break;
    }
  }
};

the login page code is:

import { PublicClientApplication } from "@azure/msal-browser";

const applicationId = "REDACTED";

const msalConfig = {
  auth: {
    clientId: applicationId,
    authority: "https://login.microsoftonline.com/common",
    supportsNestedAppAuth: true,
  },
  cache: {
    cacheLocation: "localStorage", // Needed to avoid a "login required" error.
  },
};

Office.onReady(async () => {
  console.log("Office is ready");
  // if (!Office.context.requirements.isSetSupported("DialogAPI", "1.1")) {
  //   console.log("DialogAPI not supported.");
  //   return;
  // }
  const pca = new PublicClientApplication(msalConfig);
  await pca.initialize();
  console.log("MSAL initialized");

  try {
    // handleRedirectPromise should be invoked on every page load.
    const response = await pca.handleRedirectPromise();
    console.log("Response: ", response);
    if (response) {
      Office.context.ui.messageParent(
        JSON.stringify({
          status: "success",
          token: response.idToken,
          accessToken: response.accessToken,
          userName: response.account.username,
        })
      );
      // window.close();
    } else {
      // A problem occurred, so invoke login.
      await pca.loginRedirect({
        scopes: ["user.read", "mail.read"],
      });
    }
  } catch (error) {
    const errorData = {
      errorMessage: error.errorCode,
      message: error.errorMessage,
      errorCode: error.stack,
    };
    console.log({ status: "failure", result: errorData });
    Office.context.ui.messageParent(
      JSON.stringify({ status: "failure", result: errorData })
    );
  }
});

On the panel window I see the following logs:

Opening Dialog
Dialog created. Object {...}
Dialog created. undefined
5001 An internal error has occured

On the login page I see the following:

Office is ready
MSAL initialized
Response: Object {...}

Your Environment

Expected behavior

Dialog will get closed and the authentication details will be sent to the parent window

Current behavior

The dialog is not getting closed automatically and the authentication details sent through the messageParent API are not reaching the parent.

Steps to reproduce

  1. You can try our manifest if we can send it in some private channel

Link to live example(s)

  1. Can send privately

Provide additional details

Context

I saw many issues where something simillar is caused by using different domain for the login page but this is not the case here.

Useful logs

Pazamozaurus commented 3 months ago

The problem happens also for me. Searched for online info regarding how to solve it but found only this issue. Microsoft - would appreciate the help!

Pazamozaurus commented 3 months ago

Any updates, someone from Office team?

rajjha-msft commented 3 months ago

Hello @barp

The issue is not a repro for us.

Can you please share a sample add-in with us where you can repro the issue ? You can create a private GH repro and add @exextoc to it.

barp commented 3 months ago

I have added @exextoc and invited to the project microsoft-android-issue, please take a look

rajjha-msft commented 3 months ago

Hey @barp

We had received the add-in and are working on the issue, thanks.

rajjha-msft commented 2 months ago

Can you share logs for the given account, while we try to create the repro ? You can follow the steps here : https://github.com/OfficeDev/office-js/wiki/Collecting-log-files-for-Outlook-Add%E2%80%90ins-issues

barp commented 2 months ago

I did it for android and got the following incident ID: DUSZSX7Y

barp commented 2 months ago

Hi, sorry to bother you guys. did you discover anything?

Pazamozaurus commented 2 months ago

Hi @rajjha-msft Any new feedback regarding this issue? We're having this problem in my company as well, and it causes us a big delay in launching our outlook add-in for Android. Sorry for pushing, but I'd be happy if you guys can take a look on that soon.

barp commented 2 months ago

I have also tried running the Sample provided in https://github.com/OfficeDev/Office-Add-in-samples/tree/main/Samples/auth/Office-Add-in-Microsoft-Graph-React without any changes except from setting my own APP ID.

It didn't work on android emulator while working on iPhone.

Swathy-Mothilal commented 2 months ago

@barp Thanks for your patience. We are able to repro the issue and have put on our backlog. We, unfortunately have no timelines to share at this point. Internal tracking id: Office : 4823900

barp commented 2 months ago

Is there any workaround for this?

On Wed, 25 Sep 2024 at 23:06 swmothil-MSFT @.***> wrote:

@barp https://github.com/barp Thanks for your patience. We are able to repro the issue and have put on our backlog. We, unfortunately have no timelines to share at this point. Internal tracking id: Office : 4823900

— Reply to this email directly, view it on GitHub https://github.com/OfficeDev/office-js/issues/4763#issuecomment-2374192844, or unsubscribe https://github.com/notifications/unsubscribe-auth/AA5D5RVGQKGXHTSNKMEFTYDZYK7NRAVCNFSM6AAAAABMDW252CVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNZUGE4TEOBUGQ . You are receiving this because you were mentioned.Message ID: @.***>

Pazamozaurus commented 1 month ago

@Swathy-Mothilal Is there any way to implement SSO for an outlook add-in for Android users?