【2023年末: aws-amplify v6対応】ReactでSSO(シングルサインオン)を実装する

2023.12.23

情報システム室 進地 です。

2023年10月に途中まで実装していたaws-amplifyを使ったReactでのSSO処理を、先日実装再開したところaws-amplifyがv6にバージョンアップし色々変わっていて難儀しました。

https://docs.amplify.aws/

このエントリーでは、aws-amplify v6を使ったReactでのSSO実装を記述します。

前提

既にAzureAD等でCognitoユーザプールとの接続設定はできているものとします。 私は、Amazon Cognito user poolの外部IdPとしてAzure ADを設定してみたの記事を参考に設定しました。

Reactコードサンプル

aws-amplify v6によるSSOの実装コードのサンプルを示します。

src/App.js

import React, { useState, useEffect } from 'react'
import AWS from 'aws-sdk';
import { CircularProgress, Box, Button } from "@mui/material";
// 認証にはAmplify Authを利用する
import { Amplify } from 'aws-amplify';
import { Hub } from 'aws-amplify/utils';
import {
  signInWithRedirect,
  fetchUserAttributes,
  getCurrentUser,
  signOut
} from 'aws-amplify/auth';

import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

function App() {
  const [user, setUser] = useState(null);
  const [userAttributes, setUserAttributes] = useState(null);
  const [authInProgress, setAuthInProgress] = useState(false);

  useEffect(async () => {
    setAuthInProgress(true);

    const unsubscribe = Hub.listen("auth", (data) => {
      const { payload } = data;
      switch (payload.event) {
        case "signedIn":
          getUser();
          break;
        case "signedOut":
          setUser(null);
          setUserAttributes(null);
          break;
        default:
          console.log(payload);
      }
    });

    getUser();

    return unsubscribe;
  }, [])

  const getUser = async () => {
    try {
      const currentUser = await getCurrentUser();
      const currentUserAttributes = await fetchUserAttributes();
      setUser(currentUser);
      setUserAttributes(currentUserAttributes);
      setAuthInProgress(false);
    } catch (err) {
      console.log("Not signed in");
      setUser(null);
      setUserAttributes(null);
      setAuthInProgress(true);
      await signInWithRedirect();
    }
  };

  return (
    <Box>
      {authInProgress ? (
        <Box>
          <CircularProgress />
        </Box>
      ) : (
        {user && (
        <Box>
          <Button onClick={async () => await signOut()}>
            サインアウト ({userAttributes?.email})
          </Button>
        </Box>
        )}
      )}
    </Box>
  );
}

export default App;

v5からの主な変更点

Hubaws-amplify/utilsに、signInWithRedirectなどのAuth関連の関数はaws-amplify/authに移動しています。また、Hub.listenのインタフェースも変わっていますので注意が必要です(ハイライト部25〜27行)。

getUser関数でユーザ情報の取得を試み、取得できなければサインインしていないと判断して、catch節でsignInWithRedirectを呼び出して、IdPのログインを促しています。

ハマりポイント

fetchUserAttributesでメールアドレスなどを取得するには、Cognitoユーザプールのアプリケーションクライアント設定でaws.cognito.signin.user.adminスコープの追加が必要です。

See Also: Flutter Amplifyでアプリ(iOS)から自身の属性情報を取得しようとするとエラーとなる際の確認ポイント

参考

Migrate from v5 to v6 - React - AWS Amplify Documentation