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
653 stars 93 forks source link

Outlook addin - is user always forced to click on the dialog to get a graph token? #4617

Open FedericoCaruso opened 3 days ago

FedericoCaruso commented 3 days ago

Sorry if im using the wrong place to ask this question but i already tried on Microsoft Q&A but my question is getting perma blocked by some automated task.

Hi everyone, I'm developing an outlook addin where i need to get an access token to fetch graph apis.
I followed the react office addin graph auth microsoft's guide and everything is working fine, indeed i successfully get an access token and can consume graph api without any problems.

My main concern is that the only way i succeed at getting the access token is by using Office.context.ui.displayDialogAsync which opens a dialog where after the user interacted with it opens a popup which correctly gives me back the access token.

There is any way i can avoid the user repeating this process over and over again?

The perfect scenario would be that the user opens the addin, click on the confirm dialog and when he closes and reopen it he doesn't have to click again on the dialog box.

Your Environment

"@azure/msal-browser": "^3.17.0",
"@azure/msal-react": "^2.0.19",
"react": "^18.2.0",
"react-dom": "^18.2.0",

"office-addin-cli": "^1.5.9",
"office-addin-debugging": "^5.0.17",
"office-addin-dev-certs": "^1.12.2",
"office-addin-lint": "^2.2.9",
"office-addin-manifest": "^1.12.11",
"office-addin-prettier-config": "^1.2.0",

Expected behavior

I would love that somehow the user is not forced to always click on the dialog in order to get graph token

Current behavior

The user is always forced to click on the dialog to get graph token.

this is my code if may help you.

/* global Office console */
/* eslint-disable no-undef */

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

let loginDialog: Office.Dialog;

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

export const signInO365 = async (
  setToken: (token: string) => void,
  setAccount: (accountInfo: AccountInfo) => void,
  setLoading: (isLoading: boolean) => void,
  setError: (error: any) => void
) => {
  Office.onReady(() => {
    Office.context.ui.displayDialogAsync(dialogLoginUrl, { height: 40, width: 30 }, (result) => {
      if (result.status === Office.AsyncResultStatus.Failed) {
        console.log(`${result.error.code} ${result.error.message}`);
        setError(result.error);
        setLoading(false);
      } else {
        loginDialog = result.value;
        loginDialog.addEventHandler(Office.EventType.DialogMessageReceived, processLoginMessage);
      }
    });
  });

  const processLoginMessage = async (arg: { message: string; origin: string }) => {
    if (arg.origin !== window.location.origin) {
      setError("Incorrect origin passed to processLoginMessage.");
      setLoading(false);
      throw new Error("Incorrect origin passed to processLoginMessage.");
    }

    const messageFromDialog = JSON.parse(arg.message);

    if (messageFromDialog.status === "success") {
      setToken(messageFromDialog.result.accessToken);
      setAccount(messageFromDialog.result.account);
      setLoading(false);
      loginDialog.close();
    } else {
      // Something went wrong with authentication or the authorization of the web application.
      setError("error");
      setLoading(false);
      console.log("error");
      loginDialog.close();
    }
  };
};

this is my login.html page

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />

    <!-- Office JavaScript API -->
    <script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1/hosted/office.js"></script>

    <script type="text/javascript" src="/login.ts"></script>
</head>

<body>

</body>

</html>

and this is login.ts

/* global Office */

Office.onReady(async () => {
  try {

const configuration: Configuration = {
  auth: {
    clientId: "clientId",
    authority: "https://login.microsoftonline.com/tenandId",
  },
  cache: {
    cacheLocation: BrowserCacheLocation.LocalStorage,
    storeAuthStateInCookie: true,
  },
};

    const scopes = ["User.ReadBasic.All", "profile", "openid"];
    const pca = new PublicClientApplication(configuration);

    await pca.initialize();
    // handleRedirectPromise should be invoked on every page load.
    const response = await pca.handleRedirectPromise();
    if (response) {
      Office.context.ui.messageParent(JSON.stringify({ status: "success", result: response }));
    } else {
      // A problem occurred, so invoke login.
      await pca.loginRedirect({
        scopes: scopes,
      });
    }
  } catch (error) {
    const errorData = {
      errorMessage: error.errorCode,
      message: error.errorMessage,
      errorCode: error.stack,
    };
    Office.context.ui.messageParent(JSON.stringify({ status: "failure", result: errorData }));
  }
});
isabela-dominguez commented 2 days ago

Thank you for sharing this issue @FedericoCaruso! Connecting you with @exextoc who may be able to help.