OAuth2.0 Node.js の構築
    • PDF

    OAuth2.0 Node.js の構築

    • PDF

    記事の要約

    Classic/VPC環境で利用できます。

    Node.jsベースの OAuth2.0 Serverの基本的な構築方法について説明します。ガイドを参照し、OAuth2.0サーバが実装されていないサービスで既存の会員/認証システムと統合できます。

    プロジェクト設定

    プロジェクトの設定方法について説明します。

    使用バージョン

    使用バージョン情報は次の通りです。

    • Node.js Latest LTS(2023年10月10日現在)
      • node: 18.18.0
      • npm: 9.8.1

    使用ライブラリ

    使用ライブラリ情報は次の通りです。

    • express
    • node-oauth2-server
      • https://github.com/oauthjs/node-oauth2-server
        npm install --save node-oauth2-server
        
    参考

    詳細は https://oauth2-server.readthedocs.io/en/latestで確認でき、当該ライブラリを使った公式例は https://github.com/14gasher/oauth-exampleで確認できます。

    構築ガイドの範囲

    構築ガイドでは簡単なログインページを通して例を説明します。実際のサービス実装時、既存のログインページを次の OAuth2.0 Login APIと統合して開発します。

    参考

    暗号化アルゴリズム、トークン作成アルゴリズムなどは各サービスポリシーに従って開発し、このガイドの範囲を超えるため当該領域はコメントでご案内します。

    node-oauth2-server

    node-oauth2-serverは事前に定義されたモデル(*OAuth2.0過程で必要な機能の明細)を実装し、認証(authenticate)、認可(authorize)、トークン(token)の3つの機能を呼び出すことで、実装された Modelのロジックに合わせて機能を提供します。
    OAuth2.0に必要な機能が Modelを通して抽象化されており、その内容を実装して注入することで簡単に認証/認可/トークン発行の機能を使用できます。

    提供機能

    提供する機能は、次の通りです。

    機能説明
    認証(authenticate)発行されたトークンに基づき、API入力で認証処理を提供
    認可(authorize)code、passwordなどの方法で認可機能を提供
    トークン(token)認可されたユーザーに対して Tokenの発行および保存機能を提供

    ライブラリ Modelリスト

    B2B PRISM Live Studio OAuth2.0の連携過程では Authorization Code/Refresh Token Grantのみを必要としており、Scopeの機能は提供していません。

    PRISM OAuth2.0に必要な Modelリスト

    ここで扱う Modelリストは、次の通りです。

    参考

    全 Modelリストは以下をご参照ください。

    機能説明
    generateAccessTokenAccess Tokenを作成するロジックを担当
    generateRefreshTokenRefresh Tokenを作成するロジックを担当
    generateAuthorizationCode認可過程で使用される Authorization Codeを作成するロジックを担当
    getAccessTokenToken発行段階で保存されている Access Tokenを取得して検証するために使用
    getRefreshTokenToken発行段階で保存されている Refresh Tokenを取得して検証するために使用
    getAuthorizationCodeAuthorization段階で保存されている Authorization Codeを取得して検証するために使用
    getClientClient情報(Client ID、Client Secret、Redirect URI)を取得するために使用
    saveTokenToken発行段階で作成されたトークンを保存
    saveAuthorizationCodeAuthorization段階で作成された Authorization Codeを保存

    それぞれのロールと機能については、実際の実装例をご参照ください。各モデルの最新の詳細情報などはこちらでご確認いただけます。
    Modelの実装において Promiseを使った方法や async-await、callbackなどの方法がありますが、例では Promiseを使った方法で実装します。以下のサンプルコードをご確認ください。

    const model = {
      // We support returning promises.
      getAccessToken: function() {
        return new Promise('works!');
      },
     
      // Or, calling a Node-style callback.
      getAuthorizationCode: function(done) {
        done(null, 'works!');
      },
     
      // Or, using generators.
      getClient: function*() {
        yield somethingAsync();
        return 'works!';
      },
     
      // Or, async/wait (using Babel).
      getUser: async function() {
        await somethingAsync();
        return 'works!';
      }
    };
     
    const OAuth2Server = require('oauth2-server');
    let oauth = new OAuth2Server({model: model});
    

    1. OAuth2.0 Login API(Authorization Code発行 API)

    Authorization Code発行機能のために実装すべき Modelは、次の通りです。

    generateAuthorizationCode

    この機能はオプション(Optional)です。実装しない場合、40文字の codeが自動的に作成されます。独自の発行アルゴリズムが必要な場合は、直接実装します。

    Arguments

    因子の説明は次の通りです。

    フィールドタイプ説明
    clientObject
    • Access Token/Refresh Tokenを作成する Client情報が入った Object
    • getClient() Modelが呼び出され、その Modelで照会された情報を自動的に転送
    userObjectAccess Token/Refresh Tokenを作成する User情報が含まれている
    [callback]FunctionPromiseで返さない場合に使える callback関数

    Return Value

    String(Authorization Code値)タイプで返されます。

    Example Code

    generateAuthorizationCodeのサンプルコードは、次の通りです。

    {
        generateAuthorizationCode: function(client, user) {
            // AccessToken、RefreshTokenを作成する独自のロジックを作成
            return new Promise(accessToken);
        }
    }
    

    getClient

    Client ID、Client Secretの情報で、Redirect URI、Token Lifetime情報を取得する機能です。実装によっては、DBなどで情報を照会して返すことができます。返された情報は OAuth2Serverの各機能内で Code/Token発行などに使用されます。

    Arguments

    因子の説明は次の通りです。

    フィールドタイプ説明
    clientIdString認証/認可を処理する Clientの Client ID
    clientSecretString認証/認可を処理する Clientの Client Secret
    [callback]FunctionPromiseで返さない場合に使える callback関数

    Return Value

    レスポンスボディの説明は、次の通りです。

    フィールドタイプ説明
    clientObjectAccess Token/Refresh Tokenを作成する Client情報が含まれている Object
    client.idString認証/認可を処理する Clientの Client ID
    [client.redirectUris]Array<String>当該 Clientの Redirect URIの配列で、その URIに存在する Redirect URIのみ処理が可能
    [client.accessTokenLifetime]NumberAccess Tokenの期限切れ時間(秒)
    [client.refreshTokenLifetime]NumberRefresh Tokenの期限切れ時間(秒)

    Example Code

    generateAuthorizationCodeのサンプルコードは、次の通りです。

    {
        getClient: function(clientId, clientSecret) {
            // DBなどから情報を取得し、client Objectを作成して返す
            return new Promise(client);
        }
    }
    

    saveAuthorizationCode

    generateAuthorizationCodeで作成された Authorization Codeを保存する役割をします。実装によっては、DBまたは In Memory Storageに保存できます。保存された Authorization Codeを Tokenの発行時に getAuthorizationCode Modelから取り出し、有効性を検証できます。

    Arguments

    因子の説明は次の通りです。

    フィールドタイプ説明
    codeObject保存する Code
    code.authorizationCodeStringAuthorization Code
    code.expiresAtDate期限切れ時間
    code.redirectUriString発行された Authorization Codeに使用される Redirect URI
    clientObject発行された Authorization Codeの Client情報
    userObject発行された Authorization Codeの User情報
    [callback]FunctionPromiseで返さない場合に使える callback関数

    Return Value

    レスポンスボディの説明は、次の通りです。

    フィールドタイプ説明
    codeObject保存する Code
    code.authorizationCodeStringAuthorization Code
    code.expiresAtDate期限切れ時間
    code.redirectUriString発行された Authorization Codeに使用される Redirect URI
    code.clientObject発行された Authorization Codeの Client情報
    code.client.idString発行された Authorization Codeの Client ID情報
    code.userObject発行された Authorization Codeの User情報

    OAuth2.0 Login API(Authorization Code発行 API)例

    authenticateのサンプルコードは、次の通りです。

    const oauth = new OAuth2Server({model: ...});  // 先に実装された Model Objectを転送
    
    function authorizeHandler(options) {
        return function(req, res, next) {
            let request = new Request(req);
            let response = new Response(res);
            return oauth.authorize(request, response, options) // oauth.authorizeを呼び出すことで先に実装した Model が内部的に呼び出され、authorization codeを発行
                .then(function(code) {
                    res.locals.oauth = {code: code};
                    next();
                })
                .catch(function(err) {
                    // handle error condition
                });
        }
    }
    

    2. Token発行 API

    前段階で発行された Authorization Codeを Access Token/Refresh Tokenと交換/保存する機能を提供します。または、Refresh Tokenを通じて新しい Access Tokenを発行できます。
    Token発行機能のために実装すべき Modelは、次の通りです。

    generateAccessToken/generateRefreshToken

    この機能はオプション(Optional)です。実装しない場合、40文字のトークンが自動的に作成されます。独自のトークン発行アルゴリズムが必要な場合は、直接実装します。2つのモデルは同じ明細を示しています。

    Arguments

    因子の説明は次の通りです。

    フィールドタイプ説明
    clientObject
    • Access Token/Refresh Tokenを作成する Client情報が入った Object
    • getClient() Modelが呼び出され、その Modelで照会された情報を自動的に転送
    userObject
    • Access Token/Refresh Tokenを作成する User情報が含まれている
    • Authorization Code → Tokenの場合は Model#getAuthorizationCodeで照会された code.userが含まれており、Refresh Token → Tokenの場合は Model#getRefreshTokenで照会された token.userが含まれている
    [callback]FunctionPromiseで返さない場合に使える callback関数

    Return Value

    String(Access Token、Refresh Token値)タイプで返されます。

    Example Code

    generateAccessTokenのサンプルコードは、次の通りです。

    {
        generateAccessToken: function(client, user) {
            // AccessToken、RefreshTokenを作成する独自のロジックを作成してください。
            return new Promise(accessToken);
        }
    }
    

    getRefreshToken

    ユーザーから渡された Refresh Tokenが実際に存在する Refresh Tokenであるかを照会する目的で使用されます。
    DBなどで Refresh Tokenを照会できます。Refresh Tokenが検証された後、Grant Refresh Tokenの Token発行手続きが行われます。

    Arguments

    因子の説明は次の通りです。

    フィールドタイプ説明
    refreshTokenString検査する Refresh Token
    [callback]FunctionPromiseで返さない場合に使える callback関数

    Return Value

    レスポンスボディの説明は、次の通りです。

    フィールドタイプ説明
    tokenObject検査する Access Token
    token.refreshTokenStringgetRefreshTokenに渡された Refresh Token
    token.refreshTokenExpiresAtDate期限切れ時間
    token.clientObject
    token.client.idStringAccess Tokenに該当する Client ID

    Example Code

    getAccessTokenのサンプルコードは、次の通りです。

    {
        getRefreshToken: token => {
           if (!token || token === 'undefined') return false
            return new Promise(resolve => {
                // DBなどから渡された tokenの有効性(存在有無)を検査後にレスポンス
            })
        }
    }
    

    getClient

    Authorization Codeで実装された getClientをそのまま使用できます。

    getAuthorizationCode

    saveAuthorizationCodeで保存された Authorization Codeを取得する役割をします。実装によっては、DBまたは In Memory Storageから取得できます。保存された AuthorizationCodeを Tokenの発行時に getAuthorizationCode Modelから取り出し、有効性を検証できます。

    Arguments

    因子の説明は次の通りです。

    フィールドタイプ説明
    authorizationCodeString照会する Authorization Code
    [callback]FunctionPromiseで返さない場合に使える callback関数

    Return Value

    レスポンスボディの説明は、次の通りです。

    フィールドタイプ説明
    codeObject照会された Code
    code.codeStringAuthorization Code
    code.expiresAtDate期限切れ時間
    code.redirectUriString発行された Authorization Codeに使用される Redirect URI
    code.clientObject発行された Authorization Codeの Client情報
    code.client.idString発行された Authorization Codeの Client ID情報
    code.userObject発行された Authorization Codeの User情報

    saveToken

    generateAccessToken/generateRefreshTokenで作成された Tokenを保存する役割をします。実装によっては、DBまたは In Memory Storageに保存できます。保存時に saveTokenでは Access Token/Refresh Tokenの両方を保存する必要があることにご注意ください。保存時は1つの Modelで、照会時はそれぞれの Modelで照会することになります。

    Arguments

    因子の説明は次の通りです。

    フィールドタイプ説明
    tokenObject保存する Token
    token.accessTokenString保存する Access Token
    token.accessTokenExpiresAtDateAccess Tokenの期限切れ時間
    token.refreshTokenString保存する Refresh Token
    token.refreshTokenExpiresAtDateRefresh Tokenの期限切れ時間
    clientObject発行された Tokenの Client情報
    userObject発行された Tokenの User情報
    [callback]FunctionPromiseで返さない場合に使える callback関数

    Return Value

    レスポンスボディの説明は、次の通りです。

    フィールドタイプ説明
    tokenObject保存した Token
    token.accessTokenString保存した Access Token
    token.accessTokenExpiresAtDateAccess Tokenの期限切れ時間
    token.refreshTokenString保存した Refresh Token
    token.refreshTokenExpiresAtDateRefresh Tokenの期限切れ時間
    token.clientObject発行された Tokenの Client情報
    token.client.idString発行された Tokenの Client ID情報
    token.userObject発行された Tokenの User情報

    トークン発行の統合 Example

    authenticateのサンプルコードは、次の通りです。

    const oauth = new OAuth2Server({model: ...});  // 先に実装された Model Objectを転送
     
    // 下記の Handlerを PRISM OAuth2.0ガイドに従って/prism/v1/service/oauth2/token Routerで動作するように設定可能
    function tokenHandler(options) { // optionsには Token Life Timeなどのオプションを追加可能(https://oauth2-server.readthedocs.io/en/latest/api/oauth2-server.html#token-request-response-options-callback)
      return function(req, res, next) {
        let request = new Request(req);
        let response = new Response(res);
        return oauth.token(request, response, options) // oauth.authenticateを呼び出すことで先に実装した Modelsが内部的に呼び出され、authorization code/refresh token -> new tokenを発行
          .then(function(code) {
            res.locals.oauth = {token: token};
            next();
           })
          .catch(function(err) {
            // handle error condition
          });
      }
    }
    

    サンプルコードでは oauth.token(...)を包む Handlerを実装しましたが、上記サンプルコードの oauth.token(...)を API認証が必要な Routerなどで呼び出すことで、PRISM OAuth2.0連携のための/prism/v1/service/oauth2/token APIのレスポンスとして使用できます。

    3. Authenticate(認証)

    node-oauth2-serverでは発行された Access Tokenを利用した認証機能も提供します。認証機能のために実装する Modelは getAccessTokenです。

    getAccessToken Model

    ユーザーから渡された accessTokenが実際に存在する accessTokenかどうかを照会する目的で使用されます。DBなどで accessTokenを照会できます。

    Arguments

    因子の説明は次の通りです。

    フィールドタイプ説明
    accessTokenString検査する Access Token
    [callback]FunctionPromiseで返さない場合に使える callback関数

    Return Value

    レスポンスボディの説明は、次の通りです。

    フィールドタイプ説明
    tokenObject検査する Access Token
    token.accessTokenStringgetAccessTokenに渡された Access Token
    token.accessTokenExpiresAtDate期限切れ時間
    token.clientObject
    token.client.idStringAccessTokenに該当する Client ID

    Example Code

    getAccessTokenのサンプルコードは、次の通りです。

    {
        getAccessToken: token => {
           if (!token || token === 'undefined') return false
            return new Promise(resolve => {
                // DBなどから渡された tokenの有効性(存在有無)を検査後にレスポンス
            })
        }
    }
    

    authenticateの例

    authenticateのサンプルコードは、次の通りです。

    const oauth = new OAuth2Server({model: ...});  // 先に実装された Model Objectを転送
     
    function authenticateHandler(options) {
      return function(req, res, next) {
        let request = new Request(req);
        let response = new Response(res);
        return oauth.authenticate(request, response, options) // oauth.authenticateを呼び出すことで実装していた getAccessTokenが内部的に呼び出され、Tokenを検証
          .then(function(token) {
            res.locals.oauth = {token: token};
            next(); // Access Tokenが正常に認証され、次の MiddleWareに移行
          })
          .catch(function(err) {
            // handle error condition
          });
      }
    }
    

    サンプルコードの oauth.authenticate(...)を API認証が必要な Routerなどで Middlewareとして登録することで、ビジネスロジックと分離して認証できます。


    この記事は役に立ちましたか?

    Changing your password will log you out immediately. Use the new password to log back in.
    First name must have atleast 2 characters. Numbers and special characters are not allowed.
    Last name must have atleast 1 characters. Numbers and special characters are not allowed.
    Enter a valid email
    Enter a valid password
    Your profile has been successfully updated.