[SalesForce] Oauth- getting refresh token

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

Best Answer

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