🐕

【Flutter × AWS without Amplify】IAM認証のかかったAPI Gatewayにアクセスするときの備忘録

2023/05/05に公開

サマリ

  • Cognito オーソライザの場合は session!.getIdToken().getJwtToken()で良かった
  • IAM 認証の場合は SigV4Request の header を使う必要がある
  • サンプルコードが null 許容になってて使えないので、null 許容じゃない型に変換して使う

使用パッケージ

amazon_cognito_identity_dart_2
https://pub.dev/packages/amazon_cognito_identity_dart_2

エラーの内容

サンプルコードのまま実装していくとこのようにエラーとなってしまいます。

なお、API Gateway の認可設定で IAM ではなく Cognito オーソライザを使用する場合は、ヘッダーに直接'Authorization': session!.getIdToken().getJwtToken()のように追加してあげるだけで動作していました。

https://zenn.dev/gekitenius/articles/cf6f75c4307738

修正

For API Gateway & Lambda
Signing requests for authenticated users for access to secured routes to API Gateway and Lambda.

import 'package:http/http.dart' as http;
import 'package:amazon_cognito_identity_dart_2/cognito.dart';
import 'package:amazon_cognito_identity_dart_2/sig_v4.dart';

void main() async {
  final credentials = CognitoCredentials(
      'ap-southeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx', userPool);
  await credentials.getAwsCredentials(session.getIdToken().getJwtToken());

  const endpoint =
      'https://xxxx.execute-api.ap-southeast-1.amazonaws.com/dev';
  final awsSigV4Client = AwsSigV4Client(
      credentials.accessKeyId, credentials.secretAccessKey, endpoint,
      sessionToken: credentials.sessionToken,
      region: 'ap-southeast-1');

  // signedRequest.headersの型がMap<String, String?>?となっていて、後続の
  // リクエストヘッダを設定する時にエラーになります
  final signedRequest = SigV4Request(awsSigV4Client,
      method: 'POST',
      path: '/projects',
      headers: Map<String, String>.from(
          {'header-1': 'one', 'header-2': 'two'}),
      queryParams: Map<String, String>.from({'tracking': 'x123'}),
      body: Map<String, dynamic>.from({'color': 'blue'}));

  // リクエストヘッダに設定するため、Map<String, String>?に変換します
+ Map<String, String> nonNullableSignedRequestHeaders = Map.fromEntries(
+ sigV4Request.headers?.entries.where((entry) => entry.value != null).map(
+             (entry) => MapEntry(entry.key, entry.value!),
+           ) ??
+       [],
+ );

  http.Response response;

  try {
    response = await http.post(
      signedRequest.url,
-      headers: signedRequest.headers,
+       headers: nonNullableSignedRequestHeaders,
      body: signedRequest.body,
    );
  } catch (e) {
    print(e);
  }
  print(response.body);
}

Discussion