# Developing a Backend App with OAuth2

For this guide we assume that you have read [the general OAuth2 introduction](https://docs.ilert.com/developer-docs/developing-ilert-apps/understanding-oauth2) as well as created an application as shown in [the getting started guide](https://docs.ilert.com/developer-docs/developing-ilert-apps/get-started-with-ilert-apps).

You may find the whole source code project in [this Github repository](https://github.com/iLert/sample-oauth2-app).

## Preparing your ilert app

Before we can started, we need to make sure that our ilert application is configured correctly.\
Navigate to your application and make sure that you have entered a redirect url that fits your local or deployed webservice that should act as OAuth2 client. Also copy the client id and client secret, as we will need them to configure your application.

<figure><img src="https://1534978131-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F684bnaGsqSFjESghpiiu%2Fuploads%2FsQtetrji6OpPbwlo54qy%2Fimage.png?alt=media&#x26;token=c6e62a96-2e82-4e89-a951-d49bc9ff975e" alt=""><figcaption></figcaption></figure>

## Redirecting the user

Using the parameters generated by ilert during the creation of our app, we can build a redirect url for our application, that will take unauthorized users to ilert and ask them to login and grant their permission for our app. In the case of our app, we ask for the **profile** scope (find more information on other available scopes [here](https://docs.ilert.com/developer-docs/token-lifetimes-error-codes-app-verification-etc.#ilert-oauth2-scopes)), as well as the **source:w** scope which will grant us permission to read the user's profile data, as well as to read and edit alert sources in the name of the authorizing user.

{% hint style="info" %}
Make sure that the redirect\_uri that is passed to the redirect url is exactly the same as the one the you have entered in your application's settings or the authorization will fail. This validation is necessary, as verifing the redirect\_uri is a very important part of implementing a secure OAuth2 flow. In case you need to send optional data e.g. your own id, use the **state** query parameter. It will be returned to your client.
{% endhint %}

{% tabs %}
{% tab title="Node.js" %}

```javascript
const url = "https://app.ilert.com/api/developers/oauth2/authorize";
const queryParams = new URLSearchParams({
    client_id: '0501439fd7dee9af0c25',
    response_type: 'code',
    redirect_uri: 'http://localhost:4597/authorize-result',
    scope: 'profile source:w',
    state: 'optional-state'
});

res.redirect(url + "?" + queryParams.toString());
```

{% endtab %}

{% tab title="cURL" %}

```shell
curl --request GET \
  --url 'https://app.ilert.com/api/developers/oauth2/authorize?client_id=0501439fd7dee9af0c25&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A4597%2Fauthorize-result&scope=profile%20source%3Aw&state=optional-state
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
In case the user is known to your application or especially if the application is limited to a single account. We suggest to redirect the user directly to the **tenant** (account url) of the user, this way he might be able to skip the login step if logged in already. e.g. `https://someTenant.ilert.com/api/developers/oauth2/authorize` instead of `https://app.ilert.com/api/developers/...`
{% endhint %}

### User grant view

The user will be able to see the scopes that you have requested and grant them.

<figure><img src="https://1534978131-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F684bnaGsqSFjESghpiiu%2Fuploads%2FQkXAfVIhxF10uBjb9jVw%2Fimage.png?alt=media&#x26;token=7cf4742b-c1dd-4118-9860-49e4ac5c6083" alt=""><figcaption></figcaption></figure>

### In case of an error

In case of any error, ilert's authorization server will send the user back to the provided redirect\_uri while adding an **error** and **error\_description** query parameter to it.

### In case of successful authorization

If the user has accepted your scopes, ilert's authorization server will redirect the user back to your provided **redirect\_uri** while adding a **code** query parameter to it. This code parameter can be used in the next step to fetch the access token.

```
http://localhost:4597/authorize-result?code=c82ec4eca4c0ac90061fdd4225d1&state=optional-state
```

## Turning a code into a token

Using the code your backend can make an outbound HTTP request to the authorization server, providing your client secret.

{% hint style="danger" %}
Never expose your client\_secret, keep it safe.
{% endhint %}

{% tabs %}
{% tab title="Node.js" %}

```javascript
var axios = require("axios").default;

var options = {
  method: 'POST',
  url: 'https://api.ilert.com/api/developers/oauth2/token',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  data: {
    client_id: '0501439fd7dee9af0c25',
    client_secret: '3908acda0291d0c4c1e77171aac3b4e501cbbbfc6797f13be1c7a607241498ad',
    code: 'a74e0a0bfbfefbe62ab94a60942e',
    grant_type: 'authorization_code'
  }
};

axios.request(options).then(function (response) {
  console.log(response.data);
}).catch(function (error) {
  console.error(error);
});
```

{% endtab %}

{% tab title="cUrl" %}

```shell
curl --request POST \
  --url https://api.ilert.com/api/developers/oauth2/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data client_id=0501439fd7dee9af0c25 \
  --data client_secret=3908acda0291d0c4c1e77171aac3b4e501cbbbfc6797f13be1c7a607241498ad \
  --data code=a74e0a0bfbfefbe62ab94a60942e \
  --data grant_type=authorization_code
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://api.ilert.com/api/developers/oauth2/token"

	payload := strings.NewReader("client_id=0501439fd7dee9af0c25&client_secret=3908acda0291d0c4c1e77171aac3b4e501cbbbfc6797f13be1c7a607241498ad&code=a74e0a0bfbfefbe62ab94a60942e&grant_type=authorization_code")

	req, _ := http.NewRequest("POST", url, payload)
	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

{% endtab %}

{% tab title="Python" %}

```python
import http.client

conn = http.client.HTTPSConnection("api.ilert.com")

payload = "client_id=0501439fd7dee9af0c25&client_secret=3908acda0291d0c4c1e77171aac3b4e501cbbbfc6797f13be1c7a607241498ad&code=a74e0a0bfbfefbe62ab94a60942e&grant_type=authorization_code"

headers = {
    'Content-Type': "application/x-www-form-urlencoded"
}

conn.request("POST", "/api/developers/oauth2/token", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
```

{% endtab %}
{% endtabs %}

### In case of an error

You will receive an error response.

```json
{
	"code": "invalid_grant",
	"error": "Provided code is unknown"
}
```

### In case of successful token generation

If code and secret are valid, the authorization server will respond with an access as well as a refresh token.

{% hint style="danger" %}
Never expose your user's tokens, especially not the refresh tokens treat them like passwords.
{% endhint %}

```json
{
	"token_type": "Bearer",
	"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpbF9uIjoiNWNmIiwiaWxfYSI6MiwiaWxfcyI6InByb2ZpbGUgc291cmNlOnciLCJpc3MiOiJpbGVydCIsImlsX3UiOiJrcnlzdGlhbml0eSIsImlsX3QiOiJBQ0NFU1MiLCJpbF92IjoxLCJleHAiOjE2NDM3MjY3MjN9.Ao0dTxQpcez0IsaUOdsPzWqWhj31ob9Tzf-5KSoqJEmjC4lkeOiRJ255HI8w2IQyj7aunW_SM50rRQBcDHVkt8JmfuT4TgYJ3dvZiJzeZ-YGU1QDT6pCN30wJ9a3rpmv6Y6T2cJD1JvNuEh1qyjdjmJGuBVU3-_0qZSu-Y6CBaRxaBvM27JOf2JkQ4pAN7dK4c2Yw7-MyEkBhtwI_JEMhNCp6GF5SJGhCFBq-xPF1iFqpllIrpqaTWAvRz0ZCNWZCumXCaJAfvnS_OJJoPwEvr2DBV8x0bAuFpECgycE8_--rjU9gZafqiRd2cfFas7AmzQFuvvDGQx_1Zq7leW3EA",
	"expires_in": 3600,
	"scope": "profile source:w",
	"refresh_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpbGVydCIsImlsX3QiOiJPQVVUSCIsImlsX3YiOjEsImV4cCI6MTY3NTI1OTEyMywiaWxfayI6IjM0ZTMzYzdmZGUzZjQzZTdhMTEwOWJmYTgzMmRkNDdiIn0.ol0HwWO_zAAhKLjLPLDPwvxv7PNPnUnZq8IXd5fC1FY",
	"refresh_token_expires_in": 31536000
}
```

## Using the access token

Your application backend should store the access and especially the refresh token safely. You can now make requests to ilert's API on behalf of the authorized user.

{% hint style="success" %}
Do not forget the Bearer prefix in the authorization header before your access token.
{% endhint %}

{% tabs %}
{% tab title="Node.js" %}

```javascript
var axios = require("axios").default;

var options = {
  method: 'GET',
  url: 'https://api.ilert.com/api/users/current',
  headers: {
    Authorization: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpbF9uIjoiNWNmIiwiaWxfYSI6MiwiaWxfcyI6InByb2ZpbGUgc291cmNlOnciLCJpc3MiOiJpbGVydCIsImlsX3UiOiJrcnlzdGlhbml0eSIsImlsX3QiOiJBQ0NFU1MiLCJpbF92IjoxLCJleHAiOjE2NDM3MjczNTR9.ZSxXJiR7yPF9BMfsfa9dYVpdv5E2o88iBTG1VFp7-vdF3wciNte7_fKQU2z2aMVudGIZ6dhpBuA8FnSJa3sjaXgsHy2r8Fjvj2XCTuPigaZgURTjAM0zqTC6bxHVkn-G9bKUoJ8mx40U8hFZFPsnD5b9qiZZ6CjqU0CCuiWjoEC8hapHe1TOYnNvqeFPRUYfOhJTXAuOoW0wmcKdrAyk6YbVN74nDVlEbG1TEGIXk893jVyLaoiShqHxkcnyliTWLYg9P_DG0JXFflxugyGttP3GaxAq28KAxI-5VAa_QptXlwybEVN9Q8072a7Xk4R0_jCKbp9uMKE3E4qH72f3PA'
  }
};

axios.request(options).then(function (response) {
  console.log(response.data);
}).catch(function (error) {
  console.error(error);
});
```

{% endtab %}

{% tab title="cUrl" %}

```shell
curl --request GET \
  --url https://api.ilert.com/api/users/current \
  --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpbF9uIjoiNWNmIiwiaWxfYSI6MiwiaWxfcyI6InByb2ZpbGUgc291cmNlOnciLCJpc3MiOiJpbGVydCIsImlsX3UiOiJrcnlzdGlhbml0eSIsImlsX3QiOiJBQ0NFU1MiLCJpbF92IjoxLCJleHAiOjE2NDM3MjczNTR9.ZSxXJiR7yPF9BMfsfa9dYVpdv5E2o88iBTG1VFp7-vdF3wciNte7_fKQU2z2aMVudGIZ6dhpBuA8FnSJa3sjaXgsHy2r8Fjvj2XCTuPigaZgURTjAM0zqTC6bxHVkn-G9bKUoJ8mx40U8hFZFPsnD5b9qiZZ6CjqU0CCuiWjoEC8hapHe1TOYnNvqeFPRUYfOhJTXAuOoW0wmcKdrAyk6YbVN74nDVlEbG1TEGIXk893jVyLaoiShqHxkcnyliTWLYg9P_DG0JXFflxugyGttP3GaxAq28KAxI-5VAa_QptXlwybEVN9Q8072a7Xk4R0_jCKbp9uMKE3E4qH72f3PA' 
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"fmt"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://api.ilert.com/api/users/current"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpbF9uIjoiNWNmIiwiaWxfYSI6MiwiaWxfcyI6InByb2ZpbGUgc291cmNlOnciLCJpc3MiOiJpbGVydCIsImlsX3UiOiJrcnlzdGlhbml0eSIsImlsX3QiOiJBQ0NFU1MiLCJpbF92IjoxLCJleHAiOjE2NDM3MjczNTR9.ZSxXJiR7yPF9BMfsfa9dYVpdv5E2o88iBTG1VFp7-vdF3wciNte7_fKQU2z2aMVudGIZ6dhpBuA8FnSJa3sjaXgsHy2r8Fjvj2XCTuPigaZgURTjAM0zqTC6bxHVkn-G9bKUoJ8mx40U8hFZFPsnD5b9qiZZ6CjqU0CCuiWjoEC8hapHe1TOYnNvqeFPRUYfOhJTXAuOoW0wmcKdrAyk6YbVN74nDVlEbG1TEGIXk893jVyLaoiShqHxkcnyliTWLYg9P_DG0JXFflxugyGttP3GaxAq28KAxI-5VAa_QptXlwybEVN9Q8072a7Xk4R0_jCKbp9uMKE3E4qH72f3PA")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))
}
```

{% endtab %}

{% tab title="Python" %}

```python
import http.client

conn = http.client.HTTPSConnection("api.ilert.com")

payload = ""

headers = {
    'Authorization': "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpbF9uIjoiNWNmIiwiaWxfYSI6MiwiaWxfcyI6InByb2ZpbGUgc291cmNlOnciLCJpc3MiOiJpbGVydCIsImlsX3UiOiJrcnlzdGlhbml0eSIsImlsX3QiOiJBQ0NFU1MiLCJpbF92IjoxLCJleHAiOjE2NDM3MjczNTR9.ZSxXJiR7yPF9BMfsfa9dYVpdv5E2o88iBTG1VFp7-vdF3wciNte7_fKQU2z2aMVudGIZ6dhpBuA8FnSJa3sjaXgsHy2r8Fjvj2XCTuPigaZgURTjAM0zqTC6bxHVkn-G9bKUoJ8mx40U8hFZFPsnD5b9qiZZ6CjqU0CCuiWjoEC8hapHe1TOYnNvqeFPRUYfOhJTXAuOoW0wmcKdrAyk6YbVN74nDVlEbG1TEGIXk893jVyLaoiShqHxkcnyliTWLYg9P_DG0JXFflxugyGttP3GaxAq28KAxI-5VAa_QptXlwybEVN9Q8072a7Xk4R0_jCKbp9uMKE3E4qH72f3PA"
    }

conn.request("GET", "/api/users/current", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
```

{% endtab %}
{% endtabs %}

## Refreshing an access token

As access tokens are short lived (read more about token lifetime [here](https://docs.ilert.com/developer-docs/token-lifetimes-error-codes-app-verification-etc.#oauth2-lifetimes-and-numbers)), you will have to refresh them regularly, at least in case they expire and the ilert API returns a 401 HTTP status code error.

{% tabs %}
{% tab title="Node.js" %}

```javascript
var axios = require("axios").default;

var options = {
  method: 'POST',
  url: 'https://api.ilert.com/api/developers/oauth2/token',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  data: {
    client_id: '0501439fd7dee9af0c25',
    client_secret: '3908acda0291d0c4c1e77171aac3b4e501cbbbfc6797f13be1c7a607241498ad',
    refresh_token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpbGVydCIsImlsX3QiOiJPQVVUSCIsImlsX3YiOjEsImV4cCI6MTY3NTI1OTEyMywiaWxfayI6IjM0ZTMzYzdmZGUzZjQzZTdhMTEwOWJmYTgzMmRkNDdiIn0.ol0HwWO_zAAhKLjLPLDPwvxv7PNPnUnZq8IXd5fC1FY',
    grant_type: 'refresh_token'
  }
};

axios.request(options).then(function (response) {
  console.log(response.data);
}).catch(function (error) {
  console.error(error);
});
```

{% endtab %}

{% tab title="cUrl" %}

```shell
curl --request POST \
  --url https://api.ilert.com/api/developers/oauth2/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data client_id=0501439fd7dee9af0c25 \
  --data client_secret=3908acda0291d0c4c1e77171aac3b4e501cbbbfc6797f13be1c7a607241498ad \
  --data refresh_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpbGVydCIsImlsX3QiOiJPQVVUSCIsImlsX3YiOjEsImV4cCI6MTY3NTI1OTEyMywiaWxfayI6IjM0ZTMzYzdmZGUzZjQzZTdhMTEwOWJmYTgzMmRkNDdiIn0.ol0HwWO_zAAhKLjLPLDPwvxv7PNPnUnZq8IXd5fC1FY \
  --data grant_type=refresh_token
```

{% endtab %}

{% tab title="Go" %}

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://api.ilert.com/api/developers/oauth2/token"

	payload := strings.NewReader("client_id=0501439fd7dee9af0c25&client_secret=3908acda0291d0c4c1e77171aac3b4e501cbbbfc6797f13be1c7a607241498ad&refresh_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpbGVydCIsImlsX3QiOiJPQVVUSCIsImlsX3YiOjEsImV4cCI6MTY3NTI1OTEyMywiaWxfayI6IjM0ZTMzYzdmZGUzZjQzZTdhMTEwOWJmYTgzMmRkNDdiIn0.ol0HwWO_zAAhKLjLPLDPwvxv7PNPnUnZq8IXd5fC1FY&grant_type=refresh_token")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))
}
```

{% endtab %}

{% tab title="Python" %}

```python
import http.client

conn = http.client.HTTPSConnection("api.ilert.com")

payload = "client_id=0501439fd7dee9af0c25&client_secret=3908acda0291d0c4c1e77171aac3b4e501cbbbfc6797f13be1c7a607241498ad&refresh_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpbGVydCIsImlsX3QiOiJPQVVUSCIsImlsX3YiOjEsImV4cCI6MTY3NTI1OTEyMywiaWxfayI6IjM0ZTMzYzdmZGUzZjQzZTdhMTEwOWJmYTgzMmRkNDdiIn0.ol0HwWO_zAAhKLjLPLDPwvxv7PNPnUnZq8IXd5fC1FY&grant_type=refresh_token"

headers = {
    'Content-Type': "application/x-www-form-urlencoded"
}

conn.request("POST", "/api/developers/oauth2/token", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))
```

{% endtab %}
{% endtabs %}

The responses will be equal to the ones of **Turning a code into a token** above.

## Accessing token information

You could parse the JWT token yourself, however we offer a token info endpoint for convience.\
Note that this endpoint only accepts access tokens.

{% tabs %}
{% tab title="Node.js" %}

```javascript
var axios = require("axios").default;

var options = {
  method: 'POST',
  url: 'https://api.ilert.com/api/developers/oauth2/token_info',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  data: {
    token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpbF9uIjoiNWNmIiwiaWxfYSI6MiwiaWxfcyI6InByb2ZpbGUgc291cmNlOnciLCJpc3MiOiJpbGVydCIsImlsX3UiOiJrcnlzdGlhbml0eSIsImlsX3QiOiJBQ0NFU1MiLCJpbF92IjoxLCJleHAiOjE2NDM3MjczNTR9.ZSxXJiR7yPF9BMfsfa9dYVpdv5E2o88iBTG1VFp7-vdF3wciNte7_fKQU2z2aMVudGIZ6dhpBuA8FnSJa3sjaXgsHy2r8Fjvj2XCTuPigaZgURTjAM0zqTC6bxHVkn-G9bKUoJ8mx40U8hFZFPsnD5b9qiZZ6CjqU0CCuiWjoEC8hapHe1TOYnNvqeFPRUYfOhJTXAuOoW0wmcKdrAyk6YbVN74nDVlEbG1TEGIXk893jVyLaoiShqHxkcnyliTWLYg9P_DG0JXFflxugyGttP3GaxAq28KAxI-5VAa_QptXlwybEVN9Q8072a7Xk4R0_jCKbp9uMKE3E4qH72f3PA'
  }
};

axios.request(options).then(function (response) {
  console.log(response.data);
}).catch(function (error) {
  console.error(error);
});
```

{% endtab %}
{% endtabs %}

You will receive an info response like this:

```json
{
	"active": true,
	"tenant_id": "someTenant",
	"username": "someUser",
	"scope": "profile source:w",
	"app_id": 250
}
```

## Revoking a refresh token

Just like the user may at any time revoke the refresh token that was issued to your application, your application may also proactively revoke the refresh token.

{% tabs %}
{% tab title="Node.js" %}

```javascript
var axios = require("axios").default;

var options = {
  method: 'POST',
  url: 'https://api.ilert.com/api/developers/oauth2/revoke',
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  },
  data: {
    token: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpbGVydCIsImlsX3QiOiJPQVVUSCIsImlsX3YiOjEsImV4cCI6MTY3NTI1OTEyMywiaWxfayI6IjM0ZTMzYzdmZGUzZjQzZTdhMTEwOWJmYTgzMmRkNDdiIn0.ol0HwWO_zAAhKLjLPLDPwvxv7PNPnUnZq8IXd5fC1FY'
  }
};

axios.request(options).then(function (response) {
  console.log(response.data);
}).catch(function (error) {
  console.error(error);
});
```

{% endtab %}
{% endtabs %}

Make sure to checkout [further information on OAuth2 apps](https://docs.ilert.com/developer-docs/developing-ilert-apps/token-lifetimes-error-codes-app-verification-etc.).
