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
emacadieemacadie 

Getting an OAuth token

I am trying to obtain an OAuth token.

 

I see that there is some Java code on http://www.salesforce.com/us/developer/docs/api_rest/Content/quickstart_oauth.htm, but it is not very useful. Is this a web app? A command line app? What packages are being imported? There are some variables put into the initParams array, but this array is never used as far as I can tell. Can this app be downloaded from somewhere?

 

 

emacadieemacadie

I think I got an access token. I was able to get one via curl. I think. It is about 110 characters. Is that normal?

 

I got it via this:

curl -v -k https://na3.salesforce.com/services/oauth2/token -d "grant_type=password" -d "client_id=COMNSUMER_KEY" -d "client_secret=CONSUMER_SECRET" -d "username=USERNAME" -d "password=PASSWORD"

 

I saw another post that I would need to get a refresh token because the access tokens expire. How do I get that?

cconlincconlin

For anyone else looking for an answer to this, to login using the "password" grant type, you must do the following:

 

 

import urllib
import urllib2

params = urllib.urlencode({
    'grant_type'    : 'password',
    'client_id'     : '<YOUR CONSUMER KEY>',
    'client_secret' : '<YOUR CONSUMER SECRET>',
    'username'      : '<YOUR USERNAME>',
    'password'      : '<THE COMBINATION OF YOUR PASSWORD AND TOKEN>'
})

# You would use https://test.salesforce.com if not using a live system.
url = 'https://login.salesforce.com/services/oauth2/token'

# Make a POST request
response = urllib.urlopen(url, params)

 

If you are successful, something like the following will appear in your response:

 

 

{
    "id":"https://login.salesforce.com/id/XXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXX",
    "issued_at":"1302557953612",
    "instance_url":"https://xxn.salesforce.com",
    "signature":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "access_token":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}

 

If your credentials are incorrect or you did something stupid (like I did when I didn't encode the URL properly), you will see something like the following:

 

 

{
    "error":"invalid_grant",
    "error_description":"authentication failure"
}

 

Now you can REST.

 

 

 

tompkinrtompkinr

Thanks for posting this.

 

Here is the curl version

curl -d "username=username@company.com&client_secret=123456789&password=pwdgoeshere&grant_type=password&client_id=ReallyLongClientIDGoesHere" -H "Accept: application/json" https://login.salesforce.com/services/oauth2/token

 

username :     your salesforce login name

password :     your salesforce password. If you are logging in from a non whitelisted host, you will need to attach your security token

client_secret : the "Consumer Secret" found on the remote access setting

client_id :        the "Consumer Key" found on the remote access setting

Pat PattersonPat Patterson
emacadieemacadie

Thanks for the link to the tutorial. I am going through it now.

 

Just so you know: That page has a link to the Apache HttpClient library and it links to the latest version, version 4. The servlet code uses version 3 of ht HttpClient library, which can be found here: http://archive.apache.org/dist/httpcomponents/commons-httpclient/3.0/

 

emacadieemacadie

How long is the access token good for?

Pat PattersonPat Patterson

Thanks for the catch! I actually used version 3.1 of the HttpClient library, which is available at a similar location - http://archive.apache.org/dist/httpcomponents/commons-httpclient/ .

 

I've updated the article.

 

Cheers,


Pat

Pat PattersonPat Patterson

The lifetime of an OAuth access token is the same as that of any other session ID - i.e. "Sessions expire automatically after a predetermined length of inactivity, which can be configured in Salesforce by clicking Your Name ➤ Setup ➤ Security Controls. The default is 120 minutes (two hours). If you make an API call, the inactivity timer is reset to zero."

The 'getting started' article doesn't go into any detail on token refresh, but it's covered in the 'digging deeper into OAuth 2.0' article at http://wiki.developerforce.com/index.php/Digging_Deeper_into_OAuth_2.0_on_Force.com

Cheers,

Pat

emacadieemacadie

Do you know if I could run this with two browsers on one machine hitting two different accounts?

Pat PattersonPat Patterson

Yes - I do this frequently - one account in Firefox, another in Chrome. If you're on the Mac, then Trapdoor is a great tool to help you manage multiple salesforce.com accounts.

etntetnt

Hi,

 

I'm trying to follow your curl example with the passwprd grant_type, but I get either: "expired access/refresh token" or,

when using a HTTP POST: "grant type not supported".

 

Any ideas?

Any other examples using curl?

 

--T.

 

Pat PattersonPat Patterson

Can you post the curl command line you're trying to use, and the error you're seeing? Change any sensitive data such as passwords! :-)

