Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Acquire token in pop-up window managed by library caller #7362

Closed
kanguro opened this issue Oct 7, 2024 · 4 comments
Closed

Acquire token in pop-up window managed by library caller #7362

kanguro opened this issue Oct 7, 2024 · 4 comments
Labels
msal-browser Related to msal-browser package public-client Issues regarding PublicClientApplications question Customer is asking for a clarification, use case or information.

Comments

@kanguro
Copy link

kanguro commented Oct 7, 2024

Core Library

MSAL.js (@azure/msal-browser)

Wrapper Library

Not Applicable

Public or Confidential Client?

Public

Description

Hello!

Summary
I would like to have an ability to control lifetime of pop-up window that is currently spawned by PublicClientApplication.acquireTokenPopup(request: PopupRequest): Promise<AuthenticationResult> . Currently the method opens pop-up window, performs authentication and closes pop-up on successful authentication, resolving the promise with authentication result. My idea is to add optional parameter popupWindow?: Window to PopupRequest. If set, its value would be used as a host for authentication prompt instead of spawning new window.

Example use case
Let's consider following example: user clicks on a button that would connect them to external service, i.e. OneDrive. Control allowing interaction with external service should be spawned in separate window. Before user can use the service, they must first authenticate via Microsoft Entra ID authentication. Since interaction with the service will be taking place in separate window, it seems intuitive to perform authorization also in the same window. Moreover, browser ad-blocker will prevent opening multiple windows (one for authentication purpose, the other one for service integration).

My first thought is that web application should control the lifetime and the content of single window, so it can serve both purposes.

Considered workarounds
Another idea that crossed my mind is to spawn new window and use PublicClientApplication.acquireTokenRedirect(request: RedirectRequest): Promise<void> in its context somehow. This has the downside of ... well, following redirect logic. After user is done with the authentication, this must be somehow communicated to the parent window. acquireTokenPopup interface seems much easier for this purpose.

Please, let me know what you think. Maybe there is some flow or wiring in existing implementation that I have missed that could lead to same or similar result as described in "Example use case" section?

Thanks in advance,
Artur

Source

External (Customer)

@kanguro kanguro added feature-unconfirmed question Customer is asking for a clarification, use case or information. labels Oct 7, 2024
@github-actions github-actions bot added msal-browser Related to msal-browser package public-client Issues regarding PublicClientApplications labels Oct 7, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs: Attention 👋 Awaiting response from the MSAL.js team label Oct 7, 2024
@tnorling
Copy link
Collaborator

tnorling commented Oct 8, 2024

You can use acquireTokenRedirect and the onRedirectNavigate request parameter to provide your own implementation of how the auth request will be handled. This callback will be invoked with the authorization url instead of redirecting. By using this, however, you will be responsible for making sure you get the response from the login service and passing it back into handleRedirectPromise to complete the flow.

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Author Feedback Awaiting response from issue author and removed Needs: Attention 👋 Awaiting response from the MSAL.js team labels Oct 8, 2024
@kanguro
Copy link
Author

kanguro commented Oct 9, 2024

Thank you @tnorling for quick reply! Please, give me a day or two to check out your proposal.

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Attention 👋 Awaiting response from the MSAL.js team and removed Needs: Author Feedback Awaiting response from issue author labels Oct 9, 2024
@tnorling tnorling added Needs: Author Feedback Awaiting response from issue author and removed Needs: Attention 👋 Awaiting response from the MSAL.js team labels Oct 10, 2024
@kanguro
Copy link
Author

kanguro commented Oct 11, 2024

On one hand I managed to achieve end goal, on the other it requires some boilerplate to get the job done. I wonder if my initial proposal - to make the window customizable via parameter in popup flow - could still be considered as a feature proposal.

In case someone runs into similar problem, I'm sharing example snippets of code illustrating how I dealt with the problem, following advice from @tnorling. Please keep in mind this is just example to show happy-path flow, without proper validation and error handling.

Code in parent window

  async open(): Promise<void> {
    // 1) Open child window immediately, initialize it to empty page
    const childWindow = window.open('about:blank', 'Microsoft OneDrive', 'width=1080,height=680');

    const publicClientApplication = new PublicClientApplication({
      auth: {
        clientId: 'supply your app registration ID here'
      },
      cache: {
        cacheLocation: BrowserCacheLocation.LocalStorage
      }
    });

    await publicClientApplication.initialize();

    childWindow.focus();

    const parentWindow = window;

    let authorizationCompleted = false;

    parentWindow.addEventListener('message', (event) => {
      if (event.origin !== parentWindow.origin) {
        console.error('Unexpected child window origin', event.origin);
        return;
      }

      const payload = event.data as string;
      const containsPostAuthorizationPayload = payload && typeof payload === 'string' && payload.startsWith("#");

      if (!containsPostAuthorizationPayload) {
        return;
      }

      // 4) Child window sent data required to complete authentication as event. Process it as needed.
      publicClientApplication.handleRedirectPromise(payload)
        .then((result: AuthenticationResult) => {
          console.log(result);
          authorizationCompleted = true;
        });
    });

    const isAuthorizationCompletedLoop = new Promise<void>(resolve => {
      const i = setInterval(() => {
        if (authorizationCompleted) {
          clearInterval(i);
          resolve();
        }
      }, 1000);
    });

    // 2) Authenticate using redirect flow
    await publicClientApplication.acquireTokenRedirect({
      scopes: ['User.Read', 'Files.Read.All'],
      redirectUri: `${parentWindow.location.origin}/landing-page.html`, // This page is responsible for posting token back. Must be listed in app registration.
      onRedirectNavigate: (url) => {
        childWindow.location.replace(url); // Here manually opened pop-up is used instead of current (parent) window
        return false;
      }
    });

    await isAuthorizationCompletedLoop;
    // 5) All expected communication between parent and child windows are completed now.
  }

Content of landing-page.html

<!doctype html>
<html>
  <body>
    <script>
      /*
       3) When Entra authentication completes, it redirects to this page.
       Data required to complete authentication is contained in URL and can be accessed by location.hash
       Post it back to the parent window.
       */
      window.opener.postMessage(location.hash, location.origin);
    </script>
  </body>
</html>

@microsoft-github-policy-service microsoft-github-policy-service bot added Needs: Attention 👋 Awaiting response from the MSAL.js team and removed Needs: Author Feedback Awaiting response from issue author labels Oct 11, 2024
@tnorling
Copy link
Collaborator

Thanks for following up to confirm that worked for you! As of right now we have no plans to add support for this outside of onRedirectNavigate but we'll keep this in mind for future consideration.

@microsoft-github-policy-service microsoft-github-policy-service bot removed the Needs: Attention 👋 Awaiting response from the MSAL.js team label Oct 14, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
msal-browser Related to msal-browser package public-client Issues regarding PublicClientApplications question Customer is asking for a clarification, use case or information.
Projects
None yet
Development

No branches or pull requests

2 participants