Authentication in HTTP integrations
OAuth flow
OAuth (Open Authorization) is an open standard framework for authentication that allows safely sharing access to resources. Usually OAuth flows are experienced with end-users in web, mobile or desktop applications for getting access with 3rd party authentication provider but they surely are common in the world of enterprise integrations as well. The OAuth standard has evolved to its current version 2.0 and provides a set of suggested authentication flows that are implemented for specific purposes. Now we'll focus on the OAuth version 2.0 (OAuth2) flow that is suitable for common enterprise integration patterns, called the Client Credentials Flow.
In Client Credentials Flow the client, say Frends, passes ClientID and ClientSecret to the authorization server or endpoint for receiving tokens which enable access to corresponding resources. Usually the the authorization server provides an AccessToken for a limited time access and a RefreshToken for getting new tokens in a longer time period. The flow is described in the picture below.
Depending on the OAuth2 Client Credentials flow implementation, the payload and required credentials may vary but fortunately these are usually described in the API documentation.
Let's have a look at an example of using a Client Credentials Flow with Frends for an imaginary GraphQL API that has following properties:
AccessToken with expiration time of 600 seconds and RefreshToken with expiration time of 30 days is retrieved from imaginary.com/api/login with ClientID and ClientSecret in JSON payload.
A new AccessToken and RefreshToken can be requested by using POST with payload {"refreshToken": "your_refresh_token"} to endpoint imaginary.com/api/login/refresh
The GraphQL queries can be posted to endpoint imaginary.com/api/graphql with HTTP header Authorization: Bearer your_access_token
As it would be beneficial to temporarily store these tokens and always provide a valid AccessToken, we should first build a reusable Subprocess for the handling of these tokens. By storing these tokens with Shared State Task functionality, we gain frequent usage performance compared to always requesting a new AccessToken per GraphQL query as the Shared State Task's database queries under the hood are much faster than HTTP requests to the authorization server or endpoint. Additionally, we avoid unnecessary traffic to the authorization server and many API service providers expect the consumers to reuse AccessTokens and RefreshTokens as much as possible.
One approach is to build a following Subprocess which would called whenever a Process requires an AccessToken for the GraphQL query.
The first Shared State Task would try to get the AccessToken with Throw an exception on failure parameter not toggled. The Exclusive Decision after that would then evaluate whether the AccessToken was available with #result[try get acess_token].Success expression and with evaluation to true, the Subprocess would return the Shared State Task result containing property Value for the actual AccessToken. When the AccessToken could not be retrieved, the Exclusive Decision would proceed to a Shared State Task that tries to retrieve a RefreshToken in a similar way than with the AccessToken earlier. Depending on the next Exclusive Decision Expression evaluation, the Subprocess would use RestRequest Task with the retrieved RefreshToken to get new tokens or use RestRequest Task with the Client Credentials to request new tokens altogether. The Client Credentials of ClientID and ClientSecret would be stored in Frends Environment Variables and referenced in the RestRequest Task. The results from both branches would join in Code element Assign Body for assigning #var.Body with the HTTP responses containing new tokens. Finally, the RefreshToken and AccessToken would be added or updated with Shared State Tasks ending the Subprocess with result containing property Value that is the valid AccessToken. In the calling Subprocess or Process, the correct reference for AccessToken would eventually be like #result[this subprocess name].Value.
Now that we can retrieve the AccessToken, we can call the GraphQL API with HTTP header Authorization: Bearer #{{#result[this subprocess name].Value}}.
This type of OAuth2 flow is very common in REST and GraphQL APIs.
API keys
API keys are also fairly common practice of authentication but do not provide such security as OAuth2 flows due to the simplicity of API key authentication. API keys are pieces of strings commonly passed in a specific HTTP header of a request and anyone using those keys could get the access to resources that are granted for the specific key. An API key HTTP header could look like X-API-KEY: abcdefg098765. The documentation of the API should elaborate on how the API keys should be used and the implementation with Frends HTTP Tasks is fairly simple.
Let's look at an example of a REST API that represents a dog as a resource and authentication is handled with an API key. The API key containing a random string needs to passed in a HTTP header named X-API-KEY. The API returns data in JSON format.
In the implementation we would use RestRequest Task and configure the parameters like in the following picture. The API key itself would be referenced from Environment Variables and treated as a secret.
Remember to check the documentation of the consumable API for the correct HTTP header name as they do vary.
Basic Authentication
Basic Authentication is very similar to API keys as the authentication method is based on a secret in HTTP header. In Basic Auth the header is in form Authorization: Basic "base64encode(username:password)" where the username and password are joined with single colon (:) and base64 encoded.
Basic Auth can be implemented in two ways with Frends; form the Authorization header yourself or use HTTP request Tasks' Authentication option Basic. These both result in a correct Basic Auth HTTP header for the HTTP request but using the built-in Task Basic Authentication surely is more simple.
In the following examples these both approaches have been implemented with same references to the Environment Variables for username and password.
Using the built in Basic Authentication parameters:
Without using the Task options and forming the HTTP header manually:
Mutual authentication with certificates
In an HTTP request the client and the server can use mutual authentication with certificates which means that the client also provides a certificate for authenticating to the server. This can be achieved by using the Frends HTTP Tasks' Authentication option ClientCertificate.
The following screen capture from a Task Options tab shows the necessary parameters for ClientCertificate authentication.
The developer must choose from where to get the public key certificate for a certain HTTP server in that specific HTTP request with Client certificate source (CertificateStore/File/String) as the certificates can be stored in Frends Agent Certificate store, in a file on a drive or in a string format. The following parameters depend on the selection of Client certificate source. When CertificateStore is used, the developer must set Certificate thumbprint which selects the correct certificate from the store. With File as the source, the Client certificate file path needs to be configured with the path on Frends Agent drive for the pfx (pkcs12) file. If String is used for the source, the client certificate file needs to be converted to base64 representation of the byte array. Both File and String also require the Client certificate key phrase for accessing the certificate data.
The next article is Introduction to Structured Query Language (SQL)