etntetnt

 

Ok, my curl request looks like this:

 

curl -v --data-urlencode @salesforce.data  -H "Accept: application/json" https://test.salesforce.com/services/oauth2/token

 

and the file: salesforce.data contains (secret stuff removed...):

 

grant_type=password
client_id=3MV....snip.....3ZZ
client_secret=33...snip...60
username=abc@xyz.com
password=mypasswordMySecretToken
The curl output looks like this:
...snip...some...SSL...specifics...removed....here...
> POST /services/oauth2/token HTTP/1.1
> User-Agent: curl/7.21.3 (x86_64-pc-linux-gnu) libcurl/7.21.3 OpenSSL/0.9.8o zlib/1.2.3.4 libidn/1.18
> Host: test.salesforce.com
> Accept: application/json
> Content-Length: 244
> Content-Type: application/x-www-form-urlencoded
< HTTP/1.1 400 Bad Request
< Server: 
< Content-Type: application/json; charset=UTF-8
< Content-Length: 81
< Date: Tue, 10 May 2011 12:48:16 GMT
* Connection #0 to host test.salesforce.com left intact
* Closing connection #0
* SSLv3, TLS alert, Client hello (1):
{"error":"unsupported_grant_type","error_description":"grant type not supported"}
I also tried to go towards login.salesforce.com with the same result.
Cheers, Tobbe

 

Pat PattersonPat Patterson

You need to separate the key/value pairs in the file with '&' rather than <cr> thus:

 

 

grant_type=password&client_id=3MV....snip.....3ZZ&client_secret=33...snip...60&username=abc@xyz.com&password=mypasswordMySecretToken

(with no line break, regardless of how it's actually shown above) and change --data-urlencode to --data.

 

What's happening is that you're sending

 

 

 

grant%5Ftype%3Dpassword%0Aclient%5Fid%3D3MV...

 as the body of the post, while the server is expecting

 

 

grant_type=password&client_id=3MV...

 You can see the difference between --data-urlencode and --data if you use --trace - or --trace-ascii -.

 

 

etntetnt

 

Ok, thanks! That got me a bit further :-)
Next problem: how do I use the acess-token?
I tried the following: 
$ curl -d @salesforce.data -H "Accept: application/json" https://login.salesforce.com/services/oauth2/token                        {"id":"https://login.salesforce.com/id/00DA0...snip...YEIAY",
"issued_at":"1305205072739","instance_url":"https://na7.salesforce.com",
"signature":"8v....snip...FA=",
"access_token":"00DA...snip....6viL"}
So I get the access_token, I follow up with a request to list some objects, making use of the access_token in the Authorization header:
$ curl https://na1.salesforce.com/services/data/v20.0/sobjects/  -H 'Authorization: OAuth 00DA....snip....6viL' -H "X-PrettyPrint:1"
[ {
  "message" : "Session expired or invalid",
  "errorCode" : "INVALID_SESSION_ID"
}]
What am I doing wrong this time?
Cheers, Toby

 

etntetnt

Replying to my own post here...

I found out that the problem was that I didn't use the

instance_url I got back with the access token.

 

I seem to be in the air now, thanks!

 

--Toby

Divya MallDivya Mall
Hi Pat Patterson can u help me that how to implement JWT authorization toke in salesforce. I have some code but am confused about some point like what value will be pass in these key like "iss","aud","sub", and one other thingh is using in my code like certificate key and end pont. 
Divya MallDivya Mall
Hi  Pat Patterson  here is my code

