Amplify + Cognito でハマったポイント

AWS Amplifyでネイティブアプリを作っているのですが、思いのほかハマったので、ポイントをここに書き残します。

- Ampliy CLI バージョン 4.52.0 で確認した内容です。

# ハマり1: User PoolのWebアプリとNativeアプリの設定が一致していないとエラーになる

AmplifyでUser Poolを使う場合、WebアプリとNativeアプリの2つがUser PoolのApp Client Settingsに登録されている必要がありますが、各種設定（Identity Provider, Callback/Signout URLs, OAuth Scopeなど）は2つのアプリで一致させておかないとエラーが発生します。例えば以下のようなエラーが出ます。

```
The following OAuth properties are not matching:

Callback URLs:

| web_app | native_app |
| ------- | ---------- |
|         | myapp://   |
```

`amplify add auth` を実行した場合は、設定が一致するようにUser Poolが作成されるのでエラーはでません。`amplify import auth` を実行した際には、設定によってエラーが出たり出なかったりするので、分かりにくいです。仮にエラーが出なくても、次回`amplify pull`を実行した際にエラーが出ます。

# ハマり2: import authのタイミングでは動的生成コードが更新されない

`amplify import auth`を実行しても、動的生成コード（amplifyconfiguration.dart や aws-exports.js など）は更新されないようです。`amplify push`すると更新されます。

# ハマり3: Auth.signUpの結果がiOSとAndroidで異なる
Email Verificationが必要な場合、SignUpResultのisSignUpCompleteの真偽値がiOSとAndroidで一致しないという恐ろしい問題があります。以下は　Flutterでのコード例です。

```dart
final result = await Amplify.Auth.signUp(...);
print(result.nextStep.signUpStep); // CONFIRM_SIGN_UP_STEP
print(result.isSignUpComplete); // iOS は false, Android は true
```

サンプルコードによってはisSignUpCompleteの値を見て条件分岐しているものがあるので、安易に参考にするとAndroidでは動くがiOSでは動かない...という事故が発生します。

2020年の9月には既に[Issueがある](https://github.com/aws-amplify/amplify-ios/issues/760)ようですが、2021年6月現在でも[直っていない](https://github.com/aws-amplify/amplify-flutter/issues/581)ようです。


# ハマり4: Cognito User Pool OnlyにするとAndoridで例外が出る（未解決）

Cognito User Pool Only(Identity Pool を使わない)の場合、 Androidでログイン時に例外が出ます。警告なのでログイン自体は出来ているのですが、盛大にスタックトレースが出るのでなにか設定を間違っているのかとしばらく悩みました。iOSでは特に警告は出ません。

```
W/AWSMobileClient( 7940): Failed to federate tokens during sign-in
W/AWSMobileClient( 7940): java.lang.Exception: Federation is not enabled, please check if you have CognitoIdentity configured.
W/AWSMobileClient( 7940):       at com.amazonaws.mobile.client.AWSMobileClient$10.run(AWSMobileClient.java:1715)
W/AWSMobileClient( 7940):       at com.amazonaws.mobile.client.internal.InternalCallback.await(InternalCallback.java:115)
W/AWSMobileClient( 7940):       at com.amazonaws.mobile.client.AWSMobileClient.federatedSignInWithoutAssigningState(AWSMobileClient.java:1668)
W/AWSMobileClient( 7940):       at com.amazonaws.mobile.client.AWSMobileClient$6$1.onSuccess(AWSMobileClient.java:1200)
W/AWSMobileClient( 7940):       at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser$6.onSuccess(CognitoUser.java:1099)
W/AWSMobileClient( 7940):       at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser$27.run(CognitoUser.java:3098)
W/AWSMobileClient( 7940):       at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser$24.run(CognitoUser.java:2965)
W/AWSMobileClient( 7940):       at com.amazonaws.mobileconnectors.cognitoidentityprovider.continuations.AuthenticationContinuation.continueTask(AuthenticationContinuation.java:147)
W/AWSMobileClient( 7940):       at com.amazonaws.mobile.client.AWSMobileClient$6$1.getAuthenticationDetails(AWSMobileClient.java:1235)
W/AWSMobileClient( 7940):       at com.amazonaws.mobileconnectors.cognitoidentityprovider.CognitoUser.getSession(CognitoUser.java:1032)
W/AWSMobileClient( 7940):       at com.amazonaws.mobile.client.AWSMobileClient$6.run(AWSMobileClient.java:1185)
W/AWSMobileClient( 7940):       at com.amazonaws.mobile.client.internal.InternalCallback$1.run(InternalCallback.java:101)
W/AWSMobileClient( 7940):       at java.lang.Thread.run(Thread.java:919)
```

# ハマり5:　User PoolのWebアプリとNativeアプリのApp client idはIdentity Poolに両方とも追加しなければならない

User Pool　に加えて Identity Pool も使う場合、Identity Pool 側の Authentication Providers の設定で、User Pool ID と App client id を追加する必要があります。ここで、User Pool 側のApp Client Settings に登録した WebアプリとNativeアプリのApp client idのうち、どちらか一方だけを、Identity Pool 側の設定に追加してしまうと、`amplify import auth` 時に次のエラーが出ます。

> There are no Identity Pools found which has the selected Cognito User Pool configured as identity provider.

エラーメッセージが非常に不親切ですが、これはUser Poolに設定されているWebアプリとNativeアプリのApp client idを両方ともIdentity PoolのAuthentication Providersの設定で追加することで解消します。

# ハマリ6: 自動生成コードが正しく生成されなくなることがあった
これは Cognito とは無関係かもしれませんが、import auth, remove auth, push, pull を繰り返していたら、突然 flutter プロジェクトのはずなのに amplifyconfiguration.dart ではなく aws-exports.js が生成されるようになってしまいました。

`amplify init` から改めてやり直したところ復旧しましたが、`amplify configure project` でアプリのフレームワークを再設定しても回復できたかもしれません。