As most of you probably know by now, Salesforce supports the OAuth protocol for authenticating with Force.com. Check out Pat's excellent article for a deeper dive into OAuth 2.0 at Salesforce.com. What some of you may not know however is that you can use the access token acquired via OAuth to authenticate with the venerable SOAP API. So instead of invoking the 'login' method of the SOAP API by providing your username/password (and optionally security token), you can acquire an OAuth access token by implementing any one of the OAuth 2.0 flows described in Pat's article (say the 'Username-Password Flow'). You can then insert the OAuth access token into the standard 'sessionID' SOAP header to make subsequent calls to the SOAP API. 

So far so good. There is however a small nuance to using OAuth authentication with the SOAP API that I wanted to highlight. In the traditional username/password authentication scheme (described in greater details here), the initial 'login' call is made to the https://login( or test).salesforce.com/services/Soap/….. URL. In response, Salesforce returns the server URL (e.g. https://na1-api.salesforce.com/services/Soap/c/21.0) that all subsequent API requests should be redirected to. With OAuth, since you're never invoking the 'login' method of the SOAP API, how do you know which URL to redirect your API calls to? If you simply directed your API calls to the generic https://login(or test).salesforce.com/services/Soap/….. URL, you'd get an authentication error.

What's that you say? Couldn't I just use the 'instance_url' that is returned along with the access token during the OAuth dance? (Quick non sequitur. I love when geeks try to describe technology to other geeks with metaphors like 'dance'. Like any of us geeks can relate to how it is to dance!). The 'instance_url' value acquired via OAuth 2.0 simply points to the Salesforce instance that your Org is hosted on (e.g. 'https://na1.salesforce.com'). It is not the SOAP endpoint that you should be redirecting your API requests to. Since the SOAP endpoint URI naming convention is well known, you could of course construct the SOAP endpoint in your client code by appending '/services/Soap/….' to the 'instance_url'. There is however a better option that doesn't require hard-coding the endpoint (and by extension the API version) in your code.

The answer lies in the magical, yet often overlooked 'id' parameter that is returned by OAuth 2.0 along with the access token. As described by Pat here, you can get a wealth of information by making a simple GET request to the 'id' URI. Among the pieces of information returned (in the 'urls' array to be exact) are the SOAP endpoints for the Enterprise and Partner WSDLs. Depending on whether you're consuming the Enterprise or Partner WSDL, these are the URLs that you should direct all subsequent SOAP calls to.

So, to recap, here is the sequence of events for using OAuth 2.0 with the SOAP API

1) Implement one of the 6 flows supported by OAuth 2.0 and receive the access token, 'id' and other parameters from Force.com.

2) Make a GET request (passing in the access token as the OAuth authorization HTTP header) to the 'id' URI.

3) Insert the access token into the 'sessionID' SOAP header and make all subsequent API calls to the enterprise or partner SOAP endpoints returned by the previous step.

 

As always, comments/brickbats/suggestions are welcome. Now its back to 'dancing' with my current project! 

tagged Bookmark the permalink. Trackbacks are closed, but you can post a comment.
  • Ayaz Pasha

    Many thanks for a good article.

    I would like to know if OAuth takes care of the GET request to the ‘id’ URI. If so, then how is OAuth pulling out these details (SOAP endpoints)?

    • Anonymous

      Not sure I understand what you mean by ‘take care of the GET request’. You still have to make an explicit GET request to the ‘id’ URI (with the access token in the HTTP header) – OAuth doesn’t do that automatically.

  • http://twitter.com/fredericmeunier Frédéric Meunier

    We have encountered many many problems with that damned endpoint URL. With a partner WSDL it works fine to use the partner url retrieved with “id” URL. This Url looks like “https://xxx.salesforce.com/services/Soap/u/{version}/yyyyyyyyyy”.
    BUT for a managed WSDL (AppEx), with partner and enterprise Urls an exception is thrown (“No operation available for request {http://soap.sforce.com/schemas/class/yourApp}yourVerb”). However, with a concatained Url using instance_url and /soap/class/yourApp… it works!
    With some malformed URL, an other exception is thrown : “INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session. Session not found, missing session key”…
    What an headache we have got these 3 last days!

    • David Mosher

      Did you ever figure out this session id issue? Seeing similar issue

      • David Mosher

        Note that even if you can get the access code and pass it into the session Id for the soap, you can’t call webservices if the end org is a Professional or WebServices edition, even with the client id. You can only call standard Salesforce calls so you might as well do it with the REST API. If you are doing a webservice for use in Enterprise or Unlimited edition, theorically this will work if you can figure out what is misinformation and what is really current. Good luck!

    • Monzer Hijazi

      I successfully utilized the Url returned by replacing the {version} with the Force.com API version my code is utilizing (25) You can see the available API versions via Workbench when you are logging in.

      Thanks for the great post… I’ll let you know if I find any complications.

  • Dmitriy Salko

    Does OAuth work with Metadata API ? Thanks.

  • Anonymous

    hello, I’m a beginner, tried to verify this for my case. can you explain me – as a beginner – how to make the get Request to get the right Id (Step2) and how to Insert the access token into the ‘sessionID’ SOAP header. (step3)
    if possible – can you give me a php code example?
    thsnks a lot,
    adi