Nuxt.js + AWS Cognito で認証を実装する

Nuxt.js で AWS Cognito のユーザープールのアカウントで認証を実装する方法を紹介します。本稿は2021年5月時点の情報です。
概要
- 所要時間: 約15分
- 対象:
- Nuxt を使ったアプリ開発をしたことがある方
- AWS Cognito でユーザープールを作成したことがある方
- AWS CLI でアカウント設定済み
 
環境
- Windows 10 Pro
- Node.js 14.16.0
- nuxt 2.15.4
- @nuxtjs/auth-next 5.0.0
- @a1ter/nuxt-auth-aws-cognito-scheme 0.0.12
nuxt/auth について
nuxt/auth には旧バージョンの @nuxtjs/auth と新バージョンの @nuxtjs/auth-next があります。
現行の公式ドキュメントはすべて後者の @nuxtjs/auth-next を対象としたものになっていますが、ネット上の情報は旧バージョンの方が多く、特にストラテジ設定の周辺が変わっているので、ややこしいです。
今回は新バージョンの @nuxtjs/auth-next をベースにしています。
また、nuxt auth はデフォルトでは Cognito に対応していないため、スキーマを自作するか、適当なパッケージを利用する必要があります。
「nuxt auth cognito」などで検索すると @sirdiego/nuxt-auth-cognito-scheme というスキーマが引っかかりますが、こちらは旧バージョン用なのでそのまま利用することはできません。
今回は @a1ter/nuxt-auth-aws-cognito-scheme を利用させていただきました。
認証系なので念のためソースコードも確認しましたが、内部的に Cognito の認証ライブラリである amplify/auth を使っているシンプルな構成なので、あまり問題はなさそうです。
AWS Cognito ユーザープールの作成
先に認証に使う Cognito のユーザープールを作成します。
Cognito のコンソールの [ユーザープールを作成する] を選び、適当なユーザープール名を入力して「デフォルトを確認する」を選びます。ここでは名前を NuxtAuthUserPool としました。
属性の設定の編集ボタンを押します。
サインイン方法の設定で**ユーザー名(任意のユーザー名)**にチェックを入れておきます。
下記のようになっていればとりあえず OK でしょう。
次にアプリクライアントの設定で「アプリクライアントの追加」を選びます。
クライアント名も適当に設定し、 「クライアントシークレットの生成」からチェックを外しておきます。
上記を設定して、保存するとユーザープールが作成されます。
アプリクライアントの設定
左メニューの「アプリの統合」から「アプリクライアントの設定」を選びます。
「有効な ID プロバイダ」で「Cognito User Pool」を選び、「コールバック URL」には http://localhost:3000 を入れておきます。
OAuth のフローは Implicit grant、スコープは email openid profile として保存します。このあたりは必要に応じて設定してください。
今回の例ではドメインの設定は不要です。
接続情報の確認
あとで環境変数に設定するために必要なパラメーターを確認しておきます。
- リージョン: Cognito を作成した AWS のリージョン
- ユーザープールID: ユーザープールの「全体設定」にある「プールID」
- クライアントID: 「全体設定」→「アプリクライアント」で確認できる「アプリクライアントID」
ユーザーの作成とコンファーム
AWS CLI でテスト用のユーザーを Coginito に作成します。コンソールからも行えますが、アカウントのコンファームができず、どのみち CLI を使うため、作成から CLI で行いました。
今回は管理者権限でユーザーを作成しますので、 admin-create-user でユーザーを作り、 admin-set-user-password でステータスを CONFIRMED にします。
$ aws cognito-idp admin-create-user --region <リージョン> --user-pool-id <ユーザープールID> --username <ユーザー名>
{
    "User": {
        "Username": "<ユーザー名>",
        "Attributes": [
            {
                "Name": "sub",
                "Value": "<ユーザーのGUID>"
            }
        ],
        "UserCreateDate": "2021-05-04T09:07:09.481000+09:00",
        "UserLastModifiedDate": "2021-05-04T09:07:09.481000+09:00",
        "Enabled": true,
        "UserStatus": "FORCE_CHANGE_PASSWORD"
    }
}
$ aws cognito-idp admin-set-user-password --region <リージョン> --user-pool-id <ユーザープールID> --username <ユーザー名> --password <パスワード> --permanent
$ aws cognito-idp admin-get-user --region <リージョン> --user-pool-id <ユーザープールID> --username <ユーザー名>
{
    "Username": "<ユーザー名>",
    "UserAttributes": [
        {
            "Name": "sub",
            "Value": "<ユーザーのGUID>"
        }
    ],
    "UserCreateDate": "2021-05-04T09:07:09.481000+09:00",
    "UserLastModifiedDate": "2021-05-04T09:08:04.723000+09:00",
    "Enabled": true,
    "UserStatus": "CONFIRMED"
}Nuxt のセットアップ
Nuxt については create-nuxt-app でもよいですし、スクラッチからでもかまいませんので、適当なプロジェクトを作ってインストールしておきます。
個人的にはスクラッチからインストールするほうが好みです。
ここで package.json が下記の状態とします。
{
  "name": "nuxt-auth-cognito",
  "dependencies": {
    "nuxt": "^2.15.4"
  },
  "scripts": {
    "dev": "nuxt",
    "build": "nuxt build",
    "generate": "nuxt generate",
    "start": "nuxt start"
  }
}vue ファイルの準備
とりあえずデモのため、 pages ディレクトリに簡単な index.vue と login.vue を準備します。
pages/index.vue
<template>
  <div>
    <p>{{ $auth.user }}</p>
    <button @click.prevent="$auth.logout()">Logout</button>
  </div>
