Amazon Cognitoを使ってNode.jsで認証

  • 2019.11.16
  • AWS
Amazon Cognitoを使ってNode.jsで認証

ユーザ認証を実装する際に、これからCognitoを使用する機会が多くなりそうなので試しに使ってみました。
今回は、CognitoのUser Poolsを使って認証の一連の流れを実装してみました(サインアップ→アクティベート→サインイン)。今回は実装しませんが、AWSリソースへのアクセス許可(認可)に関してはFederated Identitiesを使うみたいです。

AWSマネジメントコンソールでの設定

ユーザプールを作成

  1. マネジメントコンソールからCognitoを開く
  2. 「ユーザプールを作成する」をクリック
  3. プール名を指定し「デフォルトを確認する」をクリックし、作成

アプリクライアントの作成

  1. サイドメニューから「アプクライアント」を選択
  2. アプリクライアント名を指定し、「クライアントシークレット作成」のチェックを外して作成

Node.jsのコーディング

まずは、Expressのインストール。

npm i express

続いて、以下をインストール。

npm i amazon-cognito-identity-js
npm i node-fetch

AuthController.jsとAuthService.jsを作成して、準備完了。

サインアップ

AuthService.js
※process.env.USER_POOL_ID、process.env.CLIENT_IDの箇所は、マネジメントコンソールで取得できる「プールID」、「アプリクライアントID」をそれぞれ入力します。

global.fetch = require('node-fetch')
const AmazonCognitoIdentity = require('amazon-cognito-identity-js')

const poolData = {
    UserPoolId: process.env.USER_POOL_ID,
    ClientId: process.env.CLIENT_ID,
}
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);

exports.Register = (body, callback) => {
    const name = body.name;
    const email = body.email;
    const password = body.password;
    const attributeList = [];

    attributeList.push(new AmazonCognitoIdentity.CognitoUserAttribute({
        Name: 'email',
        Value: email
    }))

    userPool.signUp(name, password, attributeList, null, (err, result) => {
        if (err) callback(err);
        callback(null, result.user)
    })
}

AuthController.js

const authService = require('./AuthService');

exports.register = (req, res) => {
    authService.Register(req.body, (err, result) => {
        if (err) res.send(err);
        res.send(result)
    })
}

上記で、サインアップのコーディングは完了。ルーティングなど指定して一旦挙動確認してみます。

routes.js

const express = require('express');
const router = express.Router();
const authController = require('./AuthController');
router.post('/auth/register', authController.register);
module.exports = router;

app.js

const express = require('express')
const app = express();
const routes = require('./routes');

app.use(express.json())
app.use(express.urlencoded({ extended: false }));
app.use('/', routes)
module.exports = app;

server.js

const app = require('./app')
var server = app.listen(3000, function () {
    console.log('Server is runnning on port 3000')
})

ここまで記述したら、node server.js でサーバ起動するはず。

以下の形でAPIを叩くと、入力したメールアドレスにアクティベート用のコードが届く。

アクティベート

AuthService.js

exports.Activate = (body, callback) => {
    const name = body.name;
    const activateKey = body.key;
    const userData = {
        Username: name,
        Pool: userPool
    }

    const cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
    cognitoUser.confirmRegistration(activateKey, true, (err, result) => {
        if (err) callback(err);
        callback(null, result)
    })
}

AuthController.js

exports.activate = (req, res) => {
    authService.Activate(req.body, (err, result) => {
        if (err) res.send(err);
        res.send(result)
    })
}

サインイン

AuthService.js

exports.Login = (body, callback) => {
    const name = body.name;
    const password = body.password;
    const authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({
        Username: name,
        Password: password
    })
    const userData = {
        Username: name,
        Pool: userPool
    }

    const cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);

    cognitoUser.authenticateUser(authenticationDetails, {
        onSuccess: result => {
            const accessToken = result.getAccessToken().getJwtToken()
            callback(null, accessToken)
        },
        onFailure: err => {
            callback(err)
        },
        mfaRequired: function (codeDeliveryDetails) {
            var verificationCode = prompt('Please input verification code', '');
            cognitoUser.sendMFACode(verificationCode, this);
        }
    })
}

AuthController.js

exports.login = (req, res) => {
    authService.Login(req.body, (err, result) => {
        if (err) res.send(err);
        res.send(result)
    })
}

以上で終了。routes.jsは、最終的に下記のようになります。

routes.js

var express = require('express');
var router = express.Router();
var authController = require('./Controllers/AuthController');
router.post('/auth/register', authController.register);
router.post('/auth/activate', authController.activate);
router.post('/auth/login', authController.login);
router.post('/auth/activate', authController.activate);
module.exports = router;

APIを叩く際のパラメータなどは、コードの中から読み取ってください笑。
ログインAPIを叩くと、JWTトークンが取れます。
今回は一旦ここまで。