API Authentication: Size Small
Adding authentication to API integrations can be a tough task. Read on to get some advice from a fellow developer on making the job easier.
Join the DZone community and get the full member experience.
Join For FreeI consider myself an API expert — well, in my own mind anyway. I've seen so many different API specifications in my tenure here at Cloud Elements that I can review the API documentation for a cloud service, and within a few minutes, categorize it by our grading style of choice - t-shirt size: S, M, L or XL. Some are really great, easy to understand, quick to realize - size S. Others not so much, screaming out, "XL!" from the moment I first review its docs.
Others are so strange (mainly due to the fact the documentation is terrible), that after about 10 minutes of looking at it, I proceed directly to happy hour to drown my confusion with a margarita (or two). Cheers!
But, with API integrations, my real nemesis is authentication.
Why? Because even though nearly all modern API authentication specifications can be categorized into a few different types, every single one of them has nuances. Even authentication standards, like OAuth 2.0, have different grant types and have components of each that are implementation dependent. Thus, nearly every OAuth 2.0 implementation that I've seen requires custom code or a nuance workaround to implement. Worse, in some cases, you have to invite auth's evil cousin "session timeout" to the party, and that can escalate quickly into trouble.
As a developer who is realizing an integration to a given service, you will need to research and understand these nuances in order to compensate in your code - and estimate its t-shirt size.
Let's step back a bit (#powerphrase) and review the major categories of authentication.
When it comes to authenticating, most mainstream cloud services (e.g. Box, Salesforce, Hubspot, Quickbooks, etc.) use one of: Basic, API Keys, Token, or OAuth — with all the other outliers falling into a catch-all category type of Custom (e.g. AWS Signature).
- Basic Auth: Username and password are passed in the authorization header. The user’s information, <username>:<password> is encoded to a base64 string and transmitted in the request. Thus, to auth as david:p@55w0rd the client would send: Authorization: Basic ZGF2aWQ6cEA1NXcwcmQ=. To ensure security, HTTPS/SSL is required across the entire authentication data cycle as base64 is easily decoded.
- API Keys: An API Key is passed in a request header, a cookie, or a query string (e.g. GET /contacts?api_key=abcd1234). API key-based auth uses one or more keys that the client and server have agreed upon. Often they are automatically/randomly generated based on the client’s specific information (e.g. IP address) or they can be provided from the endpoint service directly. They are only considered secure if used along with HTTPS/SSL encryption.
- Token/Bearer: Authentication is provided to the “bearer” using a cryptic token (string). The token is provided by the server and the client sends it in the authorization header, ie. Authorization: Bearer <token>. This, once again, is only secure if used over HTTPS/SSL encryption.
- OAuth 2.0: Used by many modern cloud-based services. It allows for a client to gain access to protected server resources without having to share user credentials. Passwords are never passed from server to server with the OAuth framework. Think of it as the client application delegates the responsibilities of authentication to some other service instead of managing them on its own. Before the authentication process can start, OAuth requires that the client application register with the authorization service. It requires basic information such as name, website, and callback URL (HTTPS only) which is used to redirect the user once they have allowed access to their data. Once registered, the endpoint service provides a set of credentials: a client_id and a client_secret. The client secret must be kept confidential, otherwise, security is compromised.
OAuth 2.0 flow consists of the following steps:
- The client application makes a request to the authorization server at endpoint service, which will respond by displaying a login and authorization UI page to the user - requesting permission to share specific data assets stored within the endpoint service.
- Once approved by the user, an authorization grant is sent back to the requesting application which contains an authorization code.
- The requesting application then uses the authorization grant and authorization code to request an access token from the endpoints authorization server.
- The authorization server within the endpoint service then provides an access token that is specifically tailored for the requesting user - setting what level of access is granted (scope) that was authorized by the user in step 1.
- Next, the requesting application can use the access token to make requests to the endpoint service to retrieve data assets authorized by the user.
What are the OAuth 2.0 nuances that you have to compensate for in your application's code? How the authorization server shares the access token with the resource server is one. Also, refresh tokens and access token expiration times are implementation details that can vary across services.
Now that we are all experts on the different categories of API authentication, you can sympathize the next time you are in a sprint planning meeting and your developer's t-shirt estimates for adding the authentication portion of your integrations is larger in size than the one that the developer is wearing.
Small t-shirt sizes for the win.
There is a better way, with Cloud Elements, we've built authentication into ALL of our 150+ Elements. We've standardized to either one or two REST API calls, depending on the authentication type in play.
Our Elements account for the nuances with authentication, regardless of the endpoint's authentication type and specs. For example, refresh tokens? Session timeouts? Handled automatically by the Element. We've done the hard work for you, leveling the authentication playing field. Making your t-shirt size estimates more consistent.
Our Elements not only reduce the development effort required for your integrations, they go way beyond that. In fact, once authenticated, all that is needed to access your customer's endpoint data is a Cloud Elements granted instance token - kinda like the access token in the OAuth 2.0 flow. Example:
curl -X GET "https://api.cloud-elements.com/elements/api-v2/ping" -H "accept: application/json" -H "Authorization: User <secret>, Organization <secret>, Element <instance token> "
How do you get the Element Instance Token? It is the result of using the built-in authentication API resources provided by the Element.
For endpoints that are authenticated via OAuth (e.g. SFDC how2 video ), the path follows the flow scenario in the blue below:
- The first call is made to
GET /elements/{keyOrId}/oauth/url
- which passes in the Client ID, Client Secret, and Callback URL (obtained from the registered app - see above). - The user authenticates via the UI provided by the endpoint's authorization server. Once authenticated, the authorization code is returned.
- The second call is made to
POST /instances
to create a new credentialled Element instance - passing in the authorization code. If successful, a unique Element instance token is returned, which is used with all subsequent calls to get or post data to the user's endpoint service, in this case, Salesforce.com. The level of access depends on the authorization scope as determined during the first step.
For all other (non-OAuth) endpoints, the path is the orange flow scenario in the above:
- The user enters their credentials based on the authentication type: key(s), username and password, or token(s).
- The call is made to
POST/instances
to create a new credentialled Element instance.
Want more goodness? More t-shirt size reducing things about the POST /instances
API resource call:
- For OAuth endpoints, the Element will encrypt and store the access and refresh tokens, and use the refresh token when needed to automatically refresh the access token set. Thus, your developers don't have to build the framework to do this - including managing session timers!
- Given that the JSON body payload for the
POST/instances
will vary by endpoint - Cloud Elements has already figured those nuances out, tested them, added the necessary code to the Element to compensate for the endpoint's inevitable authentication nuances, and mapped out a JSON payload sample — just cut and paste from the example provided. - Once the unique instance token is retrieved, you only need to store it in your application - usually in a table where you keep your customer's information - just store the instance token and the name of the endpoint (e.g. sfdc). When you include it in subsequent API calls, our platform will use it to determine what endpoint service it is associated with and whose credentials to use.
Not a believer yet?
No problem, it can take an example to see just what I mean when I say, "We do the hard work for you." So, here is an example of taking a size L authorization implementation and reducing it to a size S using Cloud Elements:

