🔑

【React】keycloak-jsの使い方と遭遇したエラーまとめ

2022/07/27に公開

はじめに

keycloak-jsを使おうとしてネットの記事を見ていたら、いくつか古いポイントやReact18固有の不具合を踏んだので、記事にしました。
※この記事はkeycloak-jsの使い方に焦点を当てているため、サーバでのセットアップ方法は解説しません

環境

package.jsonの関係する部分だけピックアップしています。

package.json
"dependencies": {
  "keycloak-js": "^18.0.1",
  "react": "^18.2.0",
},
"devDependencies": {
  "typescript": "^4.7.4",
}

使い方

インストール

$ npm i keycloak-js

認証機能を実装

今回はすべてのページをログインしていないと使えないようにしたいので、App.tsxに実装します。
特定のコンポーネントだけ利用したい場合は、適宜該当コンポーネントに対して認証を実装してください。

前提

特に変わったことはしていませんが、念の為App.tsxの初期状態を記載しておきます。
※本来はもう少し記述がありますが、今回の記事には関係ないので適宜省略しています。

App.tsx
import { useState, useEffect } from 'react';
import Keycloak from 'keycloak-js';

const App = () => {
  return (
    <div className="App">
      <p>認証後に表示される予定のコンポーネント</p>
    </div>
  );
};

export default App;

Keycloakを初期化

まずはKeycloakを使うために初期化します。
予め、Keycloakの管理画面からjsonファイルをダウンロードして(どこでも良いですが)public配下においてください。
(Clients → 自分でつけたクライアント名 → Installation から Keycloak OIDC JSON)

App.tsx
import { useState, useEffect } from 'react';
import Keycloak from 'keycloak-js';

const App = () => {
+ const keycloak = new Keycloak('/keycloak.json');

  return (
    <div className="App">
      <p>認証後に表示される予定のコンポーネント</p>
    </div>
  );
};

export default App;

認証後に格納するstateを宣言

次に、認証後に認証情報を格納するstateを宣言します。

App.tsx
import { useState, useEffect } from 'react';
import Keycloak from 'keycloak-js';

+ interface KeycloakState {
+   keycloak: Keycloak | null;
+   authenticated: Boolean;
+ }

const App = () => {
  const keycloak = new Keycloak('/keycloak.json');
+ const [keycloakState, setKeycloakState] = useState<KeycloakState>({
+   keycloak: null,
+   authenticated: false,
+ });

  return (
    <div className="App">
      <p>認証後に表示される予定のコンポーネント</p>
    </div>
  );
};

export default App;

認証処理

最後に認証処理を実装します。

App.tsx
import { useState, useEffect } from 'react';
import Keycloak from 'keycloak-js';

  interface KeycloakState {
    keycloak: Keycloak | null;
    authenticated: Boolean;
  }

const App = () => {
  const keycloak = new Keycloak('/keycloak.json');
  const [keycloakState, setKeycloakState] = useState<KeycloakState>({
    keycloak: null,
    authenticated: false,
  });

+ useEffect(() => {
+   keycloak
+     .init({ onLoad: 'login-required' })
+     .then((authenticated) => {
+       setKeycloakState({ keycloak: keycloak, authenticated: authenticated });
+     })
+     .catch((e) => {
+       console.error(e);
+     });
+ }, []);

  return (
    <div className="App">
+   {keycloakState.authenticated && (
+     <p>認証後に表示される予定のコンポーネント</p>
+   )}
    </div>
  );
};

export default App;

これで認証の実装が完了です。

まとめ

最後にApp.tsxのコード全体を載せておきます。

App.tsx
import { useState, useEffect } from 'react';
import Keycloak from 'keycloak-js';

  interface KeycloakState {
    keycloak: Keycloak | null;
    authenticated: Boolean;
  }

const App = () => {
  const keycloak = new Keycloak('/keycloak.json');
  const [keycloakState, setKeycloakState] = useState<KeycloakState>({
    keycloak: null,
    authenticated: false,
  });

  useEffect(() => {
    keycloak
      .init({ onLoad: 'login-required' })
      .then((authenticated) => {
        setKeycloakState({ keycloak: keycloak, authenticated: authenticated });
      })
      .catch((e) => {
        console.error(e);
      });
  }, []);

  return (
    <div className="App">
    {keycloakState.authenticated && (
      <p>認証後に表示される予定のコンポーネント</p>
    )}
    </div>
  );
};

export default App;

Discussion