---
sidebar_position: 6
---

Authentication in Hyper Fetch consists of two steps. We will introduce changes in the
**[Builder](/documentation/02-Core/Builder.mdx)** instance and subsequent commands created from it.

---

#### First, we need to add code for request authentication

In the example below we are doing it by adding a token header to the currently sent command.

```ts
export const builder = new Builder({ url }).onAuth((command) => {
  // Redux store or any other storage to get current value of token
  const state = store.getState();
  const authToken = state.auth.token;

  // For every authenticated command we want to
  // add the header with token and return the extended command
  return command.setHeaders({
    ...command.headers,
    Authorization: `Bearer ${authToken}`,
  });
});
```

#### The second step is to put the `auth: true` option in the command to make it available for `onAuth` method of builder.

```ts
export const getUsers = builder.createCommand()({
  endpoint: "/users",
  auth: true,
});
```

That's it, from now on, each request made using this command will be authenticated with our token.

### Refresh token

To refresh the token, we can add a special `onError` interceptor to our
**[Builder](/documentation/02-Core/Builder.mdx)**. It intercepts errors received in our requests and it is asynchronous,
which allows for efficient handling of such cases.

To properly **`avoid the infinite refresh loop`** of the token, we need to protect ourselves by setting the `used` field
to **true** thanks to the appropriate method `setUsed`. This will allow us to easily verify whether our commend has
already gone through the intercept process or not.

### Example

```ts
export const builder = new Builder({ url }).onError(async (response, command) => {
  const status = response[2];
  const refreshToken = localStorage.getItem(REFRESH_TOKEN_STORAGE_FIELD);

  // Check if command has the used value - this will ensure you to
  // not go into infinite loop and trigger this operation only once
  if (!command.used && refreshToken && status === 401) {
    // Prepare the refresh token command
    const postRefreshToken = builder.createCommand<LoginResponse, LoginData>()({
      endpoint: "/refresh-token",
      method: "POST",
    });

    // Call the command to receive new tokens
    const [data] = await postRefreshToken.setData({ refreshToken }).exec();

    if (data) {
      // Safe the new tokens
      localStorage.setItem(TOKEN_STORAGE_FIELD, data.token);
      localStorage.setItem(REFRESH_TOKEN_STORAGE_FIELD, data.refreshToken);
      // Repeat the request and set it "used"
      return command.setUsed(true).send();
    }
  }
  // Return the initial response is something goes wrong
  return response;
});
```
