Search code examples
salesforcesalesforce-lightning

Get refresh_token for Connected App in SalesForce


I set up a Connected App, a Python application to programmatically access Salesforce objects on behalf of a user (offline access).

The app works and I can generate an access_token:

$ curl https://login.salesforce.com/services/oauth2/token -d "grant_type=password" -d "client_id=MY_APP_CLIENT_ID" -d "client_secret=MY_APP_SECRET" -d "username=my@user.com" -d "password=my_password"

{"access_token":"00D09000000KDIX!AQoAQNi1234","instance_url":"https://my_instance.salesforce.com","id":"https://login.salesforce.com/id/12345/12345","token_type":"Bearer","issued_at":"1606401330889","signature":"abc/def"}

So far so good.

Now I wanted to switch to a web-server-based flow that uses refresh tokens, but I'm stumped. Where do I get the initial refresh_token to send alongside grant_type=refresh_token? The docs seem to assume I already have a refresh_token and just want to generate another access_token based off that, which is not the case.

What are the actual steps and necessary calls, end-to-end?

List of docs that I found and read, but made me no wiser:


Solution

  • Here's the Salesforce documentation on the Web Server OAuth flow. It runs like this; note that user interaction is involved, so curl by itself won't be enough to demonstrate the flow clearly.

    • You direct the user to the Salesforce login UI, in their web browser, to get yourself an an authorization code:

      https://login.salesforce.com/services/oauth2/authorize?client_id=<YOUR CONNECTED APP CLIENT ID>&redirect_uri=<CALLBACK URL ON YOUR SERVER>&response_type=code
      
    • The user interacts with the authorization page to approve your application.

    • The user is then redirected to the callback URL in your application that you provided in the call (note: this also has to be set up as a callback in your Connected App definition), e.g.,

      https://YOUR_SERVER.com/oauth2/callback?code=<AUTHORIZATION CODE>
      

      Your app can present UI here if you want but the point is to ingest the authorization code.

      The callback URL can be on localhost. That's how, for example, the Salesforce CLI implements authorization of orgs; it spins up a local web server to receive the callback.

    • At this point, the user interaction is done. Your application makes a POST request to Salesforce's /services/oauth2/token endpoint to exchange the authorization code you received for an access token.

      If your Connected App is set up with the refresh_token scope, you'll also get back at that time a refresh token that you can store and use to obtain new access tokens in the future, using the refresh token flow you already identified.

    For a headless application, it can be easier to go straight to JWT (if that's your ultimate goal). I have an example of how to pair JWT authentication with the simple_salesforce Python library. It takes a little bit of initial setup to populate the certificate on the Connected App and assign Preapproved Profiles (or better, Permission Sets), but once the setup is done it's very smooth and never requires any user interaction.