Secure authorization for your Salesforce orgs: implementing OAuth in Gearset Deploy

Matt Dickens on June 11th 2015


We’ve recently been hearing from our more security-conscious users that they’d like to use OAuth to grant permissions to their organizations – in fact, it’s right near the top of our most requested features in UserVoice.

OAuth has been one of our most requested features

We know that for our users, their Salesforce organizations are at the heart of their businesses and the safety of these organizations is of the utmost importance. With that in mind, the latest release of Gearset Deploy offers OAuth as the default mechanism of connecting to organizations.

What is OAuth?

OAuth is the de facto authorization method used on the web today. Any time you visit a third-party site and sign in with your Google or Facebook account, for example, you’re using OAuth.

Rather than give your credentials over to that third party, the third party redirects you to the service provider’s website where you can choose to grant them permission to access your resources.

Permission to access these resources is given in the form of a revocable token passed from the service provider to the third party on your approval. This token essentially replaces your credentials, but crucially it provides more fine-grained access to your resources than your full account details, and can be easily revoked when you decide to stop using that third-party service. More importantly, if a third party has a security breach and leaks your token, it can be trivially revoked without affecting any other connected applications, and your password remains safe.

Why use OAuth?

Gearset Deploy interacts with the Salesforce Metadata API on behalf of the user. In order to do this, we need to be granted permission to access the resources that API provides. Until now, Gearset Deploy has done this by asking for your username and password, and using those to provide authenticated access to the APIs.

The idea of switching to OAuth is appealing for several reasons:

  1. Gearset Deploy no longer handles your credentials directly – they go between you and Salesforce via a browser
  2. You can revoke the permissions we’ve been granted without having to change your password
  3. The user experience of the login flow will be improved:

Authenticating with OAuth vs. username/password

Implementing OAuth in Gearset Deploy

The flavour of OAuth supported by Salesforce, OAuth 2.0, offers a variety of different authentication flows, each of which corresponds to a different environment or scenario. In Gearset Deploy, we decided to use the user-agent flow, the flow designed to be used in desktop applications:

The flow that the client and server go through as OAuth access is granted

The specifics of implementing the flow are covered in detail in Pat Patterson’s excellent article. That said, we still hit a few snags along the way that are either easily overlooked or not covered in detail elsewhere – hopefully these pointers will come in handy for other developers looking to incorporate the OAuth user-agent flow into their own applications.

Different authorization endpoints

The authorization server’s endpoint URL varies according to whether you’re attempting to grant access to a sandbox, developer or production org. The different URLs are as follows:

  1. Sandboxes: https://login.salesforce.com/services/oauth2/authorize
  2. Developer and production orgs: https://test.salesforce.com/services/oauth2/authorize

Getting this wrong will of course mean that the login attempt will fail. Okay, this one was perhaps a little obvious, but we’re just getting warmed up!

Refresh tokens and custom schemes

Access tokens are only short-lived - they’re valid for the session duration specified in your organization’s configuration. If we relied on access tokens alone, you’d need to re-authorize each time you launched Gearset Deploy.

A better option is for Gearset Deploy to request a refresh token on the first authorization. Where an access token corresponds to a session, a refresh token is much closer to a password – it can be used to log in and request new access tokens. With a refresh token, you only need to go through the authorization process once per org, and of course you can always revoke an application’s access to your resources at any time.

To implement the acquisition of a refresh token in your own application, you’ll need to use a custom scheme. Once you’ve set your scheme name and updated your callback URLs in your Connected App settings accordingly, click Save. Then, on the following screen, make sure you click Continue:

Authenticating with OAuth vs. username/password

If you don’t, your changes won’t be saved.

Changing usernames

When initiating the OAuth user-agent flow, it’s possible to pass the authorization server a login hint – the username for the organization the user would like to grant access to. We use this in Gearset Deploy so it’s clear which two orgs are being compared right from the start. That said, once the user is presented with the authorization page, they’ll have the option to change the username they’re logging in for. It’s therefore important to make sure the application knows the username that the user actually entered when logging in.

Thankfully, among the parameters passed back to the application on successful authorization is the “id” URL. Making a GET request against this URL with a valid access token will return a json object which includes, among other things, a “username” field, which contains the username provided at login.

    
    var getLoginUsername = function(idUrl, acsToken) {
      return return xhr.ajax(idUrl, {
        type: 'GET',
        dataType: 'json',
        beforeSend: function (xhr) {
          xhr.setRequestHeader('Authorization', 'Bearer ' + acsToken);
        }
      }).then(function (data) {
        return data.username;
      });
    };
    

Note that this API unfortunately doesn’t have CORS enabled, so you won’t be able to make this call from a client-side web app. Luckily, it does support JSONP, which provides a helpful workaround. Swapping our GET request for a JSONP request results in the following:

    
    var getLoginUsername = function(idUrl, accessToken) {
        return xhr.ajax({
            url: idUrl + '?oauth_token=' + accessToken + '&format=json',
            dataType: 'jsonp',
            jsonp: 'callback',
        }).then(function (data) {
            return data.username;
        });
    };
    

There are a few more things to note here:

  1. Rather than using the access token in an authorization header, we now pass it as a URL parameter.
  2. We also need to tell the server that we’re expecting JSON, and have jQuery provide the name of the callback we expect it to use in the JSONP response. Setting both the format and the callback ensures that the server will respond with JSONP.
  3. The documentation is a little ambiguous on this point, but all the parameter names must be lowercase.
Valid login hints

In the previous section we talked about login hints. These are passed to the authorization server via a URL parameter:

    
    var getOAuthUrl = function(username, organizationType, sourceOrDest) {
        return getAuthBaseUrl(organizationType) +
            '&client_id=' + clientId +
            '&login_hint=' + encodeURIComponent(username) +
            '&redirect_uri=' + encodeURIComponent(getRedirectUrl());
    };
    

The user-agent is redirected to the resulting URL. Unfortunately, if “username” isn’t of the form of a Salesforce username (e.g. it contains a space), then the redirect will result in a rather unpleasant text-only response from the server, stating that the login hint is invalid. To avoid this, we perform some upfront validation. The definition of a valid login isn’t completely clear, so we’ve used some simple rules that should effectively handle the majority of cases, and more importantly won’t result in any false negatives:

  1. No whitespace
  2. No colons or semicolons
  3. Must be of the form <something>@<something>.<something>

These rules result in the following regex:

    
    /^[^\s:;][email protected][^\s:;]+\.[^\s:;]+$/
    

Validating a username in this way before passing it as a login hint ensures that your users won’t be redirected to an error page if they mistype their login names.

Conclusion

Using OAuth for authorization provides another assurance of the safety of your users’ data. Implementing the flow with Salesforce is largely painless – hopefully now even more so with the tips above.

Ready to get started with Gearset?

Sign up now to start your completely free 30 day trial
try it now