【OPTiM Cloud IoT OS 認証・認可編】OPTiM Cloud IoT OSのアカウントを使った認証・認可の実装【Node.js】

こんにちは。プラットフォーム技術戦略室の青木です。

前回投稿した記事では「OAuth2.0を利用したAPIの利用方法」でしたが、今回はOpenID Connectでの認証・認可方法を紹介します。

tech-blog.optim.co.jp

自社サービスの「OPTiM Cloud IoT OS(以下CIOSと呼ぶ)」を利用したアプリケーションを開発する際、認証・認可を伴ったユーザ認証を実装する必要が出てくることがあると思います。そんな時「CIOS」には OpenID Connect + OAuth 2.0 にて認証を任せることが出来ます。そうすることでアプリケーション開発時に自前でユーザ認証機能を実装せず、アプリケーションのコア部分の実装に集中し時短かつ安全な実装を行うことが出来ます。

今回はそういった認証連携をNode.jsでどのように実装していくかを紹介いたします。

www.optim.cloud

せっかっちな人向け

github.com

サンプルコードを用意しております。加えた行数も指定しておりますので、こちらを参考に構築していただければ OpenID Connect + OAuth 2.0 による CIOS認証・認可が実装できます。

この記事で出来ること

  • CIOSのOAuth Client(アプリケーション)の作成
  • CIOSのアカウントと認証連携を行うことが出来る
    • 「CIOSでログイン」というボタンが実装できる
  • Node.jsOpenID Connect を利用した認証連携を行うことが出来る

この記事では言及されていないこと

  • OpenID Connect,OAuth 2.0の仕様
  • 認証・認可フローの解説

    「OPTiM Cloud IoT OS」のOpenID Connect + OAuth 2.0

自社サービスである「CIOS」では、OAuth 2.0の拡張であるOpenID Connectが備わっています。

以下は、「OPTiM Cloud IoT OS」のドキュメントに記載されている内容です。

本サービスのAPIは、OAuth 2.0*1によって保護されています。 そのため、本サービスのAPIを利用してリソースへアクセスする際は、OAuth 2.0の認可の仕組みを利用する必要があります。

OAuth 2.0は、アプリケーションによるリソースアクセスの権限を認可するためのスタンダードなフレームワークです。 本サービスでは、OAuth 2.0のフローとして、以下のフローをサポートしています。

  • Authorization Code Grant
  • Client Credentials Grant

また、本サービスを使ったログイン(フェデレーション、シングルサインオン)を行うアプリケーションを作成する場合は、OpenID Connect*2を利用します。 OpenID Connectは、OAuth 2.0をベースとしたID連携(フェデレーション)の標準プロトコルです。 そのため、OAuth 2.0によるAPI認可と合わせてユーザー認証を行うことができるようなっています。

実装手順

前半は、前回の記事 【OPTiM Cloud IoT OSのアカウントを使ったOAuth連携の実装】で行った作業と同じです。

1. OAuth Clientを作成する

CIOSに作成するアプリケーションの登録をすると、OAuth Clientが作成されて認証・認可を行う準備が可能になります。 画像のように、アプリケーションの登録を行い、下準備を行います。

OPTiM Cloud IoT OS に3ヶ月無償トライアルにて*3登録を行うと、アプリケーション登録を行える Developer Center にアクセスすることが出来ます。

https://cdn-ak.f.st-hatena.com/images/fotolife/o/optim-tech/20210301/20210301095027.png

項目 設定情報 解説
表示名 tech_blog_sample_oidc_js 認可画面に表示されるアプリケーション名
状態 有効 このアプリケーションが有効かどうか
種別 Webアプリケーション 他に、ネイティブアプリやデバイスなどが存在する
リダイレクトURIs http://localhost:3000/oauth2/callback 認可レスポンスを送信するURI。セキュリティを強化するために記載し、Webアプリケーションに設定されたURIと同じでなければならない
APIスコープ openid, user.profile このアプリケーションがユーザのデータにアクセスする権限を選択。認可画面にスコープに応じた同意画面が表示される
クライアントID 非公開 認証・認可フローに利用するID
クライアントシークレット 非公開 認証・認可フローに利用するシークレット
リソースオーナー アカウント名 このOAuthClientの持ち主

3. OpenID Connect 部分を実装する

github.com

基本的には、リポジトリに記載されているサンプルコードに則って実装すればスムーズに出来ます。 ここでは実際にサンプルコードを実装した場合どのような挙動になるのかも踏まえて紹介いたします。

3-1. Expressの基盤を作る

expressjs.com

Express Generatorでアプリケーションを生成します。

express myapp
cd myapp
yarn
yarn start

