AWS Amplify Gen 2 でユーザープールのカスタム属性を設定し、標準サインアップ画面で使用してみた

AWS Amplify Gen 2 でユーザープールのカスタム属性を設定し、標準サインアップ画面で使用してみた

Clock Icon2024.08.23

いわさです。

マルチテナントっぽい Web アプリケーションのプロトタイプを Amplify Gen 2 で作成しています。

Amplify Gen 2 のデフォルト認証プロバイダーは Cognito ユーザープールが使われるわけですが、マルチテナントのプール型で作成するのであればユーザープールのカスタム属性としてテナントコンテキストは最低限設定しておきたいところです。

今回は Amplify Gen 2 の Auth コンポーネントからカスタム属性を設定してみたのですが、ちょっとエラーが発生したので解決方法などもまとめておきたいと思います。

カスタム属性の設定方法

まず、カスタム属性の設定方法自体は公式ドキュメントでも紹介されており、そのとおり対応するだけです。

https://docs.amplify.aws/react/build-a-backend/auth/concepts/user-attributes/

defineAuth 内で認証に関する構成を定義出来るのですが、userAttributesプロパティを指定することで追加の属性を指定出来ます。
Cognito 標準属性が指定出来るのですが、文字列で指定することでカスタム属性も指定出来ます。注意点としてはプレフィックスがcustom:である点です。これはまぁ Cognito の仕様なのであまり違和感はないです。

次のようにカスタム属性を定義してみました。

hoge0817amplify/amplify/auth/resource.ts
import { defineAuth } from '@aws-amplify/backend';
import { preSignUp } from './pre-sign-up/resource';

/**
 * Define and configure your auth resource
 * @see https://docs.amplify.aws/gen2/build-a-backend/auth
 */
export const auth = defineAuth({
  loginWith: {
    email: true,
  },
  triggers: {
    preSignUp
  },
  userAttributes: {
    "custom:tenant_id": {
      dataType: "String",
      mutable: true,
    },
  },
});

does not exist in type 'StandardAttributes' エラーが発生

ここで問題が発生しまして、サンドボックス環境のバックエンドリソースをデプロイしようとしたところ次のエラーが発生してデプロイに失敗しました。

% npx ampx sandbox   
[Sandbox] Pattern !.vscode/extensions.json found in .gitignore. ".vscode/extensions.json" will not be watched if other patterns in .gitignore are excluding it.

  Amplify Sandbox

  Identifier:   iwasa.takahito
  Stack:        amplify-amplifyvitereacttemplate-iwasatakahito-sandbox-c16ed1c1a8

  To specify a different sandbox identifier, use --identifier

amplify/auth/resource.ts(16,5): error TS2353: Object literal may only specify known properties, and '"custom:tenant_id"' does not exist in type 'StandardAttributes'.
TypeScript validation check failed.
Resolution: Fix the syntax and type errors in your backend definition.

[Sandbox] Watching for file changes...

StandardAttributes しか設定できないような気がします。
参照モジュールの中身を見てみても次のような感じ。なんだかドキュメントの記載のとおり文字列を指定出来るようには見えないです。

8B757373-C066-42FD-9A93-7AB26A189088.png

しかし、Amplify Backend の GitHub リポジトリを確認してみたところ、リモートリポジトリでは別の型になってます。なんか指定出来そうだな...

https://github.com/aws-amplify/amplify-backend/blob/5405c878bd6aa55becab504d91369893701daf20/packages/auth-construct/src/types.ts#L380C1-L430C35

更新履歴を確認したところ、このカスタム属性を設定出来るようにする機能は 7 月 17 日にマージされたばかりの機能でした。

https://github.com/aws-amplify/amplify-backend/pull/1732

で、今使っているプロジェクトは公式ドキュメントの Quickstart を元にテンプレートから作成したものです。
そのため package.json で参照されているパッケージが古かったようです。なるほど。

% npm outdated
Package                           Current   Wanted   Latest  Location                                       Depended by
@aws-amplify/backend                1.0.4    1.1.1    1.1.1  node_modules/@aws-amplify/backend              hoge0817amplify
@aws-amplify/backend-cli            1.1.1    1.2.4    1.2.4  node_modules/@aws-amplify/backend-cli          hoge0817amplify
@aws-amplify/ui-react              6.1.13    6.2.0    6.2.0  node_modules/@aws-amplify/ui-react             hoge0817amplify
@types/react                       18.3.3   18.3.4   18.3.4  node_modules/@types/react                      hoge0817amplify
@typescript-eslint/eslint-plugin   7.16.1   7.18.0    8.2.0  node_modules/@typescript-eslint/eslint-plugin  hoge0817amplify
@typescript-eslint/parser          7.16.1   7.18.0    8.2.0  node_modules/@typescript-eslint/parser         hoge0817amplify
aws-amplify                         6.5.1    6.5.2    6.5.2  node_modules/aws-amplify                       hoge0817amplify
aws-cdk                           2.149.0  2.154.0  2.154.0  node_modules/aws-cdk                           hoge0817amplify
aws-cdk-lib                       2.149.0  2.154.0  2.154.0  node_modules/aws-cdk-lib                       hoge0817amplify

