External IDP via Pop Up

61 views
Skip to first unread message

bob sheknowdas

unread,
Feb 17, 2020, 2:52:01 AM2/17/20
to Keycloak User
Hi

I am using keycloak in an iframe.
Behind my keycloak are some secondary IDPs like google and facebook.

With my current configuration, keycloak simply redirects to those secondary IDPs. This means they are beeing opened within the iframe aswell.
I'd really like to change that, since it contradicts some major security policies I have.

Can I somehow tell keycloak to open external IDPs in a pop up?
I have read the keycloak "server administration guide" but couldn't find any infos reagrding this issue.

Best
Bob

bob sheknowdas

unread,
Feb 19, 2020, 2:27:15 AM2/19/20
to Keycloak User
Since no one seems to know a straight forward way to do it, I am now trying workarounds...

What I've come up with so far is modifying the login.ftl of the login theme.
I changed the social hyperlinks in a way that they
  1. open the link in a popup
  2. check for the popup being closed
When the popup is closed (the login at the external IDP was successful) the parent is either refreshed or redirected (depending on keycloak being opened via iframe or via browser redirect).

So originaly the code looked like this:
<a href="${p.loginUrl}" id="zocial-${p.alias}" class="zocial ${p.providerId}">

Now it looks like this:

<a id="zocial-${p.alias}" class="zocial ${p.providerId}" onclick="
  let win
= window.open('${p.loginUrl}', '${name}', 'toolbar=no,width=600,height=600')
  let timer
= setInterval(function() {
   
if (win.closed) {
      clearInterval
(timer);
     
if (win.parent == win.self) {
         window
.history.back();
     
} else {
         window
.parent.location.reload();
     
}

   
}
 
}, 1000);
">

Now that works quite alright.

Except that the popup does not get closed automatically.
And I just seem to can't find a way to do it automatically.

When the login via social provider is successful keycloak redirects directly to its client.
So there is no freemarker template loaded that I could manipulate to close the popup.

Also no SPI seems to be available for the /auth/realms/<myrealm>/broker/<mybroker>/endpoint  endpoint.
And an event listener (who could actually detect the successful IDP login) seemingly has no communication chanel to the frontend...

Does anyone have any idea how I could solve this?
Message has been deleted

bob sheknowdas

unread,
Feb 26, 2020, 3:01:54 AM2/26/20
to Keycloak User
Ok, i figured out a solution that uses a lot of js magic and workarounds.

I modified my login.ftl again.
After opening the popup it now also registers a message listener, that expects an URL as message body. When a message is received, an empty form will be posted to that URL.

            <form id="kc_social_continue" method="post">
            </form>
           
<script>

             
function openInPopUp(url, name) {
                let popup
= window.open(url, name, 'toolbar=no,width=600,height=600');
                let receiveMessage
= (event) => {
                 
if (event.origin !== (window.location.protocol + '//' + window.location.hostname)){
                   
return;
                 
}
                  document
.forms['kc_social_continue'].action = event.data;
                  document
.forms['kc_social_continue'].submit();
               
};
                window
.addEventListener('message', receiveMessage, false);
             
}
           
</script>

Than I added a custom Authentication SPI.
This does nothing but presenting an custom .ftl to the user.

public class ClosePopupAuthenticator implements Authenticator {

    @Override
    public void authenticate(AuthenticationFlowContext context) {
        Response challenge = context.form()
                .createForm("close-popup.ftl");
        context.challenge(challenge);

    }

    @Override
    public void action(AuthenticationFlowContext context) {
        context.success();
    }
}

This close-popup.ftl sends its loginAction-URL to the parent window and then closes itself.

    <script>
      let host = window.location.hostname;
      let protocol = window.location.protocol;
      window.opener.postMessage("${url.loginAction}", protocol + '//' + host);
      window.close();
    </script>

This new SPI has to be added to a new Flow which than has to be set as "Post Login Flow" for all relevant Identity Providers.

All of this in combination solves my problem...
Reply all
Reply to author
Forward
0 new messages