</template>pages/login.vue
<template>
  <form>
    <input type="text" v-model="username" placeholder="Username" required autofocus>
    <input type="password" v-model="password" placeholder="Password" required>
    <button @click.prevent="signIn">Sign in</button>
  </form>
</template>Vuex の有効化
Vuex を有効にするため store ディレクトリを作成し、空の index.js を作成しておきます。
$ mkdir store
$ touch store/index.jsnuxt auth のセットアップ
Setup - nuxt auth docs に従い、 nuxt/auth をインストールします。
$ yarn add @nuxtjs/axios
$ yarn add --exact @nuxtjs/auth-next@a1ter/nuxt-auth-aws-cognito-scheme のインストール
nuxt auth はデフォルトでは Cognito に対応していないため、 @a1ter/nuxt-auth-aws-cognito-scheme をインストールします。
$ yarn add @a1ter/nuxt-auth-aws-cognito-schemenuxt.config.js の作成
まだ存在しない場合は nuxt.config.js に下記のように記述します。
{
  ssr: false,
  target: 'static',
  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/auth-next',
  ],
  router: {
    middleware: ['auth'],
  },
  auth: {
    redirect: {
      login: '/login',
      logout: '/login',
      callback: '/callback',
      home: '/',
    },
    strategies: {
      cognito: {
        scheme: '@a1ter/nuxt-auth-aws-cognito-scheme/scheme/scheme',
        credentials: {
          userPoolId: process.env.COGNITO_USER_POOL_ID,
          userPoolWebClientId: process.env.COGNITO_CLIENT_ID,
          region: process.env.COGNITO_REGION
        },
        endpoints: {
          user: false,
        },
      },
    },
  },
}今回は SPA を想定しますので、 ssr: false, target: 'static' とします。
modules に axios と auth-next を追加、 router の middleware に auth を指定することで全てのページで auth モジュールを有効にします。
auth モジュールの設定は auth に記述します。 redirect はデフォルトのままでも動作しますので、定義しなくてもかまいません。
strategies に認証ストラテジを指定します。今回は前述のパッケージを用いて AWS Cognito で認証を行うため、上記のように指定します。 Cognito に関する設定は環境変数経由で渡します。
.env の設定
.env に nuxt.config.js で使われる環境変数を定義します。
COGNITO_USER_POOL_ID=<ユーザープールID>
COGNITO_CLIENT_ID=<クライアントID>
COGNITO_REGION=<リージョン>ログインの実装
ログインを実装します。
pages/login.vue
<script>
export default {
  data() {
    return {
      username: '',
      password: '',
    }
  },
  methods: {
    async signIn() {
      try {
        const { username, password } = this
        await this.$auth.loginWith('cognito', {
          data: {
            username,
            password,
          }
        })
      } catch (error) {
        console.error(error)
      }
    }
  }
}
</script>基本的には this.$auth.loginWith() を実行するだけです。
第1引数のストラテジ名は nuxt.config.js のスキーマで指定した名称を、第2引数 (options) の data にユーザー名とパスワードを渡します。
loginWith は Promise を返すので、 async/await で待機させ、エラー処理には try-catch を使います。
動作確認
ここまでできたら動作するはずなので yarn dev して起動します。
.nuxt ディレクトリが生成され、 i Listening on: http://localhost:3000/ と表示されたら、 http://localhost:3000/ にアクセスします。
自動的に /login にリダイレクトされるはずなので、ユーザー名とパスワードを入力して Sign in ボタンを押します。
成功するとホーム (/) にジャンプするはずです。図のように $auth.user の中身が表示されていれば OK です。
Vuex によって Local Storage にトークンなどが保存されます。
ここで Logout を押すと Vuex のログイン情報がクリアされ、ログイン画面にリダイレクトされます。
まとめ
2021年5月時点で最新の Nuxt.js と nuxt/auth を使って Cognito のユーザープールのアカウントでログインを実装する方法を紹介しました。
事前準備も多く、まだまだ「簡単に」とはいかない印象ですが、ひとまず認証を Cognito に委任できるだけで認証用のユーザーストアをアプリ側に保持する必要がなくなるため、サーバーレスの第一歩としてはとても有用だと思います。



 
   
   
   
   
   
   
   
   
   
   
  
