function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
gscottgscott 

OAuth in Winter '10

Has anybody succesfully used OAuth for obtaining a sessionId for use with the API in Winter '10?

 

I've been able to get so far as to generate a valid OAuth access token, but I haven't yet been able to use that access token to get an API session id and I suspect the documentation may not be accurate or complete.

 

A few observations I've made: 

 

  • The documentation says the url is https://login.salesforce.com/services/OAuth/type/api-version.  Where type is "c" for the Partner WSDL and "u" for the enterprise WSDL.  This is the reverse of the normal SOAP API, and I assume it is a mistake, but can't verify since I can't get a session id.
  • The documentation says that "authorization header must have the following parameters" when referring to the request to obtain the session.  I take this to mean that one must use the Authorization HTTP header and not POST parameters to obtain the session id.  However, I've not had success with either.
  • If I do not use the authorization header and post the oauth parameters in the body, I get a response of LOGIN_OAUTH_INVALID_DSIG, indicating a bad signature.  Even though I'm using the same code to sign the request as I do for generating the request and access tokens.
  • If I instead use the Authorization HTTP header I get the error LOGIN_OAUTH_METHOD_NOT_SUPPORTED indicating I must use http POST, even though I already am.  Note, in this case the post body is empty.
 
If anybody has got this last step working it would be very helpful to know how you constructed the request.  Did you use the authorization header?  What were the contents of the POST?  Did you do anything special when generating your signature, in particular the generation of the OAuth Signature Base String and the key used for the signature (I'm using both the consumer and token secrets per the spec). 

 

Thanks,

 

George

 

Best Answer chosen by Admin (Salesforce Developers) 
gscottgscott

I got this working, the documentation definitely needs to be updated and it seems salesforce is not compliant with the OAuth spec in regards to API requests.

 

Here's a quick summary of how I got it working: 

 

To isolate this futher, I tried to login to the frontdoor at https://login.salesforce.com to see what would happen.  It turns out it let me right in using OAuth POST parameters, not the Authorization header, and sent me back a reply with session cookies and HTML to redirect to /home/home.jsp.

 

Once I knew that worked, I tried the API url again.  Because I was getting a bad signature error, I decided to use the same signature I used to go into the front door and it worked!  This means that to compute the signature for generating a session id for the API you need to use the a server URL of "https://login.salesforce.com" and not the actual url you are posting to (e.g. "https://login.salesforce.com/services/OAuth/u/17.0" ) when constructing your OAuth Signature Base String.  This is technically a violation of the OAuth spec.

 

I also verified that the "u" and "c" are swapped in the documentation.  Use the "u" if you want the partner WSDL.

 

So in summary to use OAuth with the API:

 

1. Use HTTP Post to send your oauth parameters and not the authorization header as it states in the documentation.

2. Use "u" for partner API and "c" for enterprise API (as is normally the case), not what it states in the documentation. 

3.  Use "https://login.salesforce.com" as your request URL when generating your OAuth Signature Base String, do not use the actual request URL (e.g. "https://login.salesforce.com/services/OAuth/u/17.0" ).

 

George

 

 

Message Edited by gscott on 10-22-2009 08:58 AM
Message Edited by gscott on 10-22-2009 09:33 PM
Message Edited by gscott on 10-26-2009 02:07 PM

All Answers

gscottgscott

I got this working, the documentation definitely needs to be updated and it seems salesforce is not compliant with the OAuth spec in regards to API requests.

 

Here's a quick summary of how I got it working: 

 

To isolate this futher, I tried to login to the frontdoor at https://login.salesforce.com to see what would happen.  It turns out it let me right in using OAuth POST parameters, not the Authorization header, and sent me back a reply with session cookies and HTML to redirect to /home/home.jsp.

 

Once I knew that worked, I tried the API url again.  Because I was getting a bad signature error, I decided to use the same signature I used to go into the front door and it worked!  This means that to compute the signature for generating a session id for the API you need to use the a server URL of "https://login.salesforce.com" and not the actual url you are posting to (e.g. "https://login.salesforce.com/services/OAuth/u/17.0" ) when constructing your OAuth Signature Base String.  This is technically a violation of the OAuth spec.

 

I also verified that the "u" and "c" are swapped in the documentation.  Use the "u" if you want the partner WSDL.

 

So in summary to use OAuth with the API:

 

1. Use HTTP Post to send your oauth parameters and not the authorization header as it states in the documentation.

2. Use "u" for partner API and "c" for enterprise API (as is normally the case), not what it states in the documentation. 

3.  Use "https://login.salesforce.com" as your request URL when generating your OAuth Signature Base String, do not use the actual request URL (e.g. "https://login.salesforce.com/services/OAuth/u/17.0" ).

 

George

 

 

Message Edited by gscott on 10-22-2009 08:58 AM
Message Edited by gscott on 10-22-2009 09:33 PM
Message Edited by gscott on 10-26-2009 02:07 PM
This was selected as the best answer
dapkusdapkus

Gscott,

 

thanks for putting this together and for uncovering a couple problems with our implementation.  Our goal is to comply completely with the specification. 

 

We are fixing our login method to accept either https://login.salesforce.com or the actual URL (e.g. https://login.salesforce.com/services/OAuth/u/17.0) - the fix should be in production by Thursday 10/29.  We will also correct our documentation to correct the reversal of "u" and "c".

 

Can you explain what you mean by #1 (use POST to pass parameters, not the Authorization header)?   We don't believe this should be the case.

 

Thanks,

-Pete

Message Edited by dapkus on 10-26-2009 10:59 AM
gscottgscott

Pete,

 

Great to hear this is getting fixed so quickly.  I will try it out once again after the fix goes live.

 

In regards to #1 in my post.  In the section of the documentation that discusses how to access salesforce using the consumer application and the API it states that the required parameters must be placed in the "authorization header".  This is different from the documentation that describes how to obtain the request and access tokens.  So I took that to mean one *must* use the authorization HTTP headers (per the OAuth spec), and not put the parameters in the POST body using application/x-www-form-urlencoded encoding.

 

However, when I attempted to POST to the login url using the HTTP Authorization header I always received an error saying invalid method.  Note, that since there is no data to post in this case, the body of the POST is always empty (which may be the problem).  I was never able to get this to work, even after making the change to compute the signature using "https://login.salesforce.com".  Since posting the oauth parameters in the body did work, that is what I was recommending in my post.

 

It is very possible that I made a mistake in constructing my Authorization header, I didn't spend a lot of time diagnosing it further after I got the POST parameters to work with the login url.  Since you can use POST parameters I would recommend changing the documentation to remove the "authorization headers" section and make it similar to the text on obtaining request and access tokens.

 

It would be useful if the documentation (or developer wiki) included sample HTTP headers/body for the various OAuth request types and a sample consumer key/secret.  This would make it much easier for developers to get OAuth up and running.

 

I just added an idea which references a blog post with some ideas on how to make it easier to debug OAuth:

 

http://ideas.salesforce.com/article/show/10098488/Make_it_easier_to_debug_Remote_Access_Applications_OAuth

 

George

SwivelerSwiveler

Hi,

 

I'm running into similar issues.  Using the oauth ruby gem, I've managed to successfully get an access token from Salesforce.  However, when I try to get a session id using that access token, I get an odd error.

 

# after Salesforce OAuth redirects back to my client 

 

rt = OAuth::RequestToken.new @consumer, session[:request_token], session[:request_secret]

at = rt.get_access_token :oauth_verifier => params[:oauth_verifier]

 

res = at.post 'https://login.salesforce.com/'

puts res.body 

 

# => <response><faultcode>1700</faultcode><error>Failed: Signature Invalid</error></response>

 

Here's a dump of the actual POST to 'https://login.salesforce.com/'

 

---!ruby/object:Net::HTTP::Post

body:

  oauth_nonce=4vwwHOp5ixWKNrPU6qgoPHYS03agKYC5OJARO9CqQU&

  oauth_timestamp=1258402353&

  oauth_signature_method=HMAC-SHA1&

  oauth_signature=2i93aV6j%2bl9pDSR2d5Dyk5rkbFY%3d&

  oauth_token=<REDACTED>&

  oauth_consumer_key=<REDACTED>&

  oauth_version=1.0

header: 

  accept: 

  - "*/*"

  content-type: 

  - application/x-www-form-urlencoded

  user-agent: 

  - OAuth gem v0.3.6

  content-length: 

  - 0

method: POST

path: /

request_has_body: true

response_has_body: true 

 

Per my reading, this seems to match what's expected at: https://na7.salesforce.com/help/doc/user_ed.jsp?section=help&target=remoteaccess_authenticate.htm&loc=help&hash=access_data 

 

Any help would be appreciated.

 

Thanks,

Gerad 

SuperfellSuperfell
If there's a HTTP body, the content-length header shouldn't be 0 (no idea if this is the actual problem) Its not clear from that trace if the body is really in the body, or in the queryString.
SwivelerSwiveler

Simon,

 

Thanks for getting back to me so quickly!

 

Good eye.  The OAuth library that I am using does indeed do wacky things to the 'Content-Length' header.  However, it gets ignored by the downstream http library.

 

Here's what actually gets written into the connection:

 

POST / HTTP/1.1

Accept: */*

Connection: close

Content-Type: application/x-www-form-urlencoded

User-Agent: OAuth gem v0.3.6

Content-Length: 381

Host: login.salesforce.com


oauth_nonce=WvO4joJXFVajdphR1UthYD8O2QmXtz4SWDO6f5jUE&oauth_timestamp=1258411747&oauth_signature_method=HMAC-SHA1&oauth_signature=7zbHKx%2b0EM4T8PrG7KIAILHtDUI%3d&oauth_token=<REDACTED>&oauth_consumer_key=<REDACTED>&oauth_version=1.0 

 

So it seems the content-length being 0 in my earlier posting was a bit of a red herring.  Sorry about that!  Any other thoughts?

 

Gerad 

gscottgscott

Gerad,

 

Since my original post, I have done more testing of OAuth with salesforce and I get intermittent invalid signature errors even when requesting access tokens.  I have verified this behavior with different OAuth client libraries, so they have some type of issue still on their back end.  Because of this, I decided not to use OAuth in our applications until this issue is resolved.  

 

I filed a case with support a few weeks ago and it has been reproduced internally and is currently with salesforce tier 3 support.  I would stay clear of OAuth until they get to the bottom of this issue.

 

George

 

SwivelerSwiveler

George,

 

Thanks so much.  I'll take your advice.  It's been quite an adventure getting OAuth to work.

 

Gerad

 

P.S.  Your posts definitely helped a ton with getting as far as I did.  Thanks for trailblazing.

willywuwillywu

try to remove the trailing slash to the input to your library method, i.e.

 

res = at.post 'https://login.salesforce.com'

 

that should fix the signature base string that salesforce is expecting, which hopefully will fix the generated dsig.

AcMEGXAcMEGX
WillyWu and GScott are right.
Just additional clarification/recap for those experiencing the same problems.
You may use GET method for Requesting RequestToken and Requesting AccessToken
 - keep it as "https://login.salesforce.com/" when generating base signature.
You must use POST method when Requesting Session ID and make endpoint https://login.salesforce.com/services/OAuth/type/api-version (ex https://login.salesforce.com/services/OAuth/c/17.0), however use https://login.salesforce.com when generating the base signature. If you are using a OAuth library, take out the "/" character from the normalized URL.
ex.

normalizedUrl += url.AbsolutePath;if (httpMethod.ToUpper() == "POST"){ normalizedUrl = normalizedUrl.Substring(0, normalizedUrl.LastIndexOf("/")); }

 


Hope this helps 
 
celestial_tyrantcelestial_tyrant

Hi,

  I want to send leads to salesforce api from a different web application using php scripts. Can ny1 provide temme how i can authorize, autheticate and get the callback url, or some documentation I can refer.