Microsoft-authentication-library-for-js: acquireTokenPopup doesn't work

Created on 17 Oct 2017  路  19Comments  路  Source: AzureAD/microsoft-authentication-library-for-js

I can't make acquireTokenPopup to work. In Firefox it's clearly blocked by the popup blocker, I get the notification and receive the error message: Could not retrieve token from popup. popup_window_error:Error opening popup window. This can happen if you are using IE or if popups are blocked in the browser.

In Chrome, the popup does show up, but then I get the same error message. In Edge, the popup shows up, disappears and I get the following error:

ERROR Error: Uncaught (in promise): Error
Error
   at Anonymous function (https://localhost:44388/dist/msal.js:1677:25)
   at ZoneDelegate.prototype.invoke (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111281:13)
   at onInvoke (https://localhost:44388/dist/vendor.js?v=36fdSypR7HRyyaROCi65hZ58pj3rerCHNmsj_igK_Yg:36:890)
   at ZoneDelegate.prototype.invoke (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111281:13)
   at Zone.prototype.run (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111033:17)
   at Anonymous function (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111710:17)
   at ZoneDelegate.prototype.invokeTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111314:13)
   at onInvokeTask (https://localhost:44388/dist/vendor.js?v=36fdSypR7HRyyaROCi65hZ58pj3rerCHNmsj_igK_Yg:36:802)
   at ZoneDelegate.prototype.invokeTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111314:13)
   at Zone.prototype.runTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111083:21)
vendor.js (8,349)
   "ERROR"
   {
      [functions]: ,
      __proto__: { },
      description: "Uncaught (in promise): Error
Error
   at Anonymous function (https://localhost:44388/dist/msal.js:1677:25)
   at ZoneDelegate.prototype.invoke (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111281:13)
   at onInvoke (https://localhost:44388/dist/vendor.js?v=36fdSypR7HRyyaROCi65hZ58pj3rerCHNmsj_igK_Yg:36:890)
   at ZoneDelegate.prototype.invoke (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111281:13)
   at Zone.prototype.run (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111033:17)
   at Anonymous function (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111710:17)
   at ZoneDelegate.prototype.invokeTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111314:13)
   at onInvokeTask (https://localhost:44388/dist/vendor.js?v=36fdSypR7HRyyaROCi65hZ58pj3rerCHNmsj_igK_Yg:36:802)
   at ZoneDelegate.prototype.invokeTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111314:13)
   at Zone.prototype.runTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111083:21)",
      message: "Uncaught (in promise): Error
Error
   at Anonymous function (https://localhost:44388/dist/msal.js:1677:25)
   at ZoneDelegate.prototype.invoke (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111281:13)
   at onInvoke (https://localhost:44388/dist/vendor.js?v=36fdSypR7HRyyaROCi65hZ58pj3rerCHNmsj_igK_Yg:36:890)
   at ZoneDelegate.prototype.invoke (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111281:13)
   at Zone.prototype.run (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111033:17)
   at Anonymous function (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111710:17)
   at ZoneDelegate.prototype.invokeTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111314:13)
   at onInvokeTask (https://localhost:44388/dist/vendor.js?v=36fdSypR7HRyyaROCi65hZ58pj3rerCHNmsj_igK_Yg:36:802)
   at ZoneDelegate.prototype.invokeTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111314:13)
   at Zone.prototype.runTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111083:21)",
      name: "Error",
      promise: {
         [functions]: ,
         __proto__: { },
         __zone_symbol__state: 0,
         __zone_symbol__value: { }
      },
      rejection: { },
      stack: "Error: Uncaught (in promise): Error
Error
   at Anonymous function (https://localhost:44388/dist/msal.js:1677:25)
   at ZoneDelegate.prototype.invoke (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111281:13)
   at onInvoke (https://localhost:44388/dist/vendor.js?v=36fdSypR7HRyyaROCi65hZ58pj3rerCHNmsj_igK_Yg:36:890)
   at ZoneDelegate.prototype.invoke (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111281:13)
   at Zone.prototype.run (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111033:17)
   at Anonymous function (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111710:17)
   at ZoneDelegate.prototype.invokeTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111314:13)
   at onInvokeTask (https://localhost:44388/dist/vendor.js?v=36fdSypR7HRyyaROCi65hZ58pj3rerCHNmsj_igK_Yg:36:802)
   at ZoneDelegate.prototype.invokeTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111314:13)
   at Zone.prototype.runTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111083:21)
   at resolvePromise (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111662:25)
   at Anonymous function (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111713:17)
   at ZoneDelegate.prototype.invokeTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111314:13)
   at onInvokeTask (https://localhost:44388/dist/vendor.js?v=36fdSypR7HRyyaROCi65hZ58pj3rerCHNmsj_igK_Yg:36:802)
   at ZoneDelegate.prototype.invokeTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111314:13)
   at Zone.prototype.runTask (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111083:21)
   at drainMicroTaskQueue (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111476:25)
   at invoke (https://localhost:44388/dist/main-client.js?v=gybG-8xQhYvwdYX40BeY6Wh0n99qhFPDjIcp-UKcV8A:111382:25)",
      task: { },
      zone: { }
   }

