API側でCognito認証してアプリ側でCognito認可してamplify

AWS Amplify はすごく便利だけど、レールから外れると難しい。

普通にやると、Cognitoで認証・認可して Pinpoint でPUSH通知が簡単にできる。

ただ、Cognitoの認証部分だけAPI Gateway経由で呼び出すようなシステム構成だと簡単ではない。

Cognitoの認証と認可

Cognitoは、「User Pool」と「Identify Pool」がある。

User Poolはアプリに対して認証を提供してくれて、Identify Poolはユーザーに対して認可を行うことができる。

認可することで、AWSリソースに対してIAM Roleに応じてユーザーがアクセスできる。

ちなみに、認可は認証しなくても使える。(認証済み or 未認証で Role を分けれる)

認証する場合は、User Pool や Facebook認証などを Provider として設定できる。

アプリで認証しない

システムの都合上、API Gateway を介して Cognito認証する必要があって、その場合は普通には出来ない。

aws-amplify/amplify-js では、アプリ側で Cognito認証を行ってそのまま認可まで行くことを想定しているので、

API経由で認証する場合は、自分でamplifyを認証状態にする必要がある。

その前に、ConsoleLoggerのLOG_LEVELをDEBUGにしておくと調査が捗る。

結構ログを出してくれているので、エラーが出たら、Githubでソースを検索して問題の処理を見てく感じで。

import {ConsoleLogger} from '@aws-amplify/core'

ConsoleLogger.LOG_LEVEL = 'DEBUG'

前提になりますが、configureはこんな感じで。

今回は、インフラ構築にamplify cliは使ってないので、aws-exprots.jsは使ってない。

Amplify.configure({
  Auth: {
    identityPoolId: 'ap-northeast-1:XXXX-XXXX-XXXX',
    userPoolId: 'ap-northeast-1_XXXXXXX',
    userPoolWebClientId: 'XXXXXXXXXXXXXXXX',
    region: 'ap-northeast-1',
  },
  Analytics: {
    AWSPinpoint: {
      appId: 'XXXXXXXXXXXXXXXXXX',
      region: 'us-east-1',
    },
  },
})

APIからのレスポンスで、Credentialsを設定する(認証状態にする)

import {
  CognitoUserSession,
  CognitoIdToken,
  CognitoAccessToken,
  CognitoRefreshToken,
} from 'amazon-cognito-identity-js'
import {Credentials} from '@aws-amplify/core'

...
const {token} = result.payload

const session = new CognitoUserSession({
  IdToken: new CognitoIdToken({IdToken: token.idToken}),
  AccessToken: new CognitoAccessToken({AccessToken: token.accessToken}),
  RefreshToken: new CognitoRefreshToken({
    RefreshToken: token.refreshToken,
  }),
})

await Credentials.set(session, 'session')
...

これで、認証状態になるので、User Poolで認証してIdentify Poolで認証済みのRoleを持ったもので認可できる。

まあ、わかれば簡単なのだけど。

トラブルシューティング

Identify Poolの未認証と認証のRoleを逆に設定してしまって1日はまった :|