FutureStandard MAKERS

東京にある動画解析プラットフォーム「SCORER」の開発をしているスタートアップのブログです

Express + Passport + Cognito でサーバーサイドのユーザー認証を手軽に実装

データの分析を生業にしているはずが、なぜか Node.js でサーバー&フロントエンドの開発をしている金田です。この度、Amazon Web Service (AWS) の提供する Cognito User Pools というユーザー認証機能を Node.js から簡単に利用できるモジュールを作成しましたので紹介できればと思います。

www.npmjs.com

概要

AWS には、Cognito User Pools というユーザー認証機能を簡単に実装できるマネージドサービスがあります。しかしながら、AWSから提供されているSDKは、基本的にクライアントサイドでの利用を想定しており、iOSAndroidJavaScript(ブラウザ版) しか提供されていません。今回、弊社で開発をしている SCORER という動画解析サービスの開発にあたり、Node.js を使ったサーバーサイドでの認証に Cognito User Pools を利用したかったため、Passport という認証用ミドルウェアを作成することで簡単に実装が行えるようにしました。

SCORER とは?

動画データの保存、解析、分析といった映像解析ソリューションを開発する際に必要になる機能を、ハードウェアからソフトウェアまでワンストップで提供するBaas (Backend as a Service) です。映像解析を活用したサービスを提供したい開発者が、簡単に映像解析技術を利用したサービスを開発できるプラットフォームを目指しています。現在は、標準機能として、下記の画像にあるように顔検知、動体検知、AR/QRコードの読み取りといった機能を利用することができます。

f:id:FutureStandard:20161019165038p:plain:w280 f:id:FutureStandard:20161019164759p:plain:w350

Cognito とは

Cognito はAWSの提供するユーザー認証基盤です。実は、Cognito には、Cognito Identity と Cognito User Pools の二つのサービスがあり、前者はFacebookGoogleTwitter といった外部もしくは自前のIDプロバイダを必要とするのに対して、後者はユーザー登録、多要素認証、パスワード変更といったユーザー認証に関わる一切のサービスを提供してくれるため、簡単に独自ユーザー認証基盤を作成することができます。当初、Cognito を使い始めたときに、この辺りの違いが理解できず苦労しました。

ただし、Cognito Identity と Cognito User Pools は連携をさせることもでき、この場合は、Cognito User Pools が外部IDプロバイダと同じ役割をすることになります。詳しくは、下記のリンクの Use case 17. あたりが詳しいです。
GitHub - aws/amazon-cognito-identity-js

参考:
Amazon Cognito User Poolsを使って、webサイトにユーザ認証基盤を作る - Qiita
[新機能] Amazon Cognito に待望のユーザー認証基盤「User Pools」が追加されました! | Developers.IO
Amazon Cognito User Poolsの情報をサーバサイドで取得する - Qiita

Passport とは

Express という Node.js のフレームワークとともに利用される認証用のミドルウェアです。FacebookGoogle等を使ったOAuth認証、ベーシック認証といった様々な認証方法をを統一的なAPIで利用できるため Express をで認証機能を利用する際は、事実上の標準となっています。今回は、 Cognito User Pools の認証ができる Passport のモジュールを作成して公開しました。

使い方

Express と Passport の使い方に関しては下記の記事が大変参考になりました。本稿の説明も、基本的にはこちらに書いてある Passport の実装方法に拠っています。 express実践入門 · GitHub

また、Cognito User Pools の設定はすでになされているものとします。詳しい設定方法に関しては下記の記事が詳しいのでご参照ください。

[新機能] Amazon Cognito に待望のユーザー認証基盤「User Pools」が追加されました! | Developers.IO
Amazon Cognito User Poolsを使って、webサイトにユーザ認証基盤を作る - Qiita

なお一点だけ注意点があり、JavaScript から利用する場合は、User Pools の App の設定画面で「Generate client secret」のチェックを必ず外してから作成を行ってください。

f:id:FutureStandard:20161019210305p:plain

インストール

npm のパッケージとして公開しているため、下記のコマンドを入力するだけでインストール可能です。必要に応じて --save などのオプションをつけてください。

$ npm install passport-cognito

ブラウザ側の実装

ブラウザ側からは、フォームを入力してボタンを押した際に、POSTで username と password を送るように設定します。例えば、jQueryで値を送る場合は下記のようになります。

$.ajax({
  type: 'POST',
  url: '/auth/cognito',
  data: { username: username, password: password }
})

サーバーサイドの実装

Passport と middlware の設定

まず、Passport モジュールの読み込みとセッション用の middleware を設定します。ここはほぼコピペでOKです。

app.js

var passport = require('passport');

// passportモジュールをLoad
require('./passport')(app);

// session用のmiddlewaresを有効化
app.use(passport.initialize());
app.use(passport.session());

Strategy の設定

次に、Cognito 認証の Passport モジュールを読み込み、コンストラクタから必要なオプションを与えてインスタンスを生成します。コンストラクタの2つ目の引数が、コールバック関数になっており、認証が成功した場合はここでトークンやユーザー情報が取得できますので、必要に応じて処理を書いてください。なお、この user オブジェクトにトークン情報などを格納しておくと、ルーティングの際に、req.user を参照することで情報を引き回すことができるようになります。

config/passport/cognito.js

var CognitoStrategy = require('passport-cognito')
 
module.exports = new CognitoStrategy({
    userPoolId: 'ap-northeast-1_eSjqLfqKc',
    clientId: 'vtvg02tr21zmxvspyvawtv09b',
    region: 'ap-northeast-1'
  },
  function(accessToken, idToken, refreshToken, user, cb) {
    process.nextTick(function() {
      ...
      cb(null, user);
    });
  }
);

Serialize/Deserialize の設定

セッションへの情報の格納と復元の設定を行います。なお、ここで上記のコールバック関数の引数で渡した user を session 情報に格納しているため、req.user で値を引き回すことができるようになります。ここもほぼコピペでOKです。

config/passport.js

module.exports = function(){
  var passport = require('passport');

  // sessionにユーザー(のキー)情報を格納する処理
  passport.serializeUser(function(user, done) {
    done(null, user);
  });

  // sessionからユーザー情報を復元する処理
  passport.deserializeUser(function(obj, done) {
    done(null, obj);
  });

  // 利用するstrategyを設定
  passport.use(require('./passport/cognito'));
}

Routing の設定

下記のエンドポイントにPOSTでリクエストがあった際に、passport.authenticate() が呼ばれるようにします。なお、この際、req.body.username と req.body.password でブラウザから送られてきた値が取得できている必要があります。

app.post('/auth/cognito',
  passport.authenticate('cognito', {
    successRedirect: '/',
    failureRedirect: '/login'
}));

最後に

上記の設定ができると、Cognito User Pools の認証は Passport モジュールが裏でいい感じに行ってくれ、AWSの他のサービスのアクセス等に必要なトークンの情報や User Pools に登録してあるユーザー情報が取得できるようになります。Express と Passport に多少は習熟する必要はありますが、上記のモジュールを使うと簡単にCognito User Pools の認証処理が実装できることをお分かりいただけたのではと思います。

なお最後にはなりますが、上記で紹介した SCORER の開発キットは Yahoo! ショッピングで絶賛販売しております!興味を持って頂けたらぜひ購入をお願いします。Raspberry Pi3、USBカメラ、SDカードが付いており、ほぼ原価で販売してますので大変お得になっております(笑)

Future Standard - Yahoo!ショッピング