# @relotus/keycloak

> react keycloak package

Latest version **1.0.1** (published 2023-09-05) · Apache-2.0 license · 0 weekly downloads

## Install

```sh
npm install @relotus/keycloak
pnpm add @relotus/keycloak
yarn add @relotus/keycloak
bun add @relotus/keycloak
```

## Health

**Score 20/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities.

Warnings: low downloads; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 1.0.1 |
| Published | 2023-09-05 |
| First published | 2023-08-28 |
| Weekly downloads | 0 |
| License | Apache-2.0 |
| TypeScript types | bundled |
| Module format | CommonJS |
| Node | ^16.0.0 |
| Dependencies | 5 |
| Unpacked size | 46 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 3 |
| Maintainers | syomochkin, greykor, sedx |

## Links

- npm: https://www.npmjs.com/package/@relotus/keycloak
- Repository: https://github.com/react-lotus/relotus
- Homepage: https://github.com/react-lotus/relotus#readme
- Issues: https://github.com/react-lotus/relotus/issues
- npm.io page: https://npm.io/package/@relotus/keycloak

## Dependencies (5)

- [events](https://npm.io/package/events.md) 3.3.0
- [redux-saga](https://npm.io/package/redux-saga.md) 1.1.3
- [keycloak-js](https://npm.io/package/keycloak-js.md) 22.0.1
- [@react-keycloak/web](https://npm.io/package/@react-keycloak/web.md) 3.4.0
- [@react-keycloak/core](https://npm.io/package/@react-keycloak/core.md) 3.2.0

## Recent versions

- 1.0.1 (latest) — 2023-09-05
- 1.0.0 — 2023-08-28

## README

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

- [`@relotus/keycloak`](#relotuskeycloak)
  - [Описание](#%D0%BE%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5)
  - [Подключение в проект](#%D0%BF%D0%BE%D0%B4%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%B2-%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82)
    - [Установка:](#%D1%83%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0)
    - [Пример использования](#%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80-%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

# `@relotus/keycloak`

## Описание

@relotus/keycloak - npm-пакет для работы авторизации в корпоративном Keycloak

## Подключение в проект

### Установка:

```sh
npm install @relotus/keycloak
```

### Пример использования

Для использования Keycloak в приложении его необходимо проинициализировать:

```ts
import { initKeycloak } from '@relotus/keycloak';

const KeycloakProvider = initKeycloak({
  url: config.AUTH_HTTP,
  realm: config.AUTH_REALM,
  clientId: config.AUTH_CLIENT_ID,
});
```

`KeycloakProvider` - это компонент, в которое необходимо обернуть приложение для работы хуков из этого пакета.

> **ВАЖНО**
>
> Если в вашем проекте используется `ResetErrorBoundary` из `@relotus/utkonos`, то он должен быть ребенком для `KeycloakProvider`, а не наоборот:
>
> ```tsx
> <KeycloakProvider onUserLogin={login} onUserLogOut={logout}>
>   <ErrorBoundary>
>     <Provider store={store}>{appContent}</Provider>
>   </ErrorBoundary>
> </KeycloakProvider>
> ```
>
> В противном случае это приведет к тому, что в случае ошибки будет бесконечный редирект в Keycloak

#### Установка токена для запросов

Для упрощения работы с токеном, вы можете при вызове `initKeycloak` передать Аxios и для него будет установлен интерцептор:

```ts
import { initKeycloak } from '@relotus/keycloak';

const KeycloakProvider = initKeycloak(config, axios);
```

Теперь для каждого запроса будет добавлен заголовок `Authorization` со значением `Bearer ${keycloak.token}`.

Если в вашем приложении используется адаптер поверх Axios то можно использовать функцию `bindInterceptor`. Функция возвращает функцию, вызов которой уберет интерцептор.

```ts
import { initKeycloak } from '@relotus/keycloak';
import { bindInterceptor } from '@relotus/keycloak/src/interceptor';

const KeycloakProvider = initKeycloak(config, axios);
const { keycloak } = KeycloakProvider;

class Api {
  private _axios: AxiosInstance;

  private removeInterceptor: () => void;

  constructor() {
    this._axios = axios.create({
      baseURL: `${config.API_BASE_URL}/web`,
      paramsSerializer: formatParams,
    });
    this.removeInterceptor = bindInterceptor(this._axios, keycloak);
  }
}
```

#### Обработка событий

Есть несколько способов обработать события авторизации:

1. Самый простой - пробросить в KeycloakProvider обработчики для событий авторизации и завершения сессии:

   ```tsx
   import { initKeycloak } from '@relotus/keycloak';

   const KeycloakProvider = initKeycloak(config, axios);

   function App() {
     const handleLogin = useCallback((profile: KeycloakProfile) => {}, []);
     const handleLogout = useCallback(() => {}, []);
     return (
       <KeycloakProvider onUserLogin={handleLogin} onUserLogOut={handleLogout}>
         <MyApp />
       </KeycloakProvider>
     );
   }
   ```

2. Использовать chanel для саги

   ```ts
   import { createKeycloakChannel, events } '@relotus/keycloak/src/saga';

   function* saga() {
     const keycloakChannel = yield call(createKeycloakChannel)
     try {
       while (true) {
         let keycloakEvent = yield take(keycloakChannel)
         if(events.authSuccess(keycloakEvent)){
           // обрабатываем авторизацию;
           const { payload } = keycloakEvent
         }
       }
     } finally {
       if (yield cancelled()) {
         keycloakChannel.close()
       }
     }
   }
   ```

3. Для всех остальных случаев есть возможность подписаться на `AuthClientEvent` напрямую:

   ```ts
   import { initKeycloak } from '@relotus/keycloak';
   const KeycloakProvider = initKeycloak(config, axios);

   const eventName: AuthClientEvent = 'onAuthSuccess';

   const unsubscribe = KeycloakProvider.subscribe(
     eventName,
     ({ keycloak, error }: { error?: AuthClientError; keycloak: KeycloakInstance }) => {
       // Обрабатываем событие
     },
   );

   // Отписываемся
   unsubscribe();
   ```

#### Получение доступа к Keycloak

Для получения доступа в компонентах можно использовать хук `useKeycloak`:

```ts
import { useKeycloak } from '@relotus/keycloak';

const { keycloak } = useKeycloak();
const logout = useCallback(() => {
  keycloak.logout().catch(() => {
    /* обрабатываем ошибку */
  });
}, [toggleDetails]);
```

Вне компонентов, например для вызова `Keycloak#logout()`:

```ts
const { keycloak } = KeycloakProvider;
keycloak.logout().catch(() => {
  /* обрабатываем ошибку */
});
```

#### Проверка ролей

> **ВАЖНО**
>
> Роли настраиваются для `clientId` или `realmId` в админке Keycloak

Для проверки ролей в компоненте можно использовать хук `useHasRole`

```ts
import { useHasRole } from '@relotus/keycloak';

function Component() {
  const hasAdminRole = useHasRole('ADMIN');
  return hasAdminRole ? 'Я админ' : 'Я пользователь';
}
```

Хук проверяет как роли для для `clientId`, так и для `realmId`.

Вне компонента можно воспользоваться вызовом методов `hasRealmRole` (проверка роли для `realmId`) или `hasResourceRole` (проверка роли для `clientId`)

```ts
const isRealmManager = keycloak.hasRealmRole('MANAGER');
const isClientHasAccessToDictionaries = keycloak.hasResourceRole('Dictionaries.READ');
```

Для проверки роли можно воспользоваться утилитой `hasRole`:

```ts
import { hasRole } from '@relotus/keycloak/src/utils';

const { keycloak } = KeycloakProvider;
const hasAdminRole = hasRole(keycloak, 'ADMIN'); // Имеет роль ADMIN для clientId или для realmId
```

#### Mock для тестов

Для удобства тестирования в `setupTests` или в каждом тесте где это необходимо можно добавить:

```ts
import '@relotus/keycloak/src/mock';
```

---
_Source: https://npm.io/package/@relotus/keycloak · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
