Salesforce B2C Commerce でOAuthを利用してGoogle Calendar API呼んでみた

※ これから記載する事項は、私が所属する会社とは一切関係のない事柄です。

この記事では[B2C CommerceのOAuth2 プロバイダー](https://documentation.b2c.commercecloud.salesforce.com/DOC1/topic/com.demandware.dochelp/content/b2c_commerce/topics/oauth2/b2c_customer_authorization_with_oauth2_providers.html?resultof=%22%4f%41%75%74%68%32%22%20%22%6f%61%75%74%68%32%22%20)を利用してGoogle Calendar APIを呼んでみたので、その実装方法を紹介します。


## 完成形

* カレンダーに「テスト　イベント」というイベントを作成。
![スクリーンショット 2021-12-22 14.36.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/85cc555f-58c7-2ff6-81aa-c4a0f82b4040.png)


* ブラウザで`/Oauth-Sample` に遷移し、Googleの同意画面に同意すると、下記のようなGoogle Calendar APIのレスポンスが表示される。
![スクリーンショット 2021-12-22 14.41.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/e9d35560-d84b-d422-f689-a4ebc15dd747.png)



## 手順概要

1. Google Cloud Platform Console に必要な情報を登録し、クライアントID/シークレットを取得する。
2. B2C Commerce Business ManagerからOAuth2 プロバイダーを登録する。
3. B2C Commerce Business Managerからサービスを登録する。
4. カートリッジの作成



## 手順詳細

### 1. Google Cloud Platform Console に必要な情報を登録し、クライアントID/シークレットを取得する。

* [Google Cloud Platform Console](https://console.cloud.google.com/) にログインし、任意のプロジェクトを選択する。（なければ作成）
* `APIとサービス > 認証情報`　に遷移し、「+認証情報の作成」ボタンから、「OAuth 2.0 クライアント ID」を作成。
* アプリーケーションの種類は「ウェブアプリケーション」を選択。
* 任意の名前と、承認済みのリダイレクトURLに「/Oauth-SampleRedirect」に遷移するURLを追加。
* 「作成」ボタンをクリック。
* `APIとサービス > 認証情報`　の一覧から作成した認証情報をクリックすると下記のような詳細画面になっており、「JSONをダウンロード」をクリックすれば、クライアントID/シークレットを含むクライアント情報が記載されたJSONファイルを取得できる。
![スクリーンショット 2021-12-22 14.46.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/6014af8a-b0e9-9537-f121-2c34724ab9cd.png)



* 今回はテストとして実行するので、`APIとサービス > OAuth同意画面 `に遷移し、ステータスは「テスト」にし、テストユーザーとして自身のGoogleアカウントを追加しました。
![スクリーンショット 2021-12-22 14.47.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/8ecd8200-192c-f43c-b781-8ed1c2036802.png)





### 2. B2C Commerce Business ManagerからOAuth2 プロバイダーを登録する。



* Business Managerの `管理 > グローバル環境設定 > OAuth2 プロバイダー` に遷移し、「新規」ボタンから新しくプロバイダーを作成する。
* 下記画像のように情報を入力していく。
    * **ID**　→　任意のID
    * **説明**　→　任意
    * **クライアントID**　→　1.でダウンロードしたJSON内の”client_id”の値
    * **クライアントシークレット**　→　1.でダウンロードしたJSON内の”client_secret”の値
    * **範囲**　→　OAuthのscope。今回はカレンダーを利用するので、`https://www.googleapis.com/auth/calendar.events.readonly `[`https://www.googleapis.com/auth/calendar.readonly`](https://www.googleapis.com/auth/calendar.readonly)  (間は半角スペース)
    * **認証URL**　→　1.でダウンロードしたJSON内の”auth_uri”の値
    * **トークンURL**　→　1.でダウンロードしたJSON内の“token_uri”の値
    * **ユーザー情報URL**　→　`https://www.googleapis.com/oauth2/v1/userinfo?alt=json`
    * **ユーザー情報URLアクセストークン名**　→　`access_token`
    * **リダイレクトパイプライン**　→　のちにカートリッジで実装するパイプライン。 `Oauth-SampleRedirect`
* 入力が終わったら「適用」ボタンで作成する。
![スクリーンショット 2021-12-22 14.38.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/d9978cc1-eaf4-36ed-5cd8-717224d627d8.png)




### 3. B2C Commerce Business Managerからサービスを登録する。



* Business Managerの `管理 > オペレーション > サービス` に遷移し「認証情報」タブを選択し、「新規」ボタンから新しくサービス認証情報を作成する。
* 下記画像のように入力したら、「適用する」ボタンをクリックし作成する。
    * 名前　→　任意の名前
    * URL　→　`https://www.googleapis.com/calendar/v3`
![スクリーンショット 2021-12-22 14.38.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/c62a8b74-9114-d3c0-cb95-9b0a80f6ebef.png)



* Business Managerの `管理 > オペレーション > サービス` に遷移し「サービス」タブを選択し、「新規」ボタンから新しくサービスを作成する。
* 下記画像のように入力したら、「適用する」ボタンをクリックし作成する。
    * 名前　→　任意の名前
    * 有効　→　チェック入れる
    * 認証情報　→　先ほど作成した認証情報の名前を選択
![スクリーンショット 2021-12-22 14.38.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/859341e0-3b3a-5269-d3e3-77bc86affa54.png)




### 4. カートリッジの作成

* 下記のように`/cartridge/controllers/Oauth.js` と `/cartridge/scrips/gcalAPIService.js　`ファイルを含んだカートリッジを作成しデプロイする。（カートリッジの作成方法とデプロイ方法は[こちらの記事](https://qiita.com/syunyama/items/21c71ac9c49b332e126d#%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4%E6%96%B9%E6%B3%95)を参照してください。）
![スクリーンショット 2021-12-22 15.49.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/1f8f5901-8f27-7934-2e84-e4aecf62acac.png)


※下記ソースコードは見やすさを考慮して最小限のコードにとどめてありますので、実際使う際は構造変更・エラーハンドリング・JS Docsの記載をした方がいいと思います。


* `Oauth.js`

```js
"use strict";

var server = require("server");
var services = require("*/cartridge/scripts/gcalAPIService");
var oauthLoginFlowMgr = require("dw/customer/oauth/OAuthLoginFlowMgr");

server.get("Sample", function (req, res, next) {
    var result = oauthLoginFlowMgr.initiateOAuthLogin("{OAuthプロバーダーに設定した名前（今回はsample_gcal）}");
    if (!result) {
        res.render("/error", {
            message: "失敗しました",
        });
        return next();
    }
    res.redirect(result.location);
    next();
});

server.get("SampleRedirect", function (req, res, next) {
    var accessTokenResponse = oauthLoginFlowMgr.obtainAccessToken();
    var token = accessTokenResponse.accessToken;
    var event = services.getEvents(token, "{カレンダーのID（自分の場合はgoogleアカウントのEメールアドレスでした）}", "テストイベント")
    res.json(event);
    next();
});

module.exports = server.exports();
```

* `gcalAPIService.js`

```js
"use strict";

var LocalServiceRegistry = require("dw/svc/LocalServiceRegistry");

function _createService() {
    return LocalServiceRegistry.createService("{サービスの名前に設定した値（今回はoauth.test）}", {
        createRequest: function (svc, _path, _token) {
            var url = svc.getURL() + _path;
            svc.setURL(url)
                .setRequestMethod("GET")
                .addHeader("authorization", "Bearer " + _token);
        },
        parseResponse: function (svc, response) {
            return JSON.parse(response.text);
        },
        filterLogMessage: function (msg) {
            return msg;
        },
    });
}

function getEvents(token, calID, querytext) {
    var service = _createService();
    var path = "/calendars/" + calID + "/events?q=" + querytext;
    var result = service.call(path, token);
    return result.object.items;
}

module.exports = {
    getEvents: getEvents,
};
```




## コードの解説

* `Oauth.js`
    * OAuthを実装する場合は [OAuthLoginFlowMgr](https://documentation.b2c.commercecloud.salesforce.com/DOC1/topic/com.demandware.dochelp/DWAPI/scriptapi/html/api/class_dw_customer_oauth_OAuthLoginFlowMgr.html) を利用するといいようです。まず、`oauthLoginFlowMgr.initiateOAuthLogin(OAuthProviderID)`によってアプリケーションに認証を行い、成功した場合は、`res.redirect(result.location)`によってユーザに対してGoogleの同意画面へリダイレクトさせます。同意後は[Google Cloud Platform Console](https://console.cloud.google.com/) で設定したURL（/Oauth-SampleRedirect）へコードとともにリダイレクトされます。
    * `/Oauth-SampleRedirect` に遷移されたら、`oauthLoginFlowMgr.obtainAccessToken()`が実行され、アクセストークンを取得し、そのトークを利用しCalendar APIを呼び、そのレスポンスをそのままブラウザに描写しています。