[SalesForce] oAuth from VF Page in New Lightning – Cannot redirect vf page (iFrame) to login.salesforce.com

We have a visual force page that uses the Apex PageReference method to redirect the VF page to the https://login.salesforce.com for oAuth authentication.

All is working well except in the new Lightning experience where it is throwing the cross origin errors. It works with just the URL but when you add on all the oAuth parameters is where it fails

The code below is what we are using to redirect the page. Since I expect this to be a major issue with a lot of VF pages I am making the question now:

Q: How to do this type of redirect in the new lightning since the vf page is forced inside an iFrame…

public static pagereference oAuth_get_Code(){

    String auth_url = 'https://login.salesforce.com/services/oauth2/authorize';
    String params =  
                        '?response_type=code' +
                        '&client_id=' + encodingUtil.urlencode(client_id(),'UTF-8') +
                        '&redirect_uri=https://' + (isSandbox ? 'cs1' : 'ap1') + '.salesforce.com/apex/ns__pageName' +                             '&prompt=login' + 
                        '&scope=' + encodingUtil.URLEncode('full refresh_token','UTF-8') +
                        '&state=oAUTH_GET_TOKEN';
        pageReference pr = New PageReference(auth_url + params);
        return pr;
}

The error in the console is:

Refused to display {URLDATA} in a frame because it set
'X-Frame-Options' to 'DENY'.

I have added *.salesforce.com and *.force.com to the CORS settings which did not help…..

Exact Error after going to the URL login.salesforce.com/authorize/…….from the code below (This is not the URL I went to so it appears to be the redirect from the authorize:

Refused to display
'https://login.salesforce.com/?startURL=%2Fsetup%2Fsecur%2FRemoteAccessAuthorizationPage.apexp%3Fsource%3DCAAAAU-y0CfJME8wMTMwMX0aCFic4_6fm8ToqqV4SlqhPmh2XbkdZ_-w5uuwmHz_SUT86ve-mdoBjxCw8hcmU3BastbWyCXCohzbqioy6Iz7LWkf-PZWhu3bm7PFdH5xMiDodqSvVdWvsZ60x0je0kSxCTcj9-xydU4OuDeIgSVS4kjN5pFq7FjQLudevAktiKUvgwID1BzIqagzvbvTd7vBaFRV0e3EIbUpKdHf1ss03hilXwEIch-b3BPwmPMST21usKvKed6Z57M8ow5NoHvip5hEU6p67NDJcF8rMaM5fGl5W-HsVD9l0RU5YEH5neiehIzSS3Z-EkUhMW_KFx4UUY36hvRpIM1KbkIgbvhTQpGY0tCGPealN51o74wPkpc6ZOmCa04ZR6VkU2qw5qaftreDZzghXYh2xLqXX1Yawmxjzn5jXk52gSxyBNWH9RO_LgR8FcVM081g8eEYatVK987tfy-2F_EXH67bETUAnWCkkV-pe3mzKOvftdcW_DBp3p070iJj3MavtbENhEdrBUTDxzzO00%253D&sdtd=1'
in a frame because it set 'X-Frame-Options' to 'DENY'.

Best Answer

I usually also set

pr.setRedirect(true);

to make the redirect happen clientside (instead of serverside) so that's worth a try. See for more info here.

What I would suggest is creating a public property on the controller to store the authURL

public String redirectURL { get; set; }

then doing the redirect in Javascript. For this, you'll need rendering the redirectURL in a div (you can't rerender javascript, it will become non-functional CDATA), and do the redirect using something like this

<apex:outputPanel id='redirectURLwrapper'>
    <div id='redirectURL'>{!redirectURL}</div>
</apex:outputPanel>

<script>
    function tryRedirect() {
        var redirect = document.getElementById("redirectURL")[0].innerHTML;
        if (redirect) { top.location.href = redirect; }
    }
</script>

<apex:actionFunction action="{! }" reRender="redirectURLwrapper" oncomplete="tryRedirect();" />

We use top.location.href to make the redirect happen at the top (browser-screen) level, so not inside the iFrame. I have not tested this code literally, but you should get the idea.

If you don't want to lose your existing page, you could also open the URL in a new window like so

<script>
    var windowObjectReference;
    function tryRedirect() {
        var redirect = document.getElementById("redirectURL")[0].innerHTML;
        if (redirect) { 
            windowObjectReference = window.open(redirect, 'newWindowName');                    
        }
        // the popup window should close itself in the return window. If that is not possible, then poll the windowObjectReference and after you detect a redirect, call windowObjectReference.close(); to close it
    }
</script>

Does that help?