public class JWT_TokenTest
   {
    public class JWTClaimSet
    {
       public string iss {get;set;}
       public string scope {get;set;}
       public string sub {get;set;}
       public string aud {get;set;}
       public Long exp {get;set;}
       public Long iat {get;set;}
    }
       
//@future (callout=true)
 public static void LoginToGoogle()
  {

    Http http = new Http();
    HttpRequest req = new HttpRequest();
    HttpResponse res = new HttpResponse();
    String JWTHeader =  '{"typ":"JWT","alg":"RS256"}';
    String Base64EncodedJWTHeader = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9';
    Long expires_at = math.roundToLong(DateTime.now().addMinutes(40).getTime() / 1000);
    Long issued_at = math.roundToLong(DateTime.now().addSeconds(-2).getTime() / 1000);
    JWTClaimSet JWT = new JWTClaimSet();
    JWT.iss = '??????????????';    
    JWT.sub = '??????????????;
    JWT.aud = 'https://test.salesforce.com';
    JWT.iat = issued_at;
    JWT.exp = expires_at;

    String strJWTJSON = JSON.Serialize(JWT);
    system.debug('Unencoded claimset::'+strJWTJSON);
    Blob ClaimsetBlob = Blob.valueOf(strJWTJSON);
    String Base64EncodedClaimset = EncodingUtil.base64Encode(ClaimsetBlob);
    //Base64EncodedClaimset = PerformPostBase64Encode(Base64EncodedClaimset);
    system.debug('Base64 Encoded Claimset::'+Base64EncodedClaimset);
    // constructing the base64 encoded string to sign it
    string Base64EncodedString = Base64EncodedJWTHeader + '.' + Base64EncodedClaimset;
    // Steps to sign the base64Encoded string
    String algorithmName = 'RSA';
    String key = '????????????????????????????????????';
    Blob privateKey = EncodingUtil.base64Decode(key);
    Blob input = Blob.valueOf(Base64EncodedString);
    //Blob SHA256InputBlob = Crypto.generateDigest('SHA-256',input);
    //Blob Blobsign = Crypto.generateDigest('SHA-256',input);

    Blob Blobsign = Crypto.sign(algorithmName, input , privateKey);

    // The following line is just for debugging and viewing the blob data in signature as string and its not used anywhere
    //String signature = EncodingUtil.urlEncode(EncodingUtil.convertToHex(Blobsign),'UTF-8');
    //system.debug('Unencoded signature ::'+signature);
    
      
    String base64EncodedSignature = EncodingUtil.base64Encode(Blobsign); 
    //base64EncodedSignature = PerformPostBase64Encode(base64EncodedSignature);
    system.debug('Base 64 encoded signature ::'+base64EncodedSignature );
    system.debug('Encoded assertion : ' + Base64EncodedString+'.'+base64EncodedSignature);
    string URLEncodedUTF8GrantType = encodingUtil.urlEncode('urn:ietf:params:oauth:grant-type:jwt-bearer','UTF-8');
    string URLEncodedUTF8Assertion = encodingUtil.urlEncode(Base64EncodedString+'.'+base64EncodedSignature,'UTF-8');              
    system.debug('URLEncodedUTF8GrantType : ' + URLEncodedUTF8GrantType);
    system.debug('URLEncodedUTF8Assertion : ' + URLEncodedUTF8Assertion);
    
    //Making the call out
    req.setEndpoint('?????????????????????????');
    req.setMethod('POST');
    req.setHeader('Content-Type','application/x-www-form-urlencoded');
    req.setBody('grant_type='+URLEncodedUTF8GrantType+'&assertion='+URLEncodedUTF8Assertion);
    res = http.send(req);
    system.debug('Response : ' + res.getBody());
 }

 public static String PerformPostBase64Encode(String s)
  {
    s = s.Replace('+', '-');
    s = s.Replace('/', '_');
    s = s.Split('=')[0]; 
    return s;
  }
}