[SalesForce] Why does OAuth2 authorization endpoint redirect to callback URL as if it were the SAML IdP

This is all a proof-of-concept in a sandbox; maybe something I'm doing is not supported in sandboxes.
Our org is set up with SAML2-based SSO and that works well. Now I'm trying to use a REST API and OAuth2 to authenticate, using web server flow. We have the "My Domain" feature enabled as per the articles on mixing SAML SSO with OAuth apps.
I send a request like this (wget shown for simplicity):

wget -O – 'https://xxx.my.salesforce.com/services/oauth2/authorize?response_type=code&redirect_uri=XXX&client_id=YYY'

But instead of redirecting to our IdP login page, it generates a page with JavaScript that redirects to my redirect_uri appending a SAML app that I don't recognize from any setup we've done:

XXX/saml/authn-request.jsp?saml_request_id=ZZZ…

Naturally this is not found on my server. If I disable SSO for my account and try the same request, I get redirected to the standard salesforce login and I'm able to log in and authorize the application, and I get the auth code.

Is there something else in the setup that needs to be done?

Java Code to auth in to Salesforce.

StringBuffer data = new StringBuffer();
              data.append("response_type=code");
              data.append("&client_id=" + URLEncoder.encode("client_id", "UTF-8"));
              data.append("&redirect_uri=" + URLEncoder.encode("redirect_uri", "UTF-8"));

              URL url = new URL("mydomain.instance.my.salesforce.com/services/oauth2/authorize");
              HttpURLConnection connection = (HttpURLConnection)url.openConnection();
              connection.setDoOutput(true);
              connection.setRequestMethod("POST");
              connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
              OutputStreamWriter wr = 
                     new OutputStreamWriter(connection.getOutputStream());
              System.out.println(data.toString());
              wr.write(data.toString());
              wr.flush();
              InputStream in = connection.getInputStream();
              BufferedReader reader = new BufferedReader(new InputStreamReader(in));
              StringBuffer result = new StringBuffer();
              String line = reader.readLine();
              while(line != null) {
                     result.append(line);
                     result.append("\n");
                     line = reader.readLine();
              }
              wr.close();
              reader.close();
              System.out.println(result.toString());

Reponse : JavaScript that redirects to /saml/authn-request.jsp?saml_request_id=…

Best Answer

If you look at that response carefully, you'll see that the JavaScript actually makes a request of https://xxx.my.salesforce.com/, not your server. You need to follow one step further to see the request to your server. Here's an abbreviated version of what I just saw.

First, the initial OAuth request to a My Domain URL:

$ curl -v 'https://superpat-developer-edition.my.salesforce.com/services/oauth2/authorize?response_type=code&redirect_uri=...&client_id=...'
* ...
< HTTP/1.1 302 Found
< Location: https://superpat-developer-edition.my.salesforce.com/setup/secur/RemoteAccessAuthorizationPage.apexp?source=...

Following the redirect:

$ curl -v https://superpat-developer-edition.my.salesforce.com/setup/secur/RemoteAccessAuthorizationPage.apexp?source=...
* ...
< HTTP/1.1 200 OK
< ...
< 
<script>
var escapedHash = '';
var url = '/saml/authn-request.jsp?saml_request_id=...&saml_acs=...&saml_binding_type=HttpPost&Issuer=https%3A%2F%2Fsuperpat-developer-edition.my.salesforce.com&urlSource=1&RelayState=%2Fsetup%2Fsecur%2FRemoteAccessAuthorizationPage.apexp%3Fsource%3D...';
if (window.location.hash) {
   escapedHash = '%23' + window.location.hash.slice(1);
}
if (window.location.replace){ 
window.location.replace(url + escapedHash);
} else {;
window.location.href = url + escapedHash;
} 
</script>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
...
</html>

Note - no server on that /saml/authn-request.jsp URL, so the request will go to https://superpat-developer-edition.my.salesforce.com/. Let's simulate it with curl and see what happens:

$ curl -v 'https://superpat-developer-edition.my.salesforce.com/saml/authn-request.jsp?saml_request_id=...&saml_acs=...&saml_binding_type=HttpPost&Issuer=https%3A%2F%2Fsuperpat-developer-edition.my.salesforce.com&urlSource=1&RelayState=%2Fsetup%2Fsecur%2FRemoteAccessAuthorizationPage.apexp%3Fsource%3D...'
* ...
< HTTP/1.1 200 OK
< ...
< 

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">

    <body onload="document.forms[0].submit()">
        <noscript>
            <p>
                <strong>Note:</strong> Since your browser does not support JavaScript,
                you must press the Continue button once to proceed.
            </p>
        </noscript>

        <form action="https://ADFS.example.com/adfs/ls/" method="post">
            <div>
                <input type="hidden" name="RelayState" value="/setup/secur/RemoteAccessAuthorizationPage.apexp?source=..."/>                
                <input type="hidden" name="SAMLRequest" value="..."/>                

            </div>
            <noscript>
                <div>
                    <input type="submit" value="Continue"/>
                </div>
            </noscript>
        </form>

    </body>
</html>

And there's the request that's posted to the SAML endpoint you configured (in my case, https://ADFS.example.com/adfs/ls/). So - follow the chain one more link and you should see what's really happening.

Related Topic