AWS Amplify を使用して Vue.js から AWS API にリクエストする方法
背景
- Amplify Gen 1 でフロントエンドアプリケーションを実装していた
- フロントエンドから API Gateway 経由で Lambda 関数を実行していた
- Lambda 関数から AWS API にリクエストしていた
- 特定の処理ごとに Lambda 関数を作成していたため機能拡張によって関数の管理が複雑化していた
- フロントエンドからリクエストすることでバックエンドリソースの削減することが目的
実装の概要
- Amplify CLI で認証機能を追加
- Cognito ID プールに紐づく IAM ロールの認証情報をフロントエンドから取得
- IAM ロールの認証情報と権限で AWS API にリクエスト
前提
- Amplify Gen 1 を使用
- Vue.js のプロジェクトを作成済み
- プロジェクトフォルダで
amplify initコマンドを実行済み
01. Amplify CLI で認証機能を追加
Set up Amplify Auth - Vue - AWS Amplify Gen 1 Documentation
amplify add auth コマンドで認証機能を追加することで自動的に Cognito ユーザープールおよび ID プールが作成されます。
$ amplify add auth
# 設定値はデフォルト
How do you want users to be able to sign in? Username
Do you want to configure advanced settings? No, I am done.
$ amplify push


02. Cognito ID プールのゲストロールに権限を追加
手順 01 で作成された Cognito ユーザープールにユーザーを追加します。

次に、Cognito ID プールの IAM ロールに権限を追加します。
ID プールには認証されたロールとゲストロールがありますが、今回はログインなしで動作確認したいのでゲストロールを使用します。

デフォルトではゲストロールにアクセス権限が付与されていないため、Amplify CLI からカスタムリソースで権限を付与します。
Amplify CLI のカスタムリソースを CloudFormation で作成してみた
$ amplify add custom
✔ How do you want to define this custom resource? · AWS CloudFormation
✔ Provide a name for your custom resource · customResourcef734e541
✔ Do you want to access Amplify generated resources in your custom CloudFormation file? (y/N) · no
✅ Created skeleton CloudFormation stack in amplify/backend/custom/customResourcef734e541 directory
✔ Do you want to edit the CloudFormation stack now? (Y/n) · no
上記コマンド実行後、amplify/backend/custom/<resource-name> というディレクトリに <resource-name>-cloudformation-template.json というファイルが作成されます。
このファイルが CloudFormation テンプレートになっているため、テンプレートにリソースを定義することで Amplify CLI からカスタムリソースを作成することができます。
今回は以下のようにテンプレートを編集しました。
{
"AWSTemplateFormatVersion": "2010-09-09",
"Parameters": {
"env": {
"Type": "String"
},
"UnauthRoleName": {
"Type": "String"
}
},
"Resources": {
"AdminAccessPolicyAttachment": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyName": "admin-access-attachment",
"Roles": [
{
"Ref": "UnauthRoleName"
}
],
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
}
}
}
}
ゲストトールに対して AdministratorAccess と同じ権限を付与するという内容です。
今回は検証なので強力なを付与しましたが、要件に合わせて必要な権限を付与してください。
次にパラメーターファイルである parameters.json を上記テンプレートファイルと同じディレクトリに作成して以下を記載します。
{
"UnauthRoleName": {
"Ref": "UnauthRoleName"
}
}
この状態でデプロイします。
$ amplify push
Current Environment: dev
┌──────────┬────────────────────────┬───────────┬───────────────────┐
│ Category │ Resource name │ Operation │ Provider plugin │
├──────────┼────────────────────────┼───────────┼───────────────────┤
│ Custom │ customResourcef734e541 │ Create │ awscloudformation │
├──────────┼────────────────────────┼───────────┼───────────────────┤
│ Auth │ myprojectc3d666c1 │ No Change │ awscloudformation │
└──────────┴────────────────────────┴───────────┴───────────────────┘
? Are you sure you want to continue? (Y/n) · yes
デプロイ完了後、ゲストロールに権限が付与されていることを確認します。

