はじめに
自作のNode.jsアプリをOpenID Connectプロバイダーと連携させて認証機能を実装するためのNode.jsアプリの作り方について説明します。全体の流れは以下の通りです。
- 前提の確認
- OpenID Connectプロバイダーへのアプリの登録
- Node.jsアプリのコーディング
前提
この記事での環境の前提は以下の通りです。ただし、なるべく環境依存せず汎用的になるよう記事を書いています。コードの要所部分のみを説明しています。
- Node.js
- この記事では、npmモジュールのpassport-ci-oidcを利用します。
- npmモジュールのexpressやpassportも利用しますが、前提知識の説明を省略いたします。
- OpenID Connectプロバイダー
- OpenID Connectとは何かなど前提知識の説明を省略いたします。
- どのプロバイダーでもアプリの作り方の大まかな流れは変わりませんが、プロバイダーが利用方法を細かくガイドしている場合があります。特にどのnpmモジュールを利用するかは、プロバイダーの仕様により決まることがあります。
- この記事では、IBM Security Verifyという製品で作られたプロバイダーを利用しています。今回利用するプロバイダー自体の構築や運用には携わっておらず、あくまで一利用者の立場です。
OpenID Connectプロバイダーへのアプリの登録
プロバイダーが提供するポータルへアクセスし識別可能にするためのアプリ名などを登録すると、アプリが連携するのに必要な情報が払い出されます。主な項目は以下の通りです。
- 文字列として払い出される項目:
- Client ID
- Client Secret
- URL文字列として払い出される項目:
- Authorization Endpoint
- Token EndPoint
- UserInfo EndPoint
- Introspection EndPoint
- Discovery Endpoint
- Issuer
Node.jsアプリのコーディング
アプリのプロジェクトディレクトリで以下のコマンドを実行し、npmモジュール passport-ci-oidc をインストールします。コマンド実行後、packages.jsonのdependenciesにpassport-ci-oidcが書き込まれていることも確認します。
$ npm install passport-ci-oidc
次にアプリに認証機能を組み込みます。
OpenID Connectプロバイダーから払い出された情報のうち、以下のものを使います。実行前に環境変数に代入します。
- Client ID
- Client Secret
- Discovery Endpoint
加えて、Callback URL (認証後にリダイレクトされるURL)もパラメータに含めます。以下では www.example.com
というホスト名になっていますが、アプリを実際に稼働させるときに使うホスト名に置き換えます。
const client_id = process.env.CLIENT_ID;
const client_secret = process.env.CLIENT_SECRET;
const discovery_url = process.env.DISCOVERY_ENDPOINT;
const callback_url = 'https://www.exmaple.com/api/auth/callback';
const OpenIDConnectStrategy = require('passport-ci-oidc').IDaaSOIDCStrategy;
const Strategy = new OpenIDConnectStrategy({
discoveryURL: discovery_url,
clientID : client_id,
scope: 'email',
response_type: 'code',
clientSecret : client_secret,
callbackURL : callback_url,
skipUserProfile: true
},
(iss, sub, profile, accessToken, refreshToken, params, done) => {
process.nextTick(() => {
profile.accessToken = accessToken;
profile.refreshToken = refreshToken;
done(null, profile);
});
}
);
passport.use(Strategy);
app.get('/api/auth/callback', (req, res, next) => {
const redirect_url = req.session.originalUrl;
passport.authenticate('openidconnect', {
successRedirect: redirect_url,
failureRedirect: '/api/auth/failure'
})(req, res, next);
});
app.get('/api/auth/login', (req, res) => {
passport.authenticate('openidconnect', {})(req, res);
});
app.get('/api/auth/failure', (req, res) => {
res.send("ログインに失敗しました");
});
const ensureAuthenticated = (req, res, next) => {
if (!req.isAuthenticated()) {
res.redirect('/api/auth/login');
} else {
next();
};
};
app.get('/top', ensureAuthenticated, (req, res) => res.send('Hello World! User '+ req.user['id']);
上記のコードのポイントは、Strategyを設定するときに与えるパラメータはプロバイダーにより異なるということです。認証が通った場合や通らなかった場合の処理や、URLにアクセスされたときの認証チェックの書き方は、passportの他のStrategyを使う時と基本的に変わりません。
参考情報
passport-ci-oidc
https://www.npmjs.com/package/passport-ci-oidc