AWS AppSync の Cognito UserPools 認証を行ったユーザーで GraphQL API を実行する


はじめに

GraphQL API を実行する場合、API_KEY を使う場合は API Key 認証として具体的なリクエスト方法が示されている。

$ $ curl -XPOST -H "Content-Type:application/graphql" -H "x-api-key:ABC123" -d '{ "query": "query { movies { id } }" }' https://YOURAPPSYNCENDPOINT/graphql

一方、Cognito UserPools で認証を行っている場合は、どのような情報が必要かの具体例が少なかったので、本記事で説明する。

回答

手順の概要は以下の通り。

  • ログイン可能な Cognito UserPools を作成する (この用途であれば Cognito フェデレーティットアイデンティティは不要)
  • GraphQL API と作成した Cognito UserPools を紐づける
  • Cognito UserPools にログインして ID トークンを取得する
  • GraphQL API にアクセスする際の Authorization ヘッダに ID トークンを載せてアクセスする。
  • Cognito に保存されているユーザー情報による制御を行いたい場合、Resolver 内で ID トークンの内容が参照できるため、これを使って解決する

デフォルトの認証モードとして Cognito UserPools を紐づける場合、マネジメントコンソールであれば 設定 > デフォルトの認証モードから設定できる。

Cognito UserPools にログインして以下の結果が得られたとする(これは cognito-idp admin_initiate_auth を実行して得られた結果)。 この記事では Cognito UserPools の設定やログイン方法については説明しない。

{
  "ChallengeParameters": {},
  "AuthenticationResult": {
    "AccessToken": "eyJraWQiOiJpSlp........",
    "ExpiresIn": 3600,
    "TokenType": "Bearer",
    "RefreshToken": "eyJjdHkiOiJKV1QiLCJlbm......",
    "IdToken": "eyJraWQiOiJ3RU9......"
  },
  "ResponseMetadata": {
    "RequestId": "ed5aaa19-92a4-439f-b686-8a0525818e99",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "date": "Wed, 20 Oct 2021 00:26:58 GMT",
      "content-type": "application/x-amz-json-1.1",
      "content-length": "4098",
      "connection": "keep-alive",
      "x-amzn-requestid": "ed5aaa19-92a4-439f-b686-8a0525818e99"
    },
    "RetryAttempts": 0
  }
}

この時、得られた AuthenticationResult.IdToken をリクエスト時の Authorization ヘッダに設定してアクセスする。 具体的には以下の通り。

$ curl -s -X POST -H "Context-Type: application/graphql" -d '{"query": "{ hello }"}' -H "Authorization: eyJraWQiOiJ3RU9......" https://********.appsync-api.ap-northeast-1.amazonaws.com/graphql

# {"data":{"hello":"This is a fixed string!"}}

初期設定では Cognito にログインして正常な ID トークンさえ持っていればアクセスが可能だが、ユーザー毎にアクセスを制限したい場合、リゾルバー内で $context.identity としてアクセスして ID トークンに含まれる情報を取得し、利用できる。

例えば、$context.identity.claims.get("cognito:groups") によって、ユーザーが所属しているグループ一覧が取得できるため、これを使って「Administratorグループに属していれば PutItem が可能」と言ったリゾルバーマッピングテンプレートを記載できる。

より詳細なユースケースは以下を参照。