1

I've been banging my head against the wall trying to get a refresh token out of SFDC.

I'm currently able to authenticate via Oauth and can make queries. I'm trying to test for when a token expires by requesting a refresh token.

def get_refresh_token(customer):
    consumer_key = "my_consumer_key"
    consumer_secret = "my_secret"
    access_token_url = 'https://login.salesforce.com/services/oauth2/token'
    data = {
                'grant_type': 'refresh_token',
                'refresh_token' : 'refresh_token',
                'client_id' : consumer_key,
                'client_secret' : consumer_secret,
            }
    headers = {
                'content-type': 'application/x-www-form-urlencoded'
            }

    req = requests.post(access_token_url, data=data, headers=headers)
    response = req.json()
    return response

Unfortunately, I keep getting the response {u'error_description': u'expired access/refresh token', u'error': u'invalid_grant'}

That said, the original token has not expired so my thinking is that I can't request a refresh token if the original is still valid. Assuming that's the case: How do I go about expiring a token without revoking it?

I can revoke tokens without issue but expiring them is a different matter. If I go to session settings my timeout is set to 15 mins in the org of the user authenticating via Oauth.

The alternative is that my post is incorrect in some way. Any help would be much appreciated

below is an example of the response I'm getting from sfdc when I request a token:

{
    u'access_token': u'00skljfdsksdfjklskjdf_protected_WySu8ko0pFcX3vLSOp7ww3qJ8VGADsue', 
    u'token_type': u'Bearer', 
    u'signature': u'Y+aiNE8isd_protected_+i9QRfA=', 
    u'issued_at': u'1478737367806', 
    u'scope': u'refresh_token api', 
    u'instance_url': 
    u'https://sifdata-test.my.salesforce.com', 
    u'id': 
    u'https://login.salesforce.com/id/00D410000_protected_AU/005410_protected_AC', 
    u'refresh_token': u'5Aep861HDR3iASSX_protected_JIgHyRWn.6oH6XKva0f76V5AxRE7YhZygZQg'
}

note: The code below to obtain an authorization and refresh token works without issue.

def callback(request):
    code = request.GET['code']
    consumer_key = "my_consumer_key"
    consumer_secret = "my_secret"
    redirect_uri = 'http://localhost:8000/callback'
    access_token_url = 'https://login.salesforce.com/services/oauth2/token'
    data = {
                'grant_type': 'authorization_code',
                'redirect_uri': redirect_uri,
                'code': code,
                'client_id' : consumer_key,
                'client_secret' : consumer_secret
            }
    headers = {
                'content-type': 'application/x-www-form-urlencoded'
            }

    req = requests.post(access_token_url, data=data, headers=headers)

    response = req.json()
    return response
3

You posted in your code that you are setting the value of refresh_token to refresh_token. It needs to be the refresh token you got in the access token response (5Aep861HDR3iASSX_protected_JIgHyRWn.6oH6XKva0f76V5AxRE7YhZygZQg). not sure if you replaced the actual refresh token with the words "refresh_token" but since you had no problem posting it later in your question just making sure

You can request a new access token even if the access token is not expired but that is not the best practice.

best practice is to:

  1. Make resource request
  2. If fails, use refresh token to get new access token

In order to get a refresh token returned in the response (When initially requesting an access token) you must include refresh_token in the scope and the connected app must allow offline access. I do not see a scope in your code

The request for the Authorization code would look like this:

https://login.salesforce.com/services/oauth2/authorize?response_type=code&client_id=xxx&redirect_uri=xxx&prompt=consent&scope=' + encodingUtil.URLEncode('full refresh_token','UTF-8');

The request for the access token would then look like:

https://login.salesforce.com/services/oauth2/token?code=xxx&grant_type=authorization_code&client_id=xxx&client_secret=xxx&redirect_uri=xxx

to revoke you would do a get to:

'/services/oauth2/revoke?token=xxx'

To get a new access token using the refresh token:

https://login.salesforce.com/services/oauth2/token?grant_type=refresh_token&client_id=xxxxx'&client_secret=xxx&refresh_token=xxx

Here is a full example of a visualforce implementation of oAuth to compare to:

Oauth Implementation

  • @sfdcfox - Thanks for catching that. Was it only in the first line? updated it if so – Eric Nov 9 '16 at 23:46
  • I included an example of the response I'm getting from SFDC when I request an access token, it includes both an access_token as well as a refresh_token and the scope looks correct. It's currently returning refresh_token. Do I need to revoke the token before I can request a refresh? – shartshooter Nov 10 '16 at 0:29
  • @user3195487 No you do not need to revoke the access token before using the refresh token - Mainly because the access token SHOULD be expired before you request a new one. Regardless, you can request a new access token any time using the refresh token if you choose to not follow standard practices – Eric Nov 10 '16 at 0:47
  • @user3195487 - Hopefully this is not exactly what you are sending &refresh_token=refresh_token as in your code. I would assume that you just replaced the actual value but if not the value needs to be the refresh token – Eric Nov 10 '16 at 0:50
  • it's not, that's just there to hide the real thing. – shartshooter Nov 10 '16 at 0:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.