Cognitoのログイン情報が書き換わったタイミングを検知するhooks作った
概要
今回はReact
で動作しているSPAで、Cognito
を使っている場合のTipsです。
AWSのコンソールなんかもそうですが、同一ブラウザで複数タブで異なるアカウントで操作しようとすると、元々動かしていた方のアカウントの操作ができなくなり、リロードや再ログインを促されたりします(もしかしたら名称があるかも)。
あの仕組みをそのまま自作したので、たたき台として共有します。
バージョン情報
Reactのバージョンはちょい古めです。
関係してそうなものだけpackage.json
から抜粋。
"@aws-amplify/ui-react": "^5.0.4"
"aws-amplify": "^5.3.4"
"react": "^18.2.0"
簡単に解説
aws-amplify/auth
を使っている場合、特にカスタムしていなければ認証情報はCookieに入っています。
その時のキーは以下のような形式です。
CognitoIdentityServiceProvider.{CLIENT_ID}.{SUB}.XXXX
XXXXの箇所はidToken
やrefreshToken
などが入りますが、それより前の部分は共通のルールです。
複数タブで操作している場合に、片方のタブで別アカウントログイン・もしくはログアウトをした場合、このCookieの値が変わります(もしくはクリアされます)。
なので、Cookieの中身を監視し、変更が検知できたタイミングで何らかの表示をしてあげればいいということになります。
完成したもの
以下が完成したhooksです。
sub
とinterval
を指定して、先ほどのCookieの値を監視する処理を行っています。
※パフォーマンスに影響しそうなので、厳密な仕様でないならinterval
を伸ばしてもいいかもしれません。
import { useEffect, useRef, useState } from "react";
import Cookies from "js-cookie";
const useCognitoCookieChange = (sub: string, interval = 1000) => {
const clientId = import.meta.env.VITE_APP_AUTH_USER_POOL_WEB_CLIENT_ID;
// CognitoをIdProviderとした場合のidTokenが入っているCookie名
const cookieName = `CognitoIdentityServiceProvider.${clientId}.${sub}.idToken`;
const initialCookieValue = useRef(Cookies.get(cookieName));
const [changed, setChanged] = useState<boolean>(false);
useEffect(() => {
const checkCookieChange = () => {
const currentCookieValue = Cookies.get(cookieName);
// 変更検知時
if (currentCookieValue !== initialCookieValue.current) {
// initialの値がなかった(=未ログインからログインした)場合は無視する
if (initialCookieValue.current && !currentCookieValue) setChanged(true);
initialCookieValue.current = currentCookieValue;
}
};
const intervalId = setInterval(checkCookieChange, interval);
return () => clearInterval(intervalId);
}, [cookieName, setChanged, interval]);
return {
changed,
};
};
export default useCognitoCookieChange;
最終的にこのhooksが返す値(changed
)がtrue
になったら「他のタブでログアウトが行われた」もしくは「他のタブで別ユーザでログインが行われた」ということになるので、モーダルやアラートを出してアクションを促します。
自分は「再読み込み」のようなボタンを表示させて、そのタブはリロードさせる運用としています。
おわりに
今回は別タブでのログインやログアウトを検知し、複数アカウントでのログインを防止するhooksについて紹介しました。
割と簡易に作っているので、いくつか穴抜けとなっているケースはあるかと思います。
その場合はマサカリ大歓迎です。
この記事の内容が役立ちましたら幸いです。
Discussion