Looks like there's something wrong in the msal.js, but there's not much about what exactly is the issue.

Most helpful comment

@rohitnarula7176 OK, I got the whole project working, with a big help from @spottedmahn. The code pushed to https://github.com/Gimly/NetCoreAngularAzureB2CMsal is now working, client side and server side with the fabrikamb2c tenant.

Let me know (or directly add issues to the repo) if you want things changed or want me to do something to add it to your documentation.

Cheers.

All 19 comments

@Gimly You get this error when popups are disabled in the browser. Can you please provide a code repro for this issue?

@rohitnarula7176 Thanks for your answer.

Here's a code to reproduce

@Injectable()
export class AuthenticationService {

    private tenantConfig = {
        tenant: "example.onmicrosoft.com",
        clientID: 'redacted (guid of the client)',
        signUpSignInPolicy: "b2c_1_signup",
        b2cScopes: ["https://example.onmicrosoft.com/demo/read", "openid"]
    }

    private authority = "https://login.microsoftonline.com/tfp/" + 
        this.tenantConfig.tenant + "/" + this.tenantConfig.signUpSignInPolicy;

    private clientApplication: Msal.UserAgentApplication;

    constructor() {
        this.clientApplication = 
            new Msal.UserAgentApplication(
                this.tenantConfig.clientID, 
                this.authority, 
                this.authCallback);
    }

    public login(): void {
        this.clientApplication.loginRedirect(this.tenantConfig.b2cScopes);
    }

    public logout(): void {
        this.clientApplication.logout();
    }

    public isOnline(): boolean {
        return this.clientApplication.getUser() != null;
    }

    public getUser(): Msal.User {
        return this.clientApplication.getUser();
    }

    public getAuthenticationToken(): Promise<string> {
        return this.clientApplication.acquireTokenSilent(this.tenantConfig.b2cScopes)
            .then(token => {
                console.log("Got silent access token: ", token);
                return token;
            }).catch(error => {
                console.log("Could not silently retrieve token from storage.", error);
                return this.clientApplication.acquireTokenPopup(this.tenantConfig.b2cScopes)
                    .then(token => {
                        console.log("Got popup access token: ", token);
                        return token;
                    }).catch(error => {
                        console.log("Could not retrieve token from popup.", error);
                        this.clientApplication.acquireTokenRedirect(this.tenantConfig.b2cScopes);
                        return Promise.resolve("");
                    });
            });
    }

    private authCallback(errorDesc: any, token: any, error: any, tokenType: any) {
        console.log('Callback');

        if (token) {
            console.log("Id token", token);
        }
        else {
            console.log(error + ":" + errorDesc);
        }

        this.getAuthenticationToken();
    }
}

Then, I have a HttpInterceptor that retrieves the token by calling getAuthenticationToken and adding it to the Authorization header.