https://cdn-ak.f.st-hatena.com/images/fotolife/o/optim-tech/20210127/20210127114451.png

3-2. OPTiM Cloud IoT OS OpenID Connectに関する部分の実装

OpenID Connectの実装部分は至ってシンプルで、必要なパッケージは1つのみとなっております。また、フレームワークとして提供されているため、カスタマイズしたパッケージを作る必要が無いところも魅力となっています。

更に、OAuth 2.0 の拡張ですので認可後のAPI利用も容易となっております。

必要なパッケージをインストール

yarn add express-openid-connect node-fetch dotenv

OpenID Connect利用の為の設定

app.jsに記述します

冒頭に利用するパッケージを読み込みます。

const { auth } = require('express-openid-connect')
const fetch = require('node-fetch')
require('dotenv').config()

OpenID Connectの実装部分に、CIOSとの認証情報を記述します。

const issuer = 'https://auth.optim.cloud' // CIOSのIssuerURL
const baseURL = 'http://localhost:3000'
const clientId = typeof process.env.CLIENT_ID === "undefined" ? '' : process.env.CLIENT_ID
const clientSecret = typeof process.env.CLIENT_SECRET === "undefined" ? '' : process.env.CLIENT_SECRET
app.use(auth({
  issuerBaseURL: issuer,
  baseURL: baseURL,
  clientID: clientId,
  secret: clientSecret,
  idpLogout: true,
  
  // authRequired:true とすることで、下記記述の`app.get('/')`等に
  authRequired: true,               
  routes:{
    callback: "/oauth2/callback"    // OAuth Clientを作成した際に入力したRedirectURIのPath部分
  },
  authorizationParams: {            // OAuth 2.0 による認可でアクセストークンを取得する場合に記述
    response_type: 'code',
    scope: 'openid user.profile', 
  }
}))

アクセストークンを利用し、 CIOSのユーザ情報を取得する

app.jsに記述します

今回はViewを返さず、JSON文字列をそのまま返却するソースとなっています。

また、認証連携はDB等と紐付けを行うことで実現でき、以下で req.oidc.sub と DBのUser情報を紐付けることができれば認証連携が行えます。

/**
 * Example API (アカウント情報取得)
 */
const accountAPI = 'https://accounts.optimcloudapis.com'
app.get('/', async (req, res) => {

  // DBにUser情報を持つ場合は
  // req.oidc.sub と User情報の紐付けを行うことが出来る
  
  // 認可レスポンスに含まれたAccessTokenを利用する
  let { token_type, access_token } = req.oidc.accessToken;

  // 個人情報API (`/v2/me`) にアクセスする
  const me = await fetch(accountAPI + '/v2/me', {
    headers: {
      Authorization: `${token_type} ${access_token}`,
    },
  });

  // 本来はViewを返却し、ブラウザからJson文字列を取得しますが
  // 今回はJson文字列をそのままブラウザへ返却する
  res.json(await me.json());
});

3-3. 動作確認

http://localhost:3000 へアクセスすると、OPTiM Cloud IoT OS のログイン画面 -> 認可画面の順に表示されます。

https://cdn-ak.f.st-hatena.com/images/fotolife/o/optim-tech/20210208/20210208084333.png

https://cdn-ak.f.st-hatena.com/images/fotolife/o/optim-tech/20210225/20210225110434.png

認可を行うと、アプリケーションへ戻りAccountAPIの /me を叩いた結果が得られます。

https://cdn-ak.f.st-hatena.com/images/fotolife/o/optim-tech/20210208/20210208084330.png

ex. CIOSでログインボタンを実装するには?

今回のサンプルコードでは、 http://localhost:3000/login でOpenID Connectのフローが開始するような仕組みになっています。

ですので、以下のようなHTMLを用意するだけでログインボタンが簡単に実装出来ます。

<a href="/login">CIOSでログイン!</a>

さいごに

私はOpenID Connectを普段から利用する事はなく、難しいというイメージをとても抱いていたのですが、実際に実装してみるととてもコード記述量が少なく実装でき、しかも安全な認証・認可が行えるということにとても驚きました。

これらの認証を利用して軽くアプリケーションを作れるような記事も追々執筆しようかなと思っています。

ここまでご覧いただきありがとうございました。


オプティムではOPTiM Cloud IoT OSの開発、及び利用するアプリケーション開発を行うエンジニアを募集しています。

www.optim.co.jp

*1:https://tools.ietf.org/html/rfc6749

*2:https://openid.net/specs/openid-connect-core-1_0.html

*3:2021/01/27現在、3ヶ月間の無償トライアルが利用可能