はじめに
この記事はAuth0のハンズオンラボでAuth0 Identity Labsを元に作成しています。Node.js + Express.jsで作成されたSample ApplicationでExpressミドルウェアを利用して認証をリダイレクトし、リダイレクト先の認可サーバとしてAuth0を使います。Auth0の無料アカウントの取得とテナントの作成が完了していることが前提となっています。Auth0の無料アカウント取得がまだの方はこちらの記事を参照の上ご準備をお願いします。
検証環境
-
OS :
macOS Catalina 10.15.2
-
node :
10.15.3
-
npm :
6.13.2
-
Git :
2.23.0
ラボ
Part1
Part1ではSample ApplicationとAuth0を連携してAuth0に認証プロセスをオフロードします。Git Repoをローカルにクローンします。
$ git clone https://github.com/auth0/identity-102-exercises.git
$ cd identity-102-exercises/lab-01/begin
Node.jsの環境変数定義ファイルを作成します。
$ pwd
~/identity-102-exercises/lab-01/begin
$ cp cp .env-sample .env
cookie-sessionとexpress-openid-connectパッケージをインストールします。
- cookie-session : ユーザのログインセッションを保管する
- express-openid-connect : Opne ID Connect, JSON Web Tokenを実装するExpressミドルウェア
$ pwd
~/identity-102-exercises/lab-01/begin
$ npm install cookie-session express-openid-connect
server.jsを編集してcookie-sessionとexpress-openid-connectを読み込みます。以下、修正後のコードです。
require('dotenv').config();
const express = require('express');
const http = require('http');
const morgan = require('morgan');
// 下2行を追加
const session = require('cookie-session');
const { auth } = require('express-openid-connect');
const appUrl = process.env.BASE_URL || `http://localhost:${process.env.PORT}`;
const app = express();
app.set('view engine', 'ejs');
app.use(morgan('combined'));
app.use(express.urlencoded({ extended: false }));
app.get('/', (req, res) => {
res.render('home', { user: req.openid && req.openid.user });
});
app.get('/expenses', (req, res) => {
res.render('expenses', {
expenses: [
{
date: new Date(),
description: 'Coffee for a Coding Dojo session.',
value: 42,
}
]
});
});
http.createServer(app).listen(process.env.PORT, () => {
console.log(`listening on ${appUrl}`);
});
server.jsを修正してExpressミドルウェアで認証を取り扱うようにします。以下、修正後のコードです。
Expressミドルウェアは/login(OIDCのリクエストを認可サーバに投げる), /callback(認可サーバからのレスポンスを受け取る), /logout(Applicationのセッションを終了する)の3つのルートを自動的に定義します。
require('dotenv').config();
const express = require('express');
const http = require('http');
const morgan = require('morgan');
const session = require('cookie-session');
const { auth } = require('express-openid-connect');
const appUrl = process.env.BASE_URL || `http://localhost:${process.env.PORT}`;
const app = express();
app.set('view engine', 'ejs');
app.use(morgan('combined'));
app.use(express.urlencoded({ extended: false }));
// 下7行を追加
app.use(session({
name: 'identity102-l01-e01',
secret: process.env.COOKIE_SECRET
}));
app.use(auth({
auth0Logout: true
}));
app.get('/', (req, res) => {
res.render('home', { user: req.openid && req.openid.user });
});
app.get('/expenses', (req, res) => {
res.render('expenses', {
expenses: [
{
date: new Date(),
description: 'Coffee for a Coding Dojo session.',
value: 42,
}
]
});
});
http.createServer(app).listen(process.env.PORT, () => {
console.log(`listening on ${appUrl}`);
});
Expressミドルウェアは認可サーバ(Auth0)のURLとApplicationのIDが必要になるため、Auth0のDashboardからApplicationを登録します。左ペインの"Applications"をクリックして右上の"CREATE APPLICATION"を押します。
"Name"に任意の名前を入力、"Choose an application type"で"Regular Web Applications"を選択して”CREATE”を押します。
"Allowed Callback URLs"に"http://localhost:3000/callback
", "Allowed Logout URLs"に"http://localhost:3000
"を入力して画面下の"SAVE CHANGES"を押します。
.envを編集してExpressミドルウェアに渡す環境変数を設定します。以下、修正後のファイルです。
"COOKIE_SECRET"は任意のランダムで生成した文字列を指定します。ターミナルからopenssl rand -base64 32を実行するとランダム文字列を出力できます。
"ISSUER_BASE_URL"にはAuth0のテナントドメイン名、CLIENT_IDにはAuth0に登録したApplicationのClient_IDを設定します。Auth0 Dashboardの"Applications"->"作成したApplication"->"Settings"から確認できます。
ISSUER_BASE_URL=https://xxxx.auth0.com
CLIENT_ID=xxxx
COOKIE_SECRET=xxxx
PORT=3000
必要なパッケージをインストールしてApplicationを起動します。
$ pwd
~/identity-102-exercises/lab-01/begin
$ npm install
$ npm start
Chromeでhttp://localhost:3000
にアクセスします。Auth0のログインウィジェットが表示されてサインアップできれば成功です。
Part2
Part2では認証プロセスで発生しているトラフィックをトレースして詳細を確認してみます。サインアップしたアカウントでログアウトしてChromeのデベロッパーツールを開き"Network"タブをクリックします。"authorize?client_idxxxx"を選択するとAuth0にGETリクエストが送信されていることが確認できます。
ExpressミドルウェアがAuth0の/authorize End PointにOpen ID Connectの認証リクエストを送信しています。
https://kiriko.auth0.com/authorize
?client_id=rJbxtul1gfExXU9K5610LgBR4SpF2d4R
&scope=openid%20profile%20email
&response_type=id_token
&nonce=71890cc63567e17b
&state=85d5152581b310e3389b
&redirect_uri=http://localhost:3000/callback
&response_mode=form_post
ログインして"callback"を選択します。
Auth0がApplicationにID Token付きのPOSTレスポンスを返しています。
ID TokenをコピーしてChromeでhttps://jwt.io
にアクセスしてEncoded欄にコピーしたID Tokenをペーストします。
id_token: eyJ0eXAiOixxxx
ID Tokenの詳細を見てみます。
{
"nickname": "mokomokogaugau",
"name": "mokomokogaugau@gmail.com",
"picture": "https://s.gravatar.com/avatar/72fe59dcd73bba7543fc36d2c3c8131d?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fmo.png",
"updated_at": "2019-12-20T02:20:42.537Z",
"email": "mokomokogaugau@gmail.com",
"email_verified": false,
"iss": "https://kiriko.auth0.com/", -> 発行元. Auth0です。
"sub": "auth0|5dfc2f44d7ca3516bee542d4", -> 発行された人。mokomokogaugau@gmail.comさんです。
"aud": "rJbxtul1gfExXU9K5610LgBR4SpF2d4R", -> 発行されたApplication. Auth0に登録したApplicationのClient IDです。
"iat": 1576808442,
"exp": 1576844442,
"nonce": "b3dbc93dd431a750"
}
Auth0 Dashboardの左ペイン"Users & Roles"->"Users"でmokomokogaugau@gmail.comさんのIDを確認してみます。ID Tokenの"sub"と一致していますね。
おわりに
最後までお付き合い頂きありがとうございます。ID Tokenは認可サーバから一度発行されたら有効期限内は再利用できるため、Applicationは何度も認可サーバに問い合わせする必要はなくなります。また、複数のApplicationで認証情報を共有できるためSSOも簡単に実装できます。Auth0やExpressミドルウェアのようなOpen ID Connectに準拠したテクノロジを利用することで少ない工数でセキュアでスケーラブルなWeb Applicationを構築できますね。