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

Entire app getting built in the Adal Iframe #121

Open
jrmcdona opened this issue Apr 12, 2019 · 3 comments
Open

Entire app getting built in the Adal Iframe #121

jrmcdona opened this issue Apr 12, 2019 · 3 comments

Comments

@jrmcdona
Copy link

jrmcdona commented Apr 12, 2019

Why would my entire app be getting built inside the iframe? I a trying to track down some JavaScript issues and I can see when I am in the debugger of my app code, sometimes I am in the context of the iframe. If you look at the attached pic you can see my app is replicated in the iframe and surely that is not correct.

image

Here is some code from my AppComponent. I do not allow the user to get to my app unless signed in which is why I call login from the OnInit.

 constructor(
    private adalService2: AdalService
  ) {
    this.adalService2.init(environment.adalConfig);
    this.adalService2.handleWindowCallback();
    // This is to avoid reload during acquireTokenSilent() because of hidden iframe
    this.isIframe = window !== window.parent && !window.opener;
  }

  public ngOnInit() {
    if (!this.adalService2.userInfo.authenticated) {
      this.adalService2.login();
    } else {
      this.adalService2.acquireToken(environment.adalConfig.resource).subscribe(
        token => {
          console.log(this.adalService2.userInfo);
          localStorage.setItem("token", token);
          this.loadObjects();
        },
        err => {
          console.log(err);
          this.adalService2.login();
        }
      );

    }
  }

thoughts?

@rjwijnen
Copy link

As far as i know the iframe is there to renew the token in the background.

@shatteredarm
Copy link

shatteredarm commented May 13, 2019

The token gets renews within the iframe, and the handleWindowCallback function detects the presence of an iframe and handles the renewal.

I have a workaround, but it requires a bit of work.

  1. After initializing the AdalService, store the AuthenticationContext in a window variable:
    (<any>window).adalContext = (<any>this.service).context;
  2. Set the callback on the AuthenticationContext:
this.service.init(<adal.Config>{
            ...this.config, callback: function (error, token) {
                this.service.refreshDataFromCache();
                //do whatever needs to be done in the parent window
            }.bind(this)
        });
  1. Make a static handleWindowCallback somewhere in your application that basically does the stuff in AdalService that needs to be done within the iframe. I copied mine from the AdalService code and made some adjustments:
static handleWindowCallback() {
        let adalContext = (<any>window.parent).adalContext;

        const hash = window.location.hash;
        if (adalContext.isCallback(hash)) {
            const requestInfo = adalContext.getRequestInfo(hash);
            adalContext.saveTokenFromHash(requestInfo);
            const callback = (<any>window.parent).callBackMappedToRenewStates[requestInfo.stateResponse] || adalContext.callback;

            if (requestInfo.stateMatch) {
                if (typeof adalContext.callback === 'function') {
                    if (requestInfo.requestType === adalContext.REQUEST_TYPE.RENEW_TOKEN) {
                        // Idtoken or Accestoken can be renewed
                        if (requestInfo.parameters['access_token']) {
                            callback(adalContext._getItem(adalContext.CONSTANTS.STORAGE.ERROR_DESCRIPTION)
                                , requestInfo.parameters['access_token']);
                        } else if (requestInfo.parameters['id_token']) {
                            callback(adalContext._getItem(adalContext.CONSTANTS.STORAGE.ERROR_DESCRIPTION)
                                , requestInfo.parameters['id_token']);
                        } else if (requestInfo.parameters['error']) {
                            adalContext._renewFailed = true;
                            callback(adalContext._getItem(adalContext.CONSTANTS.STORAGE.ERROR_DESCRIPTION), null);
                        }
                    }
                }
            }
        }
    }
  1. Now, in your main.ts, you detect the iframe, and instead of bootstrapping a new instance of the application, you just call your new handleWindowCallback method:
if (!window.frameElement) {
	platformBrowserDynamic().bootstrapModule(AppModule)
	    .catch(err => console.log(err));
} else {
	AuthService.handleWindowCallback();
}

This seems to be working for me so far. Would be nice if there were a cleaner way to do this...

@jesuslpm
Copy link

jesuslpm commented Jul 8, 2019

I have another work around. Set up a reply url to an independent html page, por example https://yourapp.com/logged-in.html. the code is something like this:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
  <h1>
    You are logged in Azure Active Directory
  </h1>
  <p>
    This page will be closed ...
  </p>
  <script type="text/javascript" src="assets/adal.js"></script>
  <script type="text/javascript">
    var context = new AuthenticationContext({
        tenant: 'mytenant.com',
        clientId: 'xxxxxxxxxxxxxxxxxxxxxxx',
        postLogoutRedirectUri: 'https://myapp.com/logout',
        redirectUri: 'https://myapp.com/logged-in.html',
        cacheLocation: 'localStorage',
        endpoints: {
          "https://api.myapp.com": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
      }
    );
    context.handleWindowCallback(window.location.hash);
  </script>
</body>
</html>

Note that you need to include adal.js and logged-in.html in your assets.

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

No branches or pull requests

4 participants