🫠

[Flutter][AWS]cognitoでログイン機能を実装した時につまづいた内容(アクセストークン認証が通らない?)

2024/09/06に公開

はじめに

この記事ではAWS-AmplifyのCognitoでログインを実装を行なっている方向けの記事となっております。
私はパッケージを利用して実装していたのですが取得できたアクセストークンがうまくJWTの認証に通らなくかなり苦労しました...
※実装の方法ではなくエラーの対応策紹介を行なっていきます。
結論から言うと使用するパッケージを変更しました!

導入パッケージ

他にもインストールしなければならないパッケージはありますが省略します
こちらだとうまくいかなかった...
うまくログインはできている(AWS)と通信などはできているのですがアクセストークンなどの値がJWT認証に通らなかったのです...

こちらで試しました
https://jwt.io/

amplify_auth_cognito: ^2.4.1

こちらで対応しました

こちらのパッケージは非公式ではありますが他に対応できそうなパッケージがないので今回はこちらで実装を試してみます

jwt_decode: ^0.3.1
amazon_cognito_identity_dart_2: ^3.6.5
flutter_web_auth: ^0.5.0

実装

私はGoogleとAppleのログイン実装を行いました。

ファイルの作成(amplify_setting)

まずは下記のように定数を設定してあげる必要があります
こちらは環境毎に分けてあげる必要があるかなと思います。
こちらは.gitignoerに追加お薦めします

//lib/amplidy_setting/amplify_setting_dev.dart
import 'package:amazon_cognito_identity_dart_2/cognito.dart';

const cognitoDomain = 'test-social';

const cognitoUserPoolId = 'ap-northeast-1_〇〇';

const cognitoClientId = 'samplesamplesamplesample';

const callbackScheme = 'sample';

const cognitoOAuthResponseType = 'code';

const cognitoScope = 'openid email profile aws.cognito.signin.user.admin';

final cognitoUserPool = CognitoUserPool(cognitoUserPoolId, cognitoClientId);

エンドポイントのURLを作成

今回はloginとlogout、トークン取得のエンドポイントを作成してくれる関数を作成しました
identityProviderというのがGoogle or SignInWithAppleのどちらかになると思います

import 'package:amazon_cognito_identity_dart_2/cognito.dart';

// 認証エンドポイントのURLを作成
String createOAuthUrl(
  CognitoUserPool cognitoUserPool,
  String cognitoDomain,
  String identityProvider,
  String responseType,
  String callbackScheme,
  String cognitoScope,
) {
  return Uri.https(
    '$cognitoDomain.auth.${cognitoUserPool.getRegion()}.amazoncognito.com',
    '/oauth2/authorize',
    {
      'identity_provider': identityProvider,
      'response_type': responseType,
      'client_id': cognitoUserPool.getClientId(),
      'redirect_uri': '$callbackScheme://',
      'scope': cognitoScope,
      'prompt': 'select_account',
    },
  ).toString();
}

String createLogoutUrl(
  CognitoUserPool cognitoUserPool,
  String cognitoDomain,
  String callbackScheme,
) {
  return Uri.https(
    '$cognitoDomain.auth.${cognitoUserPool.getRegion()}.amazoncognito.com',
    '/logout',
    {
      'client_id': cognitoUserPool.getClientId(),
      'logout_uri': '$callbackScheme://',
    },
  ).toString();
}

Uri createTokenUrl(
  CognitoUserPool cognitoUserPool,
  String cognitoDomain,
) {
  return Uri.https(
    '$cognitoDomain.auth.${cognitoUserPool.getRegion()}.amazoncognito.com',
    '/oauth2/token',
  );
}

ログイン

ログイン自体にはFlutterWebAuthを利用しました。
そのため、先ほど作成したURLを追加します!
これでログイン自体はOKです!

 await FlutterWebAuth.authenticate(
      url: url,
      callbackUrlScheme: callbackUrlScheme,
    );

トークン取得

次は本題のトークン取得となりますがここは少々手間です
実装方法としてはhttpでAPIを呼び出すだけになります。
これでトークン取得までできましたね!

response = await http.post(
        tokenEndpoint,
        headers: {'Content-Type': 'application/x-www-form-urlencoded'},
        body: {
          'grant_type': 'authorization_code',
          'client_id': cognitoUserPool.getClientId(),
          'code': cognitoAuthCode,
          'redirect_uri': '$callbackUrlScheme://',
          'scope': cognitoScope,
          'prompt': 'select_account',
        },
      );

      final refreshToken = json.decode(response.body)['refresh_token'];
      final accessToken = json.decode(response.body)['access_token'];
      final idToken = json.decode(response.body)['id_token'];
      final payload = Jwt.parseJwt(accessToken);

おまけ

リフレッシュトークンの利用方法

リフレッシュトークンを利用するのにhttp通信をしなければならないと思っていたのですがどうやらやらなくても良いみたい!
CognitoUserを作成してしまえばリフレッシュが可能です!

final refreshToken = await SharedPreferenceUtils().refreshToken;
final userName = await SharedPreferenceUtils().providerUserId;
final cognitoUser = CognitoUser(userName, cognitoUserPool);
final session = await cognitoUser.refreshSession(
                    CognitoRefreshToken(refreshToken),
                );

参考資料

こちらの記事を参考に実装を行いました
https://qiita.com/chrg/items/f8a6338796aa5a84bbf6

まとめ

amplify_auth_cognitoが推奨パッケージであったのですがまさかの問題が発生しました...
こちらのパッケージでうまく実装できている内容があれば紹介していただけると幸いです
(実装するのであれば推奨を使いたいですよね...)

Discussion