# OAuth2 Authentication

{% hint style="warning" %}
**Warning:**

The steps provided in this explanation are based on Linx before release 6.4.0.

In *Linx 6.4.0 and higher* there is a **Return** function in the Linx plugin that must be used for setting the value of a function's result. The SetValue function and `$.Result` cannot be used for this purpose anymore.

Go [here](https://docs.linx.software/reference/plugins/linx/content/return) for details of the Return function.
{% endhint %}

OAuth2 enables third-party applications, such as a Linx Solution, to obtain access to protected resources (e.g. account details, documents, etc.) from a host (e.g. Microsoft, Facebook, GitHub, etc.), with a user's permission.

This is achieved by orchestrating an approval interaction between the resource owner, the host, and the third-party application. This guide will show you how.

***

## Introduction

The [OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749) enables third-party applications such as a Linx Solution to obtain access to protected resources (i.e. account details, documents, etc.) from a host (e.g. Microsoft, Facebook, GitHub, etc.) with permission from a resource owner (user). This is achieved by orchestrating an approval interaction between the resource owner, the host, and the third-party application.

The authorization action by the resource owner (user) typically happens only once, and following that there is a cycle of client-to-server re-authorization that ‘refreshes’ the application’s authentication credentials.

The advantage of using the OAuth 2.0 flow is that a resource owner’s personal credentials (i.e. password and username) are never shared, and the resource owner does not have to pre-configure anything on their side, only action the authorization when requested.

In order to implement the [OAuth 2.0 - Authorization Code Grant](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1) flow in Linx, a combination of hosting and consuming REST web services will be used. This will allow resource owners to authorize your application to access their resources without any manual intervention.

The below sections are covered in this guide:

* Authorization Code Grant flow overview
* Building a basic generic authenticator with Linx
  * Registering your application
  * Authorization Request
  * Exchange Authorization Code for an Access Token
  * Returning the access token
  * Making a request with the access token
* Automating the whole flow
  * Automatically redirect users to the Authorization URI
  * Automatically request tokens after authorization
  * Customizing the response
* Storing and retrieving the access token

{% hint style="info" %}
**Note:**\
The terms 'Process' and 'Custom Type' have been deprecated and have been replaced with 'Function' and 'Type' respectively. More details [here](https://linx.software/docs/5/releasenotes/linx/5.20.2.0/).
{% endhint %}

## Authorization Code Grant flow

The below diagram illustrates the OAuth 2.0 - Authorization Code Grant:

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fgit-blob-d316b54525b194abe9aea04478122d577d768738%2Foauth_authcodegrant.png?alt=media" alt="Code Grant"><figcaption></figcaption></figure></div>

* **(A)**: The flow is initiated by the resource owner (user) triggering the flow from the user-agent (browser) - this is done by the user browsing to a URL which will execute a request against a Linx API (client).

  The API will respond with an authorization URL and will direct the resource owner’s user-agent (browser) to the authorization endpoint. The client includes its client identifier, requested scope, local state, and a redirection URI to which the authorization server will send the user-agent back once access is granted (or denied).
* **(B)**: The resource owner then authorizes (or denies) the client’s access request via the user-agent (browser).
* **(C)**: The authorization server redirects the user-agent back to the client using the redirection URI provided earlier (in the request or during client registration).

  The Redirect URL will be a Linx API endpoint which will then receive the below details. The redirection URI includes an authorization code and any local state provided by the client earlier.
* **(D)**: The client requests an access token from the authorization server’s token endpoint by including the authorization code received in the previous step. When making the request, the client authenticates with the authorization server. The client includes the redirection URI used to obtain the authorization code for verification.
* **(E)**: The authorization server authenticates the client, validates the authorization code, and ensures that the redirection URI received matches the URI used to redirect the client in step (C). If valid, the authorization server responds back with an access token and, optionally, a refresh token.

***

## Building a basic generic authenticator with Linx

In the following sections, we will be covering how to build an automated authenticator that will allow you to connect to any API via OAuth 2.0.

The resulting user flow will look like the below:

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fgit-blob-84fe4e02d42e3faa3936a578645ccfa10f9eeb23%2Foauth_genericauthenticator.gif?alt=media" alt="authenticator"><figcaption></figcaption></figure></div>

The following sample solution provides a "basic" template for implementing the OAuth 2.0 flow in Linx:

[GenericOAuth2Authenticator.zip](https://community.linx.software/community/uploads/short-url/yZHORn1au6ObqlQXbGN7ggvvByY.zip)

### Registering your application

In this tutorial, we will be using the example of connecting to [GitHub](https://docs.github.com/en/rest/overview/resources-in-the-rest-api).

Before connecting to your target API, you need to gather the below details:

* **Client credentials**: The Client ID and Client Secret (sometimes referred to as App ID/App Secret). These are obtained by registering an application on the provider’s website or developer portal.
* **Endpoint URIs**: The Authorization and Token generation URIs should be available in the official documentation of the platform you are trying to connect to.
* **Redirection URI**: The redirect URI or **Callback URL** is used to return the Access Token. This is set when registering the application and can be changed at a later stage.

In order to generate the above information, you need to [register your App](https://github.com/login?return_to=https%3A%2F%2Fgithub.com%2Fsettings%2Fdevelopers) on the provider's website/developer portal.

{% hint style="info" %}
**Note:**\
For GitHub, ensure you register an "OAuth application".
{% endhint %}

After you have registered your application, you should have:

* Client ID
* Client Secret
* Redirect URI

Example of registering a new application (GitHub):

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fgit-blob-6f9eef3f1ee8cf1e9c12fd1de9a5b1877add1101%2Foauth_registernew.png?alt=media" alt="new registration"><figcaption></figcaption></figure></div>

Application’s (client) identifiers (GitHub):

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fgit-blob-b77cd68554c21e2da1f114ceaf5462754c4a2a59%2Foauth_appidentifiers.png?alt=media" alt="application identifiers"><figcaption></figcaption></figure></div>

{% hint style="info" %}
**Important:**\
Ensure you generate a client secret and store it somewhere for later.
{% endhint %}

### Authorization Request

The [Authorization Request](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1) involves the client (Linx) constructing a URI that points to the target host authorization endpoint. The resource owner (user) is directed to this URI followed by the user-agent (web browser). Following this, he/she will authorize the application to have access to the protected resource (typically indicated by the scope parameter).

The Authorization URI is in the following format:

`{host}{authorize-path}?response_type={response-type}&client_id={client-id}&scope={scope}&state={state}&redirect_uri={redirect-uri}`

| Name                   | Required    | Description                                                                                                             | Example                             |
| ---------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------- | ----------------------------------- |
| `{host}`               | Required    | Host server                                                                                                             | `https://github.com`                |
| `{authorize-endpoint}` | Required    | Authorization endpoint for Host server                                                                                  | `/login/oauth/authorize`            |
| `{response_type}`      | Required    | Value must be set to *code*                                                                                             | `code`                              |
| `{client_id}`          | Required    | Client identifier generated on target system application registration                                                   | `8527f38c3c4a0d8726fa`              |
| `{scope}`              | Optional    | Optional list of access scopes, depending on the host                                                                   | `repo, user`                        |
| `{state}`              | Recommended | Random string of characters used to verify the response from the server and prevent cross-site forgery                  | `QjKc`                              |
| `{redirect_uri}`       | Optional    | Redirect URI where the server will send a request to containing the authorization code after a successful authorization | `http://localhost:8080/oauth/token` |

The built-up URI will be similar to the below:

`https://github.com/login/oauth/authorize?response_type=code&client_id=xxxxxxxx&scope=repo,user&state=QjKc&redirect_uri=http://localhost:8080/oauth/token`

The Authorization URI will need to be browsed to every time you want to re-initiate the token generation flow. You can save this URI somewhere for quick reference; however, during development, you may need to remove and re-add apps, and therefore generate new client identifiers. To make life easier in such cases, we are going to get Linx to build up the Authorization URI for us.

This will be a Function that takes in a number of client credentials that we generated in the previous step.

The Function will return a single output which will contain that input value built up using string manipulations. This way, whenever the client identifiers change, we can update a single value in our Linx Solution and regenerate the Authorization URI.

To create a generic Function that will generate and return the Authorization URI:

1. Create a new **Solution**.
2. Add a **Function** and rename it to GenerateAuthorizationUri.
3. Configure the **GenerateAuthorizationUri** Function to have the below `$.Input` values:
   * host
   * authorize\_endpoint
   * response\_type
   * client\_id
   * scope
   * state
   * redirect\_uri
4. Configure the **GenerateAuthorizationUri** Function to have a single `$.Result` with the Name of uri.
5. Add a **SetValue** to the process. This will be used to build up a string combining the inputs into the proper format.
6. For the **Target**, reference `$.Result.uri`.
7. For the **Source**, use an expression to build up the query values of the URI along with the input client credentials: `=$.Input.host + $.Input.authorize_endpoint + "?" + "response_type=" + $.Input.response_type + "&client_id=" + $.Input.client_id + "&scope=" + $.Input.scope + "&state=" + $.Input.state + "&redirect_uri=" + $.Input.redirect_uri`
8. Debug the **GenerateAuthorizationUri** process.
9. When the Function completes, take a look at the Debug Values panel and take specific note of the `$.Result.uri` value.

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fgit-blob-3bed0a4e79a577e44f731d47801a4f004419a29b%2Foauth_debugvalues.png?alt=media" alt="uri value"><figcaption></figcaption></figure></div>

10. Copy the URI and paste it in your web browser.
11. You should be prompted to authorize your application:

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fgit-blob-e3ef3fa74e342a90042f543f6db3bbcf2975f3d8%2Foauth_authorizeapplication.png?alt=media" alt="authorize app"><figcaption></figcaption></figure></div>

12. Once you’ve granted access, your user-agent (browser) should redirect you to the **Redirect URI** that you set earlier, i.e. `http://localhost:8080/oauth/token`.
13. The URL will contain two query parameters:

* **code**: Authorization code returned from Authorization Server to use for generating tokens.
* **state**: Random string to link flow requests.

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fgit-blob-95eb8c3e899e64b542ac35fe5e70d47560a9775f%2Foauth_authorizeapplication2.png?alt=media" alt="authorize app"><figcaption></figcaption></figure></div>

For the next section, we will be using the value of the code parameter. The state parameter will be touched on later.

#### Exchange Authorization Code for an Access Token <a href="#exchange-authorization-code-for-an-access-token" id="exchange-authorization-code-for-an-access-token"></a>

After the [Authorization Response](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.2) has been received, the code parameter can be [exchanged](https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3) with the host for an access token.

This typically involves making a POST request to the token issuing endpoint, with a Content-Type of URL encoded , submitting the identifiers below as the list of URL encoded content parameters.

`POST https://github.com/login/oauth/access_token? client_id={client-id} &redirect_uri={redirect-uri} &client_secret={client-secret} &code={authorization-code} &state={state}`

If successful, a (200) OK response will be returned containing a JSON string containing access token related data in varying formats similiar to the below:

```json
{
      "access_token": "EAAkXlZBnWqyEBAIaOnwmOph34B3y9ooVBSPiMB07ut7FQcHFAXDFkwo9UcVihyiZB4DhcFqjrtHam",
      "token_type": "bearer",
      "expires_in": 5178671
}
```

\
`{ "access_token": "EAAkXlZBnWqyEBAIaOnwmOph34B3y9ooVBSPiMB07ut7FQcHFAXDFkwo9UcVihyiZB4DhcFqjrtHam", "token_type": "bearer", "expires_in": 5178671 }`

The value contained in the access\_token field will then be submitted in the Authorization header with the value of Bearer {access\_token}.

1. Add a new Function and rename it ExchangeCodeForToken.
2. Add the following $.Input parameters:

   * host
   * token\_endpoint
   * client\_id
   * client\_secret
   * state
   * redirect\_uri
   * code

   Configure the default values of these fields like before, you will need to generate a Client Secret if you haven’t done so already.

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FVdwOVMgYpBeuHuGO2ZLv%2Foauth_configuredefaultvalues.png?alt=media&#x26;token=1986b326-e362-4fd1-ab2a-c34033620a00" alt=""><figcaption></figcaption></figure></div>

3. Add a CallRESTEndpoint to the ExchangeCodeForToken process.
4. Set the URL with an expression which will combine the input host and token\_endpoint value: `=$.Input.host + $.Input.token_endpoint`
5. Change the Method to `POST`.
6. Set the Body format as `URL Encoded Content`.
7. A URL encoded body field will appear:

![](https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FS3wGABtfHjVNAgpujBwR%2Foauth_urlencoded.png?alt=media\&token=653f4b7d-9fca-4bf0-9c78-5087fefba802)\
\
Expand the editor and add the parameters like below:\\

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2F6wbO1Mz8BDbUZdXDFujJ%2Foauth_urlencodedparams.png?alt=media&#x26;token=a61ed813-6b21-4770-831c-3465d5a1a6fd" alt=""><figcaption></figcaption></figure></div>

8. Debug the ExchangeCodeForToken with the correct $.Input values (Copy the code parameter from the redirection URL and add it to the Solution). When the request is made, the variables will be encoded and submitted like below:

`POST https://github.com/login/oauth/access_token HTTP/1.1 Content-Type: application/x-www-form-urlencoded Host: github.com Content-Length: 182 Connection: Keep-Alive client_id=8xxxxxxxxxx&client_secret=6xxxxxxxxxxxxxx&code=0ae113efsabd60ee0b81e&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Foauth%2Ftoken&state=QjKc`

{% hint style="info" %}
Note:\
The authorization code is only valid for a certain period of time. If it has expired, you will need to re-initiate the flow by generating the Authorization URL again with the GenerateAuthorizationUri process.
{% endhint %}

9. If the request was successful a response should be returned with a ResponseBody like below: `access_token=9810c091ecf4899525c19c2d98a662762c6b2b2c&expires_in=28800&refresh_token=r1.b03080d2fd959ddb0ec4d4db708bb878ebdccc808773d997cd9f67e28de9633ec2bf7583f1bdc4d2&refresh_token_expires_in=15724800&scope=&token_type=bearer`

This response is a single string value, which is not typical of token responses. Typically, access tokens are returned as application/json. With GitHub, you are able to specify the content type of the response object by adding an Accept header value.

9. Add a Header to the request like below:\
   `[ { "Name":"Accept", "Value":"application/json" } ]`
10. Debug the ExchangeCodeForToken with the correct $.Input values.
11. The Response Body should now still be a single string, but it is in JSON format like below:

`{ "access_token":"e754cccc9d0531545706b38ccac8a32811175852", "expires_in":28800, "refresh_token":"r1.6f3b7b03a437055b5414fef7fa52c294a18d9259057ab2c4", "refresh_token_expires_in":15724800, "token_type":"bearer", "scope":"" }`

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FIwxW1p125ZZ611nzirLE%2Foauth_debugexchangecodefortoken.png?alt=media&#x26;token=1a85c08f-bf99-4714-a647-6f069f574d31" alt=""><figcaption></figcaption></figure></div>

#### Returning the access token <a href="#returning-the-access-token" id="returning-the-access-token"></a>

The current response is returned as a String type. In order to parse the text into the respective fields, the response object needs to be imported as a Custom type.

Once imported, the Output type can reference this structure and the fields will be parsed.

1. Import the Response Body as a Custom type and give it the name token.
2. You should have a token like the below:

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FHcKWOxQ7y9pk9rHVu1Ee%2Foauth_token.png?alt=media&#x26;token=260bf04d-60c6-426b-bfac-a50469bb7fd2" alt=""><figcaption></figcaption></figure></div>

3. Set the Output type of the CallRESTEndpoint in the ExchangeCodeForToken process.
4. Add an $.Result to the ExchangeCodeForToken Function with a Name of token and the Type of Project.Token. This will return the entire token object details which will allow us access to all the details when the ExchangeCodeForToken Function is called.
5. Add a SetValue to the end of the ExchangeCodeForToken process.
6. For the Target, reference $.Result.token.
7. For Source, reference CallRESTEndpoint.ResponseBody.
8. Debug the function again and take note of how the Response Body has been deserialized into the token object and the token returned as an output:

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FMYiLeX3pRBHGqRG4rIR2%2Foauth_debugexchangecodefortoken2.png?alt=media&#x26;token=9f201725-d602-40b4-8caf-9e47ecaf0fe1" alt=""><figcaption></figcaption></figure></div>

{% hint style="info" %}
Tip:\
Copy the the value of the `ResponseBody.token.access_token` and save it for the next section.
{% endhint %}

#### Using the access token <a href="#using-the-access-token" id="using-the-access-token"></a>

To demonstrate how access token’s are used in a request, the below steps outline how to add an Authorization header with the value of Bearer {token}.

Extending the example of GitHub, a request is going to be made to the /user endpoint.

The token generated from the earlier step will be added to the Authorization header.

The response will contain information related to the authenticated user.

1. Create a new Function and rename it GetAuthenticatedUser.
2. Add an access\_token $.Input parameter.
3. Add a CallRESTEndpoint function to the GetAuthenticatedUser process.
4. Set the URL as <https://api.github.com/user>.
5. Expand the Headers editor and add the header with a Name of Authorization.
6. For the Value, use an expression like below:\
   `="Bearer " + $.Input.access_token`
7. Debug the **GetAuthenticatedUser process**, copy and paste the access\_token from the previous step into the $.Input.access\_token. The request should fail with an output like below:

`Response code: 403 (Forbidden) Response Body: Request forbidden by administrative rules. Please make sure your request has a User-Agent header`

{% hint style="info" %}
Note:\
This is a specific issue with the GitHub API, more details on the solution can be found here.
{% endhint %}

To resolve the issue add the following as the User-Agent header:

`Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 YaBrowser/16.3.0.7146 Yowser/2.5 Safari/537.36`

8. Debug the GetAuthenticatedUser function again, you should receive a 200 (OK) like below:

`CallRESTEndpoint: URL Constructed https://api.github.com/user CallRESTEndpoint: HTTP client created CallRESTEndpoint: Sending GET request CallRESTEndpoint: Request Headers: CallRESTEndpoint: Authorization = Bearer debb277f9a880460a14abd4cdd474d7406fc6724 CallRESTEndpoint: User-Agent = Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 YaBrowser/16.3.0.7146 Yowser/2.5 Safari/537.36 CallRESTEndpoint: Response received CallRESTEndpoint: ----------------- CallRESTEndpoint: Response code: 200 (OK) CallRESTEndpoint: Response Body: CallRESTEndpoint: { "login":"yourlogin", "id":11111, "node_id":"xxXXXX111XXX1", "avatar_url":"https://avatars1.githubusercontent.com/u/xxxx?v=4", "gravatar_id":"", "url":"https://api.github.com/users/youruser", "html_url":"https://github.com/youruser", "followers_url":"https://api.github.com/users/youruser/followers", "following_url":"https://api.github.com/users/youruser/following{/other_user}", "gists_url":"https://api.github.com/users/youruser/gists{/gist_id}", "starred_url":"https://api.github.com/users/youruser/starred{/owner}{/repo}", "subscriptions_url":"https://api.github.com/users/youruser/subscriptions", "organizations_url":"https://api.github.com/users/youruser/orgs", "repos_url":"https://api.github.com/users/youruser/repos", "events_url":"https://api.github.com/users/youruser/events{/privacy}", "received_events_url":"https://api.github.com/users/youruser/received_events", "type":"User", "site_admin":false, "name":"youruser", "company":"yourusercompany ", "blog":" ", "location":"", "email":null, "hireable":null, "bio":" ", "twitter_username":null, "public_repos":1, "public_gists":0, "followers":0, "following":0, "created_at":"2020-09-10T14:17:48Z", "updated_at":"2020-12-03T06:57:31Z" }`

9. Import the response as a Custom type and use it to return details from the GetAuthenticatedUser process. (This will be used later in this guide).

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FL6CAR7HRDPue1Sy4eadh%2Foauth_debugauthenticateduser.png?alt=media&#x26;token=4864ce81-7226-461b-9d29-468e736946cb" alt=""><figcaption></figcaption></figure></div>

Well done, you’ve successfully implemented a Generic OAuth 2.0 Provider with Linx, however, in its current state, the application is basic and requires manual intervention.

***

### Automating the whole flow <a href="#automating-the-whole-flow" id="automating-the-whole-flow"></a>

So far, we’ve created custom processes to successfully:

* generate an authorization URL
* make a request for an access token
* use the access token in the request

However, it still requires manual intervention for the most part.

In order to automate the entire authentication flow as well as add in some nice to haves, we are going to do the following:

* receive a request to generate the authorization URI
* generate an authorization URI
* return and redirect user-agent to the authorization URI.
* receive the redirection request containing the authorization code.
* automatically make a request for an access token using the authorization code
* use the access token in the request

The result will be the below:

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FR1velqW06xotz6zBl9aD%2Foauth_automateflow.gif?alt=media&#x26;token=ae895a9e-5db6-4c43-84ca-25769f3e8091" alt=""><figcaption></figcaption></figure></div>

#### Automatically re-direct users to the Authorization URI <a href="#automatically-re-direct-users-to-the-authorization-uri" id="automatically-re-direct-users-to-the-authorization-uri"></a>

Currently, you need to manually debug the GenerateAuthorizationUri function and copy out the URL and then browse to it.

To make life easier, we are going to create a REST operation that will receive a GET request. When the user browses to this hosted url, the operation is executed, it will then make a call to the GenerateAuthorizationUri function which will return a uri.

In the response of the operation, the uri will be returned in the Location header along with an Status Code of 301 (Redirect). What this does is that when a request is made to the operation, the response redirects the user-agent (browser) to the authorization uri.

The advantage of this is that you can set up a static URL to navigate to (this can be a bookmark in your browser or a link on a page) - when you browse to this url, the current client identifiers will be used to generate the authorization uri.

1. Add a RESTHost service to your Solution.
2. Set the Base URI as <http://localhost:8080>
3. Import the below API definition:

<pre class="language-yaml" data-overflow="wrap"><code class="lang-yaml"><strong>openapi: 3.0.0 
</strong>   info: 
      version: '1' 
      title: LinxOAuth2 
      description: Linx web service to automate the Authentication Code Grant 
flow 
   paths: /oauth/authorize: 
      get: 
         description: Generates authorization URL for user authentication. 
         operationId: AuthorizeRequest
         parameters: 
            []    
         responses: 
            '301': 
               description: Redirect 
               headers: 
                  Location: 
                     schema: 
                        type: string
</code></pre>

\
This will create an AuthorizeRequest operation in the Solution Explorer.

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FZRlqQxVQ3Wlusq37F464%2Foauth_authorizerequest.png?alt=media&#x26;token=c721f74e-fd2d-4593-83ef-011b49b925b3" alt=""><figcaption></figcaption></figure></div>

When the AuthorizeRequest operation is called, it will execute the GenerateAuthorizationUri function and return the output of it.

4. Drag the GenerateAuthorizationUri function from the Solution Explorer, onto the AuthorizeRequest operation selected in the canvas panel. You will notice the the local function call to the GenerateAuthorizationUri function has empty input parameters:

{% hint style="info" %}
Note:\
The default values that were set only apply when debugging the function and not when you make a call to that function.
{% endhint %}

You could “hard code” the inputs like below:

![](https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FJuHIb0Z1sqS7UktSyit1%2Foauth_generateauthorizationuri2.png?alt=media\&token=6d9061a2-00f1-4b5e-b9fa-4014db91d457)\
\
However, client identifiers often change and going back into this operation to change them will cause issues. To resolve this, its generally best practice to store variables like this as a constant or $.Setting of the Solution and reference the $.Settings.value when needed:\
![](https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FOhkxJa11QlOIkfwQr2Un%2Foauth_generateauthorizationurisettings.png?alt=media\&token=4de0a735-9a5e-466c-b888-60fe84c2b24a)

![](https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FsJFN5h2fCT4u32GbUksJ%2Foauth_generateauthorizationurisettings2.png?alt=media\&token=2de88ff0-7506-409e-8c3a-03d70eead6be)\
If you debug the AuthorizeRequest operation, you will see the GenerateAuthorizationUri function return a uri output containing the built up uri string.

5. In order to return this uri in the response and redirect the user-agent to this address we first need to indicate in the response that this is a (301) Redirect which will make the user-agent navigate to the value provided in the Location header. To do this, the $.Result.Data.HttpContext.StatusCode needs to be set to 301. The Location header then needs to be added to the response which will contain the location of the redirect address which in this case will be the generated authorization uri. Add a SetValue function to the AuthorizeRequest operation and rename it SetValue\_Response301.
6. For the Target reference the whole $.Result.Data.HttpContext object.
7. For the Source, expand the field editor.
8. Set the StatusCode as 301.
9. Expand the Headers editor and add a Location header which references the output of the GenerateAuthorizationUri function like below:

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2F1oJ7Sffd3KQCCXW7QeYq%2Foauth_generateauthorizationurilocation.gif?alt=media&#x26;token=19456273-69b9-4c3f-8306-cdf73abe5b65" alt=""><figcaption></figcaption></figure></div>

To test the above out, we are going to locally host the REST web service and use it to make requests against.

To host a REST web service locally:

1. Right-click on the RESTHost service in the Solution Explorer.
2. Click Debug.
3. Once the Debugger has initialized, click Start
4. In your browser, make a request to [THIS URI](http://localhost:8080/oauth/authorize).

{% hint style="info" %}
Note:\
While developing, you will most likely make several repeating requests in your browser. As a result the browser may store a cache of some of the information which leads to errors during the flow. To resolve this, clear your cache or initiate the request in an incognito window.
{% endhint %}

5. If successful, you should be redirected to the GitHub authorization page to login. Each time you need to re-generate an authorization code, just navigate to the /authorize url.

{% hint style="info" %}
Tip:\
Bookmark the <http://localhost:8080/oauth/authorize> uri in your web browser to make testing easier.
{% endhint %}

#### Automatically request tokens after authorization <a href="#automatically-request-tokens-after-authorization" id="automatically-request-tokens-after-authorization"></a>

Currently, when you authorize the application, you will be redirect to the redirect URI which would be:

`http://localhost:8080/oauth/token?code=a3b35dbc42597a2e58e3&state=QjKcs`

Your browser will display a (404) Not Found error like below:

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fm3nQMPa9D0iK7XmmJkVw%2Foauth_error404.png?alt=media&#x26;token=02346e0e-340f-4d1f-b1b5-b750f3dbaf9c" alt=""><figcaption></figcaption></figure></div>

This is because there is no host listening on that address.

We are now going to add an ExchangeCode operation to our RESTHost service and host it on the redirection uri.

The operation will take in the code and state parameters as part of the query string.

The operation will then call the ExchangeCodeForToken function from earlier.

The code passed in with the URL would be passed into the ExchangeCodeForToken function to exchange with the Authorization Server.

Once the token has been generated, it will be passed into the GetAuthenticatedUser process.

A request would then be made using the token to return the currently authenticated user’s details.

These details will then be returned in the Response Body of the operation.

Add the below path and parameters to the API definition:

```yaml
/oauth/token: 
    get: 
        description: Generates Access Token 
        operationId: ExchangeCode 
        parameters: 
                - in: query 
                  name: state 
                  schema: 
                    type: string 
                - in: query 
                  name: code 
                  schema: 
                  type: string 
        responses: 
          default: 
            description: ResponseXXX 
            content: 
              text/html: 
                schema: 
                  type: string
```

This will create an ExchangeCode operation in the Solution Explorer:

\
The operation is configured to have a generic Response Body of a String type.

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FQZVWkAGlzl1bf9egdxmR%2Foauth_exchangecodeoperation1.png?alt=media&#x26;token=ccce914d-de05-4594-89dd-e9e5f12cf184" alt=""><figcaption></figcaption></figure></div>

![](https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FmtL4QsemtTmyXqBxG2Fu%2Foauth_exchangecodeoperation2.png?alt=media\&token=26b0d2f2-395e-47bd-aa9d-c5c555477282)\
\
The operation receives 2 input parameters:

2. Drag the ExchangeCodeForToken function from the Solution Explorer onto the ExchangeCode operation.
3. Configure the input values for ExchangeCodeForToken function call the like below:

![](https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fg50lKnTeAlSUAScQwlgX%2Foauth_exchangecodeoperation4.png?alt=media\&token=20896446-b561-450b-990c-a4a7e23ad4a0)\
You will see how the code and state input values reference the $.Input.Data.code and $.Input.Data.state of the operation.

4. Once the ExchangeCodeForToken function completes successfully, we will return a simple text message confirming the successful authentication. First the status code of the response must be set to indicate the result i.e. 200, 401, 403 etc. To do this, drag a SetValue function below the ExchangeCodeForToken function and rename it to SetValue\_Response200.
5. For the Target, reference $.Result.Data.HttpContext.
6. Expand the Source and set the value of the Status Code field to 200. This indicates the request result was successful.
7. For the Response Body, we are just going to return a simple text message. Add another SetValue function and rename it SetValue\_ResponseBody. For the Target, reference `$.Result.Data.ResponseXXX`. For the Source, set it as the text “OAuth 2.0 flow success!”
8. Debug the RESTHost service like below and navigate to the /authorize local endpoint from earlier:

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FTBqR0tVrk19J44duDdz6%2Foauth_debugresthost.gif?alt=media&#x26;token=e7a29bd9-53d2-4e62-9315-b5a27fd6a695" alt=""><figcaption></figcaption></figure></div>

Now, after you authorize the application, the user-agent makes a request to the Redirect URI which is our ExchangeCode operation. The code and state parameters are parsed from the query string and then passed into the ExchangeCodeForToken process. Once completed, the operation returns a message to the user-agent.

Full flow (no step through):

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FsIIjbTA1IYFz7rI4OkKJ%2Foauth_fullflow.gif?alt=media&#x26;token=3c91b31e-7ae8-4f86-a8f1-9fd7a470a23a" alt=""><figcaption></figcaption></figure></div>

#### Customizing the response <a href="#customizing-the-response" id="customizing-the-response"></a>

To personalize the response, we are going to use the GetAuthenticatedUser function to return details of the user that just granted access to the application. This is done purely to demonstrate using the access token when making a request.

1. Drag the GetAuthenticatedUser function from the Solution Explorer, into the ExchangeCode operation, positioning it right below the ExchangeCodeForToken process.
2. For the access\_token input of GetAuthenticatedUser, reference the token generated from the ExchangeCodeForToken function like below: `` `=ExchangeCodeForToken.token.access_token` ``

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FPzaVDP9SbVRezayX74Ux%2Foauth_customizeresponse.gif?alt=media&#x26;token=312a6512-183c-4b8f-b38f-c92c3abf5cd4" alt=""><figcaption></figcaption></figure></div>

3. We now use the user details returned from the GetAuthenticatedUser function to personaize the response message. Alter the Source of the SetValue\_ResponseBody like below:

`="GitHub User '" + GetAuthenticatedUser.user.name + "' successfully authenticated"`

Now, when the flow completes, a personal message is returned.

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fq44akuzXC6aevbhuab7h%2Foauth_customizeresponse2.gif?alt=media&#x26;token=ed4cb55e-4140-422d-8997-385c9b81a6bb" alt=""><figcaption></figcaption></figure></div>

***

### Storing and retrieving the access token <a href="#storing-and-retrieving-the-access-token" id="storing-and-retrieving-the-access-token"></a>

In its current state, the Solution successfully generates and uses the access token. However, to re-authorize and generate a new token each time a request is made is impractical. As Linx does not persist data unless stored as a setting, you will need to store the token in a datasource of some kind (database, text file), in order to retrieve for later use in requests.

To demonstrate the concept, we are going to create a generic function that will store the access token object in a local text file.

{% hint style="info" %}
Note:\
Typically, access tokens would be stored in a database. In this demonstration we will use a file instead as some users may not have set up a database.
{% endhint %}

We are then going to create a generic function that will return the token details when they are needed n a request.

#### Logging the token <a href="#logging-the-token" id="logging-the-token"></a>

1. Create a new function and rename it LogToken.
2. For the $.Inputs, add a token field and reference the Project.token object as the Type.
3. Within the LogToken function, add a TextFileWrite function.
4. For the File path we are going to create a $.Setting value which will store the location of the file. We can then reference this value when reading and writing from the file.
5. For the Contents. we want to store the whole token object as plain text.

{% hint style="info" %}
Note:\
If you reference a whole Custom type object as a string input i.e. when writing the contents of a file, the custom type details will not be able to be converted into text implicitly. In order to explicitly convert a Custom type into text, you need to assign it to String type first.
{% endhint %}

To explicitly convert the token into text o use for storage, add a String type instance to the function and rename it stringifyToken. For the Value, reference the whole $.Input.token. This will explicitly converted the custom type structure and values into a JSON string.

6. For the Contents of the TextFileWrite, reference stringifyToken.
7. Ensure the File exists is set to Overwrite. This means that if the file exists already, then the current contents of the file will be overwritten.

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2F6Gizqa5CeeLNeDtVJCgN%2Foauth_logtoken1.png?alt=media&#x26;token=e084401c-472c-4cb6-bd47-70e09575aca3" alt=""><figcaption></figcaption></figure></div>

8. You are then able to make a function call to the LogToken function, in the ExchangeCode operation, passing in the token that was just generated (i.e. `ExchangeCodeForToken.token`):

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2FKUhLeYohxFd6Ow8qrnz1%2Foauth_logtoken2.png?alt=media&#x26;token=8c2b7fe6-52d6-46a5-b62e-af3eb81d296d" alt=""><figcaption></figcaption></figure></div>

9. Now, if you re-initiate the whole flow again, the token response object will be logged in the “token.txt” text file:

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fmkp4Z7xO9Adjlc6NtcBv%2Foauth_logtoken3.png?alt=media&#x26;token=fd8b23f8-f1e8-4024-96e6-a06ea325194b" alt=""><figcaption></figcaption></figure></div>

#### Retrieving the token <a href="#retrieving-the-token" id="retrieving-the-token"></a>

By storing the whole JSON string of the object, we are able to read the contents back out and assign them directly into our token type, this makes working with the individual fields easier.

We are now going to build a function that will read the contents from “token.txt”, assign it to the token type and return the details. This function can then be called from other functions when a request is made. The latest stored token will be returned and then can be used in the Authorization header.

1. Create a new function and rename it RetrieveToken.
2. For the $.Result, add a token field and reference the `Project.token` object as the Type.
3. Within the RetrieveToken function, add a TextFileRead function.
4. For the File path, reference the same $.Settings value that was used when writing to the file (i.e. `$.Settings.token_log_path`).
5. For the Return options, select `Complete`. This will read the entire contents fom the file as a single String type.
6. As the JSON stored in the file maps directly to the token type, we can use a SetValue function to assign the output of the TextFileRead directly to the `$.Result.token` of the RetrieveToken function.

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2F0IHNtT2mx7atMrwm9H9w%2Foauth_retrievetoken1.png?alt=media&#x26;token=896a39e1-12b9-48a8-bcb1-4580d5a925ba" alt=""><figcaption></figcaption></figure></div>

You are then able to call RetrieveToken wherever you need the current access token to make a request.

To demonstrate:

1. Remove the `$.Input.access_token` field for the GetAuthenticatedUser function.
2. A validation error should appear as the $.Input.access\_token field no longer exists. Instead of passing in the current access token value to the GetAuthenticatedUser function, we can just make a call inside of the GetAuthenticatedUser function to the RetrieveToken function.

<div align="left"><figure><img src="https://3338214469-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1nxDeDH8GVCXb0XelqGm%2Fuploads%2Fgit-blob-23da46723e2eda5de014003b9fac498ef38cb12a%2Foauth_retrievetoken2.png?alt=media" alt=""><figcaption></figcaption></figure></div>

3. We can then use the token details returned for the Authorization header of the CallRESTEndpoint like below:

```
="Bearer " + RetrieveToken.token.access_token
```

Now when re-initiate the flow, the generated token will be logged in a file. When the user details are requested, the latest token details are retrieved from the local text file and submitted with the request.

***

### You’re set to go! <a href="#you-re-set-to-go" id="you-re-set-to-go"></a>

You should now have a better understanding of the OAuth 2.0 flow as well as have a practical understanding of building a basic OAuth 2.0 authenticator with Linx.

You will now be able to connect to your API of choice using this guide as a base template.

{% hint style="warning" %}
Warning:

The steps provided in this explanation are based on Linx before release 6.4.0.

In *Linx 6.4.0 and higher* there is a Return function in the Linx plugin that must be used for setting the value of a function's result. The SetValue function and $.Result cannot be used for this purpose anymore.

Go here for details of the Return function.
{% endhint %}

***

### Sample <a href="#sample" id="sample"></a>

View our sample solution on [GitHub](https://github.com/linx-software/linx-oauth2-token-service).
