たごもりすメモ

コードとかその他の話とか。

amplify-swiftを使ってAmazon CognitoでFederated Loginするときにクライアント設定で不必要なIdentity Providerを有効にしない

ていうか有効にしていたつもりもなかったんだけどamplify-swiftがそう動いてしまう、そしてエラーになる、という話。

結論としては、iOSアプリ側にあるamplifyconfiguration.jsonにおいて不必要なキーCredentialsProviderが存在すると自動的に使われてしまいエラーになるので、キーそのものを削除しなければならない。

経緯

Amazon Cognitoを、Google/Facebookその他IDプロバイダーのOAuth認証を通すために使っているが、IdentityProviderとしては使っていない。Web(React)で作っている画面の方ではJS用のAmplifyライブラリを経由していてログインができるんだけど、iOSアプリでSwiftからログイン用の機能を呼び出すと、なんかうまくいかない。認証用の画面が出てきてIDプロバイダー(Google)での認証が通ったあとに画面が閉じて成功も失敗も処理が走らない、という状況になってしまう。

該当のコードはこんな感じなんだけど、signInWithWebUIが呼ばれたあとのsignInResultが返ってこず、また例外も出てない。:

    @IBAction func tapSignInButton() {
        Task {
            do {
                print("Signing in...")
                let signInResult = try await Amplify.Auth.signInWithWebUI(for: .google, presentationAnchor: self.view.window!, options: .preferPrivateSession())
                print("SignInResult: \(signInResult)")
                if signInResult.isSignedIn {
                    // let attributes = try await Amplify.Auth.fetchUserAttributes()
                    // print("Sign in succeeded, attributes:\(attributes)")
                    print("Sign in succeeded")
                }
                print("Quitting the sign in flow...")
            } catch let error as AuthError {
                print("Sign in failed \(error)")
            } catch {
                print("Unexpected error: \(error)")
            }
        }
    }

なお設定ファイルamplifyconfiguration.jsonは、チュートリアルに従えば作成されるはずなんだけど従っていない*1ので、あれこれ調べて自分で以下のように設定していた。

{
    "auth": {
        "plugins": {
            "awsCognitoAuthPlugin": {
                "IdentityManager": {
                    "Default": {}
                },
                "CredentialsProvider": {
                    "CognitoIdentity": {
                        "Default": {
                            "PoolId": "[IDENTITY_POOL_IS_NOT_USED]",  // これはこの通りに書いてある
                            "Region": "ap-northeast-1"
                        }
                    }
                },
                "CognitoUserPool": {
                    "Default": {
                        "PoolId": "ap-northeast-1_mypool_id",
                        "AppClientId": "my--app--client--id",
                        "Region": "ap-northeast-1"
                    }
                },
                "Auth": {
                    "Default": {
                        "authenticationFlowType": "USER_SRP_AUTH",
                        "OAuth": {
                            "WebDomain": "my-cognito-domain.auth.ap-northeast-1.amazoncognito.com",
                            "AppClientId": "my--app--client--id",
                            "SignInRedirectURI": "myapplicationname://",
                            "SignOutRedirectURI": "myapplicationname://",
                            "Scopes": [
                                "email",
                                "openid"
                            ]
                        }
                    }
                }
            }
        }
    }
}

なお最初はWebDomainhttps://my-cognito-domain...のように設定していたところ、signInWithWebUIが呼ばれたところで「アプリケーションが(null)を開こうとしています」みたいなメッセージが出て白いページが出てきて認証が進まなくなるというウケる状態になってた。そのくらいバリデーションしてほしい……。。。https://を削除したら先に進み、認証が完了するはずなのにうまくいかなくなるという状態になった。

ログを取る

いろいろ調べてる途中、こんなコードを入れているコード例を見掛けた。

Amplify.Logging.logLevel = .verbose

ので、自分のアプリのコード内でもAmplifyの設定してるところで入れてみた。

        do {
            try Amplify.add(plugin: AWSCognitoAuthPlugin())
            try Amplify.configure()
            Amplify.Logging.logLevel = .verbose
            print("Amplify configured with auth plugin")
        } catch {
            print("Failed to initialize Amplify with \(error)")
        }

すると次のようなエラーが出ているのがデバッグコンソールに見えた。

1 validation error detected: Value '[IDENTITY_POOL_IS_NOT_USED]' at 'identityPoolId' failed to satisfy constraint: Member must satisfy regular expression pattern: [\\w-]+:[0-9a-f-]+

CredentialsProviderを削除

設定ファイルから以下の部分を削除。

                 "IdentityManager": {
                     "Default": {}
                 },
-                "CredentialsProvider": {
-                    "CognitoIdentity": {
-                        "Default": {
-                            "PoolId": "[IDENTITY_POOL_IS_NOT_USED]",
-                            "Region": "ap-northeast-1"
-                        }
-                    }
-                },
                 "CognitoUserPool": {
                     "Default": {

これでうまく動くようになった。やれやれ。

*1:サーバサイドの設定は既にあるのでいじられても困るんですよ、チュートリアルに従う以外の手順がドキュメントに見付からないのマジ困る