1

I am new to Salesforce and my current goal is to ensure that my application never is prompted to give user credentials when making an API call. I see that this is the point of the refresh token, but I'm having some difficulties understanding its workflow:

After reading the documentation, I was under the impression that the refresh access token was something which you generate and store one time. After that, instead of calling services/oauth2/authorize to get a new access_token, you instead pass the stored refresh_token and you no longer need username/password credentials.

This does not seem to be the case. I get the following error when I try to generate a new access_token using my stored refresh_token:

 {"error":"invalid_grant","error_description":"token validity expired"}

I did find the setting in the Salesforce UI where you can set the refresh token to expire immediately or after X amount of days, but it will always expire.

How then does the the refresh token workflow work to ensure that your application never needs to log into Salesforce, minus the first time connection?

EDIT: This is how I grabbed the refresh_token:

/**
* Retrieve the refresh token from the API.
*
* @return string
*   The refresh token.
*/
public function getRefreshToken() {
  try {
    $response = $this->client->request('POST', $this->tokenUrl, [
      'query' => [
        'grant_type' => 'authorization_code',
        'client_id' => $this->clientId,
        'client_secret' => $this->clientSecret,
        'redirect_uri' => $this->redirectUrl,
        'code' => $this->authorizationCode,
      ]
    ]);
    $response_data = json_decode($response->getBody()->getContents());
  }
  catch (RequestException $e) {
    echo $e->getMessage();
  }

  return $response_data->refresh_token;
 }

I am using this to refresh and reset the access token, which is then used for future calls:

/**
* Refresh the access token using the server side refresh token.
 * 
 * @return $this
 */
protected function refreshAccessToken() {
  try {
    $response = $this->client->request('POST', $this->tokenUrl, [
      'query' => [
        'grant_type' => 'refresh_token',
        'refresh_token' => $this->refreshToken,
        'client_id' => $this->clientId,
        'client_secret' => $this->clientSecret,
      ]
    ]);
    $response_data = json_decode($response->getBody()->getContents());  
  }
  catch (RequestException $e) {
    echo $e->getMessage();
  }


  $this->access_token = $response_data->access_token;
  return $this;
}
  • Can you show the details of how you are obtaining your refresh token and access tokens? – David Reed Nov 8 '18 at 3:47
  • @DavidReed I have added those details above. – user1015214 Nov 8 '18 at 15:08
2

There's a number of things you need to do to get everything just right. Under Setup > Create > Apps, go down to your connected app, and verify it has the "refresh_token" scope enabled. Next, check Setup > Manage Apps > Connected Apps OAuth Usage and make sure your app is not Blocked. After that, go to Setup > Manage Apps > Connected Apps, and make sure the Refresh Token Policy is "valid until revoked" and Permitted Users is "All Users May Self-Authorize".

Finally, there's the connection itself. Make sure you're using the Web-Server Flow or User-Client flow. The username-password flow will not provide a refresh token. If you're using the Web-Server flow, please note that there is an interim step that involves a "code." This code is not your refresh token, you need to take one more step. Check the documentation links above for details.

Also, please note that you are limited to 5 refresh tokens per application per user. If you've been testing a lot, you might accidentally be using an old token. Try revoking all your existing sessions (found on your user detail or connected apps oauth usage screen), and then try again. Always remember to log out or revoke your session when you're done using it. This isn't just from a security perspective, it can also lead to situations where you're accidentally wiping out old sessions. Finally, as a developer who has done this at least once, make sure you're not accidentally using the access token as a refresh token.

  • Thanks for the detailed explanation! I just changed the policy to 'valid until revoked', and I was already using the Web-Server flow. But I'd like to understand the 5 refresh token concept and the idea of revoking them. Shouldn't I now just be able to revoke all, request a new one, and then never need more? What is the scenario that someone would ever need more than one refresh token at all? – user1015214 Nov 8 '18 at 15:02
  • @user1015214 Typically, one refresh token will be on just one device. If you have a phone, tablet, and desktop, that might be 3 refresh tokens. Salesforce sets the limit to five active sessions by restricting you to five concurrent refresh tokens. Also, sometimes tokens get "lost" (cookies deleted, client databases purged, etc). You would rarely want to revoke tokens you don't create, but you should definitely provide a log out option so that session's token can be revoked and not count against the five token limit. – sfdcfox Nov 8 '18 at 15:15
  • In my case, I'm not sure that it makes sense to ever revoke a refresh token. I'm using my App for my site (which is basically acting as a single user) to be able to do a lookup on relevant data and report back to the site. I'm not storing the refresh token as a way to keep any particular user 'logged in' persay, but to allow the site to do lookups, initiated by any user using the site (logged in or not). I am storing the refresh token on the server side, so, if I would revoke it, the site would stop working. Does that make sense? – user1015214 Nov 8 '18 at 15:22
  • 1
    @user1015214 There's no hard requirement that a token ever be revoked, but you still might need to as a matter of security, for example, if someone gained console access to your server. Even so, many apps do need the ability to revoke a token, even if your specific use case does not. For example, if you were in a public library and logged in to an app to do stuff in Salesforce, imagine if you couldn't log out... If you don't need to revoke the token, then don't revoke the token. Different apps have different security requirements. – sfdcfox Nov 8 '18 at 15:31

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.