:

パッケージのバージョンアップを行いました。

{
  "name": "amplify-vite-react-template",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview"
  },
  "dependencies": {
    "@aws-amplify/ui-react": "^6.2.0",
    "aws-amplify": "^6.5.2",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  },
  "devDependencies": {
    "@aws-amplify/backend": "^1.1.1",
    "@aws-amplify/backend-cli": "^1.2.4",
    "@types/aws-lambda": "^8.10.143",
    "@types/react": "^18.2.66",
    "@types/react-dom": "^18.2.22",
    "@typescript-eslint/eslint-plugin": "^7.2.0",
    "@typescript-eslint/parser": "^7.2.0",
    "@vitejs/plugin-react": "^4.2.1",
    "aws-cdk": "^2.138.0",
    "aws-cdk-lib": "^2.138.0",
    "constructs": "^10.3.0",
    "esbuild": "^0.20.2",
    "eslint": "^8.57.0",
    "eslint-plugin-react-hooks": "^4.6.0",
    "eslint-plugin-react-refresh": "^0.4.6",
    "tsx": "^4.7.2",
    "typescript": "^5.4.5",
    "vite": "^5.2.0"
  }
}

バージョンアップ後はサンドボックスのバックエンドデプロイに成功し、作成された Cognito ユーザープールを見てみると、無事カスタム属性が定義されています。良いですね。

92F3EC01-5A90-41DF-94BB-FF1C2DD15CDC.png

サインアップ画面をカスタマイズする

で、テナント情報を属性として設定出来るようになったのでユーザーに指定したいところです。
ユーザーに入力させるか、あるいはカスタムトリガーで自動でテナントを識別して設定する方法が考えられます。
今回は簡単にユーザー入力させてみようかなと思いますので、標準のサインアップ画面をカスタマイズしましょう。

テンプレートの場合はApp.tsxAuthenticatorコンポーネントが使われています。

src/App.tsx
:
  return (
    <Authenticator>
      {({ signOut }) => (
        <main>
          <h1>My Hoges</h1>
          <button onClick={createHoge}>+ new</button>
          <ul>
            {hoges.map((hoge) => (
              <li key={hoge.id}>{hoge.HogeContent}</li>
            ))}
          </ul>
          <div>
            🥳 App successfully hosted. Try creating a new Hoge.
            <br />
            <a href="https://docs.amplify.aws/react/start/quickstart/#make-frontend-updates">
              Review next step of this tutorial.
            </a>
          </div>
          <button onClick={signOut}>Sign out</button>
        </main>
      )}
    </Authenticator>
  );
}

このコンポーネントですが、カスタマイズ出来るようにいくつかスロットが用意されています。
次の公式ドキュメントを参照しましょう。

https://ui.docs.amplify.aws/react/connected-components/authenticator/customization

formFieldsを設定してやることでカスタム属性を入力出来るようにしました。
フィールド名をカスタム属性名と一致させることでそのままデータ送信先として接続もされるようです。これは簡単だ。

src/App.tsx
:

  const formFields = {
    signUp: {
      "custom:tenant_id": {
        label: 'Hoge Tenant',
        order: 1
      }
    }
  };

  return (
    <Authenticator formFields={formFields}>
      {({ signOut }) => (
        <main>
          <h1>My Hoges</h1>
          <button onClick={createHoge}>+ new</button>
          <ul>
            {hoges.map((hoge) => (
              <li key={hoge.id}>{hoge.HogeContent}</li>
            ))}
          </ul>
          <div>
            🥳 App successfully hosted. Try creating a new Hoge.
            <br />
            <a href="https://docs.amplify.aws/react/start/quickstart/#make-frontend-updates">
              Review next step of this tutorial.
            </a>
          </div>
          <button onClick={signOut}>Sign out</button>
        </main>
      )}
    </Authenticator>
  );
}

export default App;

上記設定にて次のようなフォームが作成されました。良いですね。
登録もしてみましょう。

5C1D6CC9-A75D-4E5F-A8CC-008EECDD2C83.png

ユーザープールのカスタム属性に無事設定されていました。

7111C6E6-5E2E-46F2-A898-5A7F9E54DA19_4_5005_c.jpeg

さいごに

本日は AWS Amplify Gen 2 でユーザープールのカスタム属性を設定し、標準サインアップ画面で使用してみました。

Quickstart のテンプレートから開始している場合などもそうですが、開発環境のパッケージのバージョンアップを怠っているとドキュメントどおりいかなくなることを学びました。

標準コンポーネントも色々とカスタマイズ方法が提供されているのでなかなか良い感じです。
テナントの設定がとりあえず出来るようになったので、次回はこれを使ったデータ分離あたりを行ってみたいと思います。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.