@Gimly Can you try running the b2c sample we have in the repo and see if that works for you. https://github.com/AzureAD/microsoft-authentication-library-for-js/tree/dev/devApps/VanillaJSTestApp-b2c. Another thing I want you to check is: Try adding a breakpoint in the onload and onerror events of XhrClient.prototype.sendRequestAsync in msal.js at line 2453 to see whether "https://login.microsoftonline.com/tfp/{tenant}/{signUpSignInPolicy}/v2.0/.well-known/openid-configuration" returns a valid resource for your case.

@rohitnarula7176 Here are the results of the tests you suggested.

First, regarding the b2c sample in the repo, it's working correctly. I get the token with the call to acquireTokenSilent. I've modified it to use loginRedirect as with my code, and use my b2c tenant and it's working correctly.

The only thing that doesn't work with this sample is that when I use my own API running on localhost I get a CORS error. Origin http://localhost:6420 not found in Access-Control-Allow-Origin header.. Not sure what I could do about that, but it's another issue.

About the place you asked me to add the breakpoint, it does indeed send the openid-configuration correctly, and it seems to be valid for my case:

{
  "issuer": "https://login.microsoftonline.com/1e4bfcba-ba5d-4b77-a108-4a8ae45c5727/v2.0/",
  "authorization_endpoint": "https://login.microsoftonline.com/te/example.onmicrosoft.com/b2c_1_signup/oauth2/v2.0/authorize",
  "token_endpoint": "https://login.microsoftonline.com/te/example.onmicrosoft.com/b2c_1_signup/oauth2/v2.0/token",
  "end_session_endpoint": "https://login.microsoftonline.com/te/example.onmicrosoft.com/b2c_1_signup/oauth2/v2.0/logout",
  "jwks_uri": "https://login.microsoftonline.com/te/example.onmicrosoft.com/b2c_1_signup/discovery/v2.0/keys",
  "response_modes_supported": [
    "query",
    "fragment",
    "form_post"
  ],
  "response_types_supported": [
    "code",
    "code id_token",
    "code token",
    "code id_token token",
    "id_token",
    "id_token token",
    "token",
    "token id_token"
  ],
  "scopes_supported": [
    "openid"
  ],
  "subject_types_supported": [
    "pairwise"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post"
  ],
  "claims_supported": [
    "given_name",
    "family_name",
    "emails",
    "name",
    "sub",
    "idp",
    "tfp"
  ]
}

OK, did another test, I created a clone of the VanillaTestAppB2C that you have in the repo with Angular. It's available here https://github.com/Gimly/simpleAngularAzureB2C. The code is mostly the same as in my app, but it's working as expected.

There is one thing that doesn't work though, if I refresh the app, the acquireTokenSilent tells me that I'm not connected, even though I get the user through the call to getUser(). Is that another bug?

@rohitnarula7176 I managed to create a sample that reproduce the issue, and I have an idea about what is causing it, but I'm lost in how to fix it. Here's the repository : https://github.com/Gimly/AngularAzureB2CMsal

If you try to run it, you'll see that you're able to login, and if you do from the home page and then go to the weather page, you'll see it working correctly (check the console for the logs). But if you refresh the page, you'll see that it has the same behaviour as what I have experienced.

My clue as to what happens is that the call to acquireTokenSilent happens before msal is completely initialised which breaks the process. Do you have an idea about what I could do to fix that?

I might be wrong but in your https://github.com/Gimly/simpleAngularAzureB2C sample, if you call this.clientApplication.getUser(); right after the initialization of Msal.UserAgentApplication in the AuthenticationService constructor, you should be able to call your api after a browser refresh.

I think this might be related to commit aba6c618e156c21afda1016880f0a9913928b3d0 in the dev branch(https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/aba6c618e156c21afda1016880f0a9913928b3d0)

@mathlesp That's the weird thing, if you look at the code in the simpleAngularAzureB2C repository, I'm indeed calling the getUser directly after init because it's bound in the UI, and I receive the user name correctly after a refresh. But, when I try to get the token, I get an error that says that I'm not connected.