Scenario 1: Via Native Bullhorn API
Note: The access token in the response is only valid for 10 minutes, then you will need to make an additional call with the refresh token to retrieve another pair of tokens.
- Go to the authorization page with registered OAuth information to login in the client's user, i.e. https://auth.bullhornstaffing.com/oauth/authorize?client_id={client_id}&response_type=code&redirect_uri={optional redirect_uri}
- Log into the application via the Auth UI and prompt permission to share specific data assets stored within the endpoint service. Once approved by the user, an authorization grant is sent back to the requesting application which contains an authorization code.
- The requesting application then uses the authorization grant and authorization code to request an access token from the endpoints authorization server, i.e. POST https://auth.bullhornstaffing.com/oauth/token?grant_type=authorization_code&code={auth_code}&client_id={client_id}&client_secret={client_secret} The authorization server within the endpoint service then provides an access token and a refresh token that is specifically tailored for the requesting user - setting what level of access is granted (scope) that was authorized by the user in step 2.
Note: In Bullhorn's authorization, both the access token and the session token only last 10 minutes. The client needs to implement a scheduled job or lazy refresh to ensure that our tokens are not expired.
4. With the access token, you need to make a call to the login API to retrieve the session token, i.e. POSThttps://rest.bullhornstaffing.com/rest-services/login?version=2.0&access_token={xxxxxxxx}
5. With the session token, you can make requests to the endpoint service to retrieve data assets authorized by the user.
6. Once 10 minutes elapses, we encounter an error in trying to make a request to the endpoint service to retrieve data asserts, 403 Expired session token error.
7. With the refresh_token from step 4, we will make a refresh call to get a new pair of access and refresh tokens to use for the next 10 minutes, i.e POSThttps://auth.bullhornstaffing.com/oauth/token?grant_type=refresh_token&refresh_token={refresh_token}&client_id={client_id}&client_secret={client_secret}
NOTE: Repeat steps 6-9 every 10 minutes Click here for the Bullhorn Auth reference.
8. With the new access token, you need to make a call to the login API to retrieve the session token (example in 4).
9. With the new session token, you can make requests to the endpoint service to retrieve data assets authorized by the user.
Scenario 2: Via Cloud Elements API
Note: Cloud Elements switched to specifying a 12-hour session length due to experiencing refresh issues with BullHorn's default session setting of 10 minutes. There is an undocumented BullHorn parameter setting for session length.
- Get Elements OAuth Information http://api.cloud-elements/elements/api-v2/elements/bullhorn/oauth/url?apiKey=insert_bullhorn_client_id&apiSecret=insert_bullhorn_client_secret&callbackUrl=www.mycoolapp.com/auth
- The result of this API invocation is an OAuth redirect URL from the endpoint. Your application should now redirect to this URL, which in turn will present the OAuth authentication and authorization page to the user. When the provided callback URL is executed, a code value will be returned, which is required for the Create Instance API.
- Create an Instance: to provision a Bullhorn Element instance, use the /instances API: https://api.cloud-elements.com/elements/api-v2/instances win a body payload of:
{ "element": { "key": "bullhorn" }, "providerData": { "code": "Code on Return the URL" }, "configuration": { "oauth.api.key": "<INSERT_BULLHORN_CLIENT_ID>", "oauth.api.secret": "<INSERT_BULLHORN_CLIENT_SECRET>", "oauth.callback.url": "https://www.mycoolapp.com/auth" }, "tags": [ "<INSERT_TAGS>" ], "name": "<INSERT_INSTANCE_NAME>" }
3. Store the returned instance token to make subsequent API resource calls to post and/or retrieve protected data in BullHorn.
Click here for the Cloud Elements BullHorn Element reference.
Are you ready to reduce your t-shirt size? Take it to the next step, call my bluff with the above and try it out - here is a How2 doc with videos that will step you through not only the aspects above, but also how to put all the other aspects of your integrations on a Hollywood diet. Soon, all your integrations will be a size small.
Be good, aloha.
Published at DZone with permission of David Honan, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments