> For the complete documentation index, see [llms.txt](https://docs.extrahorizon.com/extrahorizon/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.extrahorizon.com/extrahorizon/services/access-management/auth-service/oauth2.md).

# OAuth2

oAuth2.0 standard: [\[rfc6749\]](https://datatracker.ietf.org/doc/html/rfc6749)

### Making an authenticated request

An example request to the User Service which is authenticated by OAuth2 looks like this:

```
GET users/v1/me HTTP/1.1
Host: api.<environment>.<​company>.extrahorizon.io
Authorization: Bearer 93a4d85654c24bd5a59c9b41f94f49e7
```

The role of the `Bearer` prefix in the **Authorization header** specifies that a token value is expected, implying a token-based authentication. In the case of OAuth2, this token value is the Access Token.

**Using the Extra Horizon SDK**

The Extra Horizon sdk solves the problem of making authenticated requests for you and will attach the right headers to the calls you are making in the background.

## Grants

### Password Grant

The Password Grant accepts your username and password, then returns an Access Token and a Refresh token. As mentioned before the Access Token can be used to authenticate API requests. These Access Tokens are short lived (A lifetime of 5 minutes for the flow described in the example below).

See also the [Password Policy User Service setting ](/extrahorizon/services/access-management/user-service/configuration.md#password-policy)for more information about the password format and login attempts.

{% tabs %}
{% tab title="Javascript" %}

```javascript
await exh.auth.authenticate({
    username:'john.doe@example.com'
    password:'myPassword1234'
});
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Not that in case this user has MFA enable this function will throw a `MfaRequiredError`. With the information in the error you can follow the [MFA Grant](#mfa-grant) to complete the authentication.
{% endhint %}

### MFA Grant

When MFA is enabled for a user and you try to authenticate using the password grant you will receive a `MfaRequiredError` . You can catch the error and use the Mfa Grant to complete the authentication.

{% tabs %}
{% tab title="Javascript" %}

```javascript
try {
  await exh.auth.authenticate({
    password: '',
    username: '',
  });
} catch (error) {
  if (error instanceof MfaRequiredError) {
    const { mfa } = error;

    // Your logic to request which method the user want to use in case of multiple methods
    const methodId = mfa.methods[0].id;

    await exh.auth.confirmMfa({
      token: mfa.token,
      methodId,
      code: '', // code from ie. Google Authenticator
    });
  }
  // handle other possible authentication errors
}
```

{% endtab %}
{% endtabs %}

### Authorization Grant

In most cases you will want to use to authorization Grant flow for external applications that are not under your direct control. E.g. partners that you allow to have an integration with your platform.

You don't want them to handle your users credentials and will require these applications to obtain an authorization grant code by redirecting you a /authorize endpoint hosted by one of your trusted applications.

An example of such a webpage would look like this:

```
/authorize/?client_id={CLIENT_ID}&response_type=code&redirect_uri={REDIRECT_URI}
```

When the user is authenticated on that page he/she will be redirected back to the URI specified in the client registration and the query parameter. this redirect will contain an authorization code that you can then use in the SDK to obtain an authentication.

```javascript
await exh.auth.authenticate({
  code: '{yourAuthorizionCodeHere}',
});
```

### Refresh Token Grant

The Refresh Token Grant is a mechanism to obtain a new Access Token. The grant accepts a Refresh Token and returns a new Access Token and a new Refresh Token. That way, the application keeps a valid access token without having the user to provide its credentials again.

When an access token is expired the SDK will use the refresh token stored in memory to refresh the tokens and make sure your call to the api is tried again.

When you want your user to stay authenticated when he reopens you app you will need to store the refreshToken and initiate the SDK authentication with the stored token.

```javascript
await exh.auth.authenticate({
  refreshToken: 'myRefreshToken',
});
```

{% hint style="danger" %}
Note that the refresh token changes every time a new access token is obtained. Therefore you will need to add a listener to the SDK to be notified when a new refresh token is received and for your app to safely and securely store it.
{% endhint %}

Each time the SDK refreshes the `accessToken` the `freshTokensCallback` is called with the response. You can store this data in `localStorage` or any other persistent data store. When you restart your application, you can check the data store for a `refreshToken` and use that to authenticate with the SDK.

```javascript
const exh = createOAuth2Client({
  host: '',
  clientId: '',
  freshTokensCallback: (tokenData) => {
    localStorage.setItem('refreshToken', tokenData.refreshToken);
  },
});
```

## Authorization codes

As mentioned before, the authorization code flow works by generating an authorization code, which can then be exchanged for tokens by another application. Below, we show how these codes can be created, listed, or removed.

### Create an authorization code

A minimal example on how to create an authorization code:

```javascript
await exh.auth.oauth2.authorizations.create({
  responseType: 'code',
  clientId: 'your client id here',
});
```

We also support the PKCE mechanism, and advise using it alongside the authorization code flow. When `codeChallengeMethod` and `codeChallenge` are supplied here, consuming the authorization code later on requires `code_verifier` to be set to the matching value.

```javascript
await exh.auth.oauth2.authorizations.create({
  responseType: 'code',
  clientId: 'your client id here',
  codeChallengeMethod: 'S256', // 'plain' is also supported
  codeChallenge: 'your code challenge here',
});
```

A `state` field can be added to the authorization. This field is not processed by the platform, and should simply be returned alongside the authorization code to the application's callback. Supplying it here can be helpful for debugging the flow, as it may give a hint as to which request the authorization was created for.

```javascript
await exh.auth.oauth2.authorizations.create({
  responseType: 'code',
  clientId: 'your client id here',
  state: 'your state',
});
```

### Retrieve a list of authorization codes

You can retrieve a list of active authorization codes and the applications they correspond to.

```javascript
await exh.auth.oauth2.authorizations.find({
  rql: //optional rql query
});
```

### Revoking authorization codes

You can revoke tokens by use the deleteAuthorization function.

```javascript
await exh.auth.oauth2.authorizations.remove(authorizationId);
```

## Tokens

OAuth2 authentication in Extra Horizon uses two token types: **access tokens** and **refresh tokens**.\
\
After successful authentication, you will receive an access token and a refresh token.\
\- Access tokens are short-lived and used to authorize the API requests\
\- Refresh tokens are longer-lived and are used to obtain a new access token when the current one expires.

### Access Tokens

#### Retrieving a list of access tokens

The following code snippet will return a list of access tokens and the refresh tokens they correspond to, filterable with RQL.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
await exh.auth.oauth2.tokens.find({
  rql: // Optional RQL query
});
```

{% endtab %}
{% endtabs %}

#### Removing an access token

The following code snippet will remove an access token with the provided id.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
await exh.auth.oauth2.tokens.remove(tokenId);
```

{% endtab %}
{% endtabs %}

### Refresh Tokens

#### Retrieving a list of refresh tokens

The following code snippet will return a list of refresh tokens, filterable with RQL.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
await exh.auth.oauth2.refreshTokens.find({
  rql: // Optional RQL query
});
```

{% endtab %}
{% endtabs %}

#### Removing a refresh token

The following code snippet will remove a refresh token with the provided id.

{% tabs %}
{% tab title="JavaScript" %}

```javascript
await exh.auth.oauth2.refreshTokens.remove(refreshTokenId);
```

{% endtab %}
{% endtabs %}