As a resume, after the refresh, isOnline returns true, getUser returns the username, but acquireTokenSilent says I'm not connected.

I cloned your repo and added the line "this.clientApplication.getUser();" in the AuthenticationService constructor right after the initialization of the Msal.UserAgentApplication and it did work. Not sure why it does not work when getUser is triggered in the way you describe above.

I also modified the msal.js file v0.1.2 as per commit https://github.com/AzureAD/microsoft-authentication-library-for-js/commit/aba6c618e156c21afda1016880f0a9913928b3d0 to call ".getUser()" instead of "._user" at lines:

1535 (addHintParameters)
1576 (acquireTokenRedirect)
1629 (acquireTokenPopup)
1703 (acquireTokenSilent)

That also fixed the issue with the refresh without requiring a call to "this.clientApplication.getUser();" in the AuthenticationService constructor.

@mathlesp @Gimly Can you try to use the msal.js file from the dist folder in the dev branch and let me know if it resolves your issue. I have removed the setTimeout function and made the constructor function synchronous to avoid ambiguity. I have also added the change to set user object from the cache before every acquireToken call. @gimly I cloned your sample https://github.com/Gimly/simpleAngularAzureB2C and I can verify that it works on refresh now with the current dev branch,

@rohitnarula7176 OK, just managed to test with the version in the dev branch. It's a bit better, but still not quite there.

My simple sample (https://github.com/Gimly/simpleAngularAzureB2C) works correctly, and indeed the refresh bug is fixed, which is great!

But, the other sample, with the more complex project still can't get the token. I've improved the code and added a Readme that explains how to set it up and run it. it's here if you can check it: https://github.com/Gimly/AngularAzureB2CMsal.

It's really weird, as before the new version, I could get the token if I was logging-in on the home page and then opening the fetch data page, there was the issue only on refreshing directly on the fetch data page. Now it's failing in all situations.

I'm starting to wonder if the reason is not an object in msal that is dropped for some reason because the IoC in Angular recreates the msal instance, or something like that.

Thanks a lot for your help.

@Gimly you are facing this issue because when you start your app at 'http://localhost:6420', angular routing redirects you to 'http://localhost:6420/home'. When you click login from your home page, since you did not specify a redirectUri in your constructor, msal uses your window.location.href which is 'http://localhost:6420/home' and assigns it to the redirectUri for the authorization request. This results in a mismatch error because the registered redirectUri for your app in the portal is 'http://localhost:6420'. To fix it, please change your constructor function in 'authentication.service.ts' to

this.clientApplication =
            new Msal.UserAgentApplication(
                environment.clientID,
                this.authority,
                this.authCallback,{redirectUri:'http://localhost:6420'});

Awesome! Thanks that was the issue.

@Gimly Thank you for your feedback. Closing this issue.

@rohitnarula7176 I'm going to correct the sample I created and leave it on GitHub. Do you think it would be useful for the tool documentation?

@Gimly Yes that would be great. I saw some issues in the sample regarding access of your weather api. If you can fix those, I can have the team review the sample and then we can add it to our documentation.

Yes, I've seen those issues as well, I'm working on fixing them. I'll update this once it's done.

@rohitnarula7176 OK, I got the whole project working, with a big help from @spottedmahn. The code pushed to https://github.com/Gimly/NetCoreAngularAzureB2CMsal is now working, client side and server side with the fabrikamb2c tenant.

Let me know (or directly add issues to the repo) if you want things changed or want me to do something to add it to your documentation.

Cheers.

@Gimly Thats great news. I will let you know once we review your sample. We will release a new version of msal 0.1.3 next week which will have all the fixes and you can directly reference it from CDN.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

yakimko picture yakimko  路  3Comments

sameerag picture sameerag  路  3Comments

spottedmahn picture spottedmahn  路  4Comments

baltuonis picture baltuonis  路  4Comments

ssuvorov picture ssuvorov  路  3Comments