03. Cognito ID プールの設定変更
Amplify CLI から作成された Cognito ID プールのデフォルト設定を変更します。
- ゲストアクセス: デフォルトでは無効なので有効化
- 基本 (クラシック) 認証: デフォルトでは無効なので有効化
ゲストアクセスについては以下のコマンドで有効化します。
$ amplify auth update
What do you want to do? Walkthrough all the auth configurations
Select the authentication/authorization services that you want to use: User Sign-Up, Sign-In, connected with AWS IAM controls (Enables per-user Storage features for images or other content,
Analytics, and more)
# ここでゲストアクセスを有効化
Allow unauthenticated logins? (Provides scoped down permissions that you can control via AWS IAM) Yes
# 以降は基本的にデフォルト設定
Do you want to enable 3rd party authentication providers in your identity pool? No
Do you want to add User Pool Groups? No
Do you want to add an admin queries API? No
Multifactor authentication (MFA) user login options: OFF
Email based user registration/forgot password: Enabled (Requires per-user email entry at registration)
Specify an email verification subject: test
Specify an email verification message: Your verification code is {####}
Do you want to override the default password policy for this User Pool? No
Specify the app's refresh token expiration period (in days): 30
Do you want to specify the user attributes this app can read and write? No
Do you want to enable any of the following capabilities?
Do you want to use an OAuth flow? No
? Do you want to configure Lambda Triggers for Cognito? No
基本 (クラシック) 認証については以下の手順で有効化します。
$ amplify override auth
Only one option for [Which resource would you like to add overrides for?]. Selecting [myprojectc3d666c1].
✅ Successfully generated "override.ts" folder at /home/ec2-user/environment/my-project/amplify/backend/auth/myprojectc3d666c1
✔ Do you want to edit override.ts file now? (Y/n) · yes
Could not find selected code editor (Visual Studio Code) on your machine.
? Try opening with system-default editor instead? Yes
Unable to open /home/ec2-user/environment/my-project/amplify/backend/auth/myprojectc3d666c1/override.ts: spawn xdg-open ENOENT
Have you installed `xdg-utils` on your machine?
? Press enter to continue
上記コマンド実行後、amplify/backend/auth/<プロジェクト名>/override.ts というファイルが作成されるので以下の内容を定義します。
import { AmplifyAuthCognitoStackTemplate, AmplifyProjectInfo } from '@aws-amplify/cli-extensibility-helper';
export function override(resources: AmplifyAuthCognitoStackTemplate, amplifyProjectInfo: AmplifyProjectInfo) {
resources.identityPool.allowClassicFlow = true;
}
以上の設定後にデプロイします。
$ amplify push
デプロイ完了後、各種設定が有効になっていることを確認します。


04. IAM ロールの認証情報を取得
Advanced workflows - Vue - AWS Amplify Gen 1 Documentation
実装方法については上記ドキュメントを参考にしました。
import { fetchAuthSession } from 'aws-amplify/auth';
import Route53 from 'aws-sdk/clients/route53';
async function changeResourceRecordSets() {
try {
const { credentials } = await fetchAuthSession();
const route53 = new Route53({
apiVersion: '2013-04-01',
credentials
});
// more code working with route53 object
//route53.changeResourceRecordSets();
} catch (err) {
console.log(err);
}
}
fetchAuthSession のレスポンスとして認証情報を取得できます。
この認証情報を AWS API へのリクエストに含めることで IAM ロールの権限でリクエストが可能になります。
なお、以前は Auth.currentCredentials で認証情報を取得する方法もありましたが現在は非推奨になっています。
Migrate from v5 to v6 - JavaScript - AWS Amplify Gen 1 Documentation
Auth.currentCredentials (DEPRECATED)
This API has been deprecated: existing use cases can be migrated to the fetchAuthSession API. Note that fetchAuthSession will throw an error if there is no authenticated user. See the migration notes on Auth.currentSession for more details on how credentials differ between v5 and v6.
しかしながら上記コードだけでは以下のエラーが発生する可能性があります。
UnauthorizedOperation: You are not authorized to perform this operation. User: arn:aws:sts::012345678901:assumed-role/amplify-myproject-dev-0e33f-unauthRole/CognitoIdentityCredentials is not authorized to perform: xxx because no session policy allows the xxx action
この事象については以下の GitHub で報告されています。
Cognito unauthenticated user not authorized to perform: ssm:GetParameter because no session policy allows · Issue #4303 · aws/aws-sdk-js
簡潔に整理すると以下の通りです。
- fetchAuthSession() の拡張フローではデフォルトのセッションポリシーが自動付与される
- デフォルトのセッションポリシーではドキュメントに記載されているアクションのみが許可される
- デフォルトのセッションポリシーで許可されていないアクションでは上述のエラーが発生する
- 回避策としては基本 (クラシック) 認証で GetId > GetOpenIdToken > AssumeRoleWithWebIdentity を使用する方法がある
上記の Issue も踏まえて App.vue の内容は以下の定義となりました。
App.vue
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<button @click="describeImages()">テスト</button>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import { CognitoIdentityClient, GetIdCommand, GetOpenIdTokenCommand } from "@aws-sdk/client-cognito-identity";
import { STSClient, AssumeRoleWithWebIdentityCommand } from "@aws-sdk/client-sts";
import { EC2Client, DescribeImagesCommand } from "@aws-sdk/client-ec2";
const REGION = "ap-northeast-1";
const IDENTITY_POOL_ID = "my-id-pool-id";
const UNAUTH_ROLE_ARN = "arn:aws:iam::012345678901:role/amplify-myproject-dev-0e33f-unauthRole";
export default {
name: 'App',
components: {
HelloWorld
},
methods: {
async describeImages() {
try {
const cognitoClient = new CognitoIdentityClient({ region: REGION });
const { IdentityId } = await cognitoClient.send(
new GetIdCommand({ IdentityPoolId: IDENTITY_POOL_ID })
);
const { Token } = await cognitoClient.send(
new GetOpenIdTokenCommand({ IdentityId })
);
const stsClient = new STSClient({ region: REGION });
const { Credentials } = await stsClient.send(
new AssumeRoleWithWebIdentityCommand({
RoleArn: UNAUTH_ROLE_ARN,
RoleSessionName: "CognitoSession",
WebIdentityToken: Token
})
);
const ec2 = new EC2Client({
region: REGION,
credentials: {
accessKeyId: Credentials.AccessKeyId,
secretAccessKey: Credentials.SecretAccessKey,
sessionToken: Credentials.SessionToken
}
});
const params = {
Filters: [
{
Name: "is-public",
Values: ["false"]
}
]
};
const command = new DescribeImagesCommand(params);
const result = await ec2.send(command);
console.log(result);
} catch (err) {
console.log(err);
}
}
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
なお、main.js については以下の内容で定義しました。
import Vue from 'vue'
import App from './App.vue'
import { Amplify } from 'aws-amplify';
import awsconfig from './aws-exports';
Amplify.configure(awsconfig);
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
05. 動作確認
以下のコマンドでアプリケーションを起動します。
$ npm run serve
起動後に開発者ツールを開き、テストボタンをクリックしてコンソールに以下の情報が表示されれば成功です。
{Images: Array(4), $metadata: {…}}

まとめ
今回は AWS Amplify を使用して Vue.js から AWS API にリクエストする方法を紹介しました。
どなたかの参考になれば幸いです。
参考資料
- Set up Amplify Auth - Vue - AWS Amplify Gen 1 Documentation
- Amplify CLI のカスタムリソースを CloudFormation で作成してみた
- Advanced workflows - Vue - AWS Amplify Gen 1 Documentation
- Migrate from v5 to v6 - JavaScript - AWS Amplify Gen 1 Documentation
- Cognito unauthenticated user not authorized to perform: ssm:GetParameter because no session policy allows · Issue #4303 · aws/aws-sdk-js
- IAM roles - Amazon Cognito
Discussion