Salesforce B2C Commerce のヘッドレス API を呼んでみる(ショッパー系 API - SCAPI パブリッククライアント編) 

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

***
この記事はヘッドレス API の使い方のシリーズの一つです。その他の記事は下記を参照してください。
* [ショッパー系 API - SCAPI パブリッククライアント編](https://qiita.com/syunyama/items/89b204486ace9fd10440)
* [ショッパー系 API - SCAPI プライベートクライアント編](https://qiita.com/syunyama/items/34bd2a11dabb93bb1dc1)
* [ショッパー系 API - OCAPI 編](https://qiita.com/syunyama/items/0bb4a6e095a53dac7267)
* [データ系 API 編](https://qiita.com/syunyama/items/060f5777b0fc04e4cea1)
***

**今回は SCAPI パブリッククライアントを利用したショッパー系 API の呼び方を紹介したいと思います。**

:::note
- データ系とショッパー系の違いについては「[データ系 API 編](https://qiita.com/syunyama/items/060f5777b0fc04e4cea1) 」を参照してください。
- SCAPI のショッパー系の API の認証する際には ２ つのクライアントタイプがあります。タイプの違いについては、「[ショッパー系 API - SCAPI プライベートクライアント編](https://qiita.com/syunyama/items/34bd2a11dabb93bb1dc1)」を参照してください。
:::

この記事では、SCAPI のパブリッククライアントで ３ つの顧客タイプが商品をカートに追加するユースケースを説明します。

* **ゲストユーザ** ・・・ ログインしていないユーザ
* **登録済みユーザ(B2C Login)** ・・・ B2C Commerce に登録済みユーザ
* **登録済みユーザ(Federated Login)** ・・・ Google や Facebook といったIDプロバイダーを利用して(Federated Login)ログインしたユーザ




## ショッパー系APIの呼び方
### 1. API クライアントの作成
### 2. スコープの設定
### 3. (Federated Login のために) Google OAuth2.0 の設定
### 4. (Federated Login のために) IDP を登録
１〜４ は、「[ショッパー系API - SCAPI プライベートクライアント編](https://qiita.com/syunyama/items/34bd2a11dabb93bb1dc1#%E3%82%B7%E3%83%A7%E3%83%83%E3%83%91%E3%83%BC%E7%B3%BBapi%E3%81%AE%E5%91%BC%E3%81%B3%E6%96%B9) 」と同じなので割愛


### 5. SLAS テナントの登録

「[Create a SLAS Client](https://developer.salesforce.com/docs/commerce/commerce-api/guide/authorization-for-shopper-apis.html#create-a-slas-client)」を参照してください。
この際に、 **[Private?]** の値を **false** に **[Redirect URI]** の値にコールバックで処理する自身のアプリケーションのエンドポイントを設定してください。(例：`http://localhost:3000/callback`)

:::note
この時生成した `Client Id` と `Secret` をメモしておいてください。
:::


### 6. アクセストークンの取得

#### ゲストユーザ

![public-guest-user-fc8126f5-f2d6-4cc6-addf-a9bb04a58049 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/94d9c9dd-d96a-a756-f254-16ca76c3aabd.png)

* まずは下記のようなリクエストでユーザーがログインをする。
    * `shortCode`、`tenantID`、`orgID`、`siteID`、`realmID` については 「[B2C Commerce に関わる ID を把握](https://qiita.com/syunyama/items/58433ae8e3c5fda7f37e#a--b2c-commerce-%E3%81%AB%E9%96%A2%E3%82%8F%E3%82%8B-id-%E3%82%92%E6%8A%8A%E6%8F%A1)」 を参照してください。
    * `clientID` は **「5.SLASテナントの登録」** で設定した `clientId` の値を入力
    * `redirectUri` はコールバックで処理する自身のアプリケーションのエンドポイントを入力
    * `code_challenge` は `code_verifier` という 43 ～ 128 文字の文字列を SHA256 でハッシュ化したものを入力。（ロジックは公開されている[Postmanコレクション](https://www.postman.com/salesforce-developers/workspace/salesforce-developers/request/15394816-99057296-4e2f-4474-8ff6-4374bb368f98)の Pre-request Script を参照）

```http
REQUEST: 
GET /shopper/auth/v1/organizations/{orgID}/oauth2/authorize
?redirect_uri={redirect_url}
&response_type=code
&client_id={clientID}
&hint=guest
&code_challenge={codeChallenge} HTTP/1.1
Host: {shortCode}.api.commercecloud.salesforce.com
```



* 上記のリクエストをすると HTTP ステータスが 303 でレスポンスヘッダーの `Location` に `{redirectUri}?usid={}&code={}`（例：`http://localhost:3000/callback?usid={}&code={}`）のフォーマットで URL が入っているので、その URL にブラウザでリダイレクトさせる。
* 自身のアプリケーションで、 `/callback` を実装し、`code` の値を利用して下記のリクエストを行い、レスポンスボディ内の `access_token` を取得
    * `code_verifier` は `code_challenge` 生成時に利用した文字列。（ロジックは公開されている[ Postman コレクション](https://www.postman.com/salesforce-developers/workspace/salesforce-developers/request/15394816-99057296-4e2f-4474-8ff6-4374bb368f98)の Pre-request Script を参照）
    * `code` はリダイレクト先（`Location`） URL のパラメータに入っている `code` を入力
```http
REQUEST: 
POST /shopper/auth/v1/organizations/{orgID}/oauth2/token HTTP/1.1
Host: {shortCode}.api.commercecloud.salesforce.com
Content-Type: application/x-www-form-urlencoded 

REQUEST PARAMETER: 
grant_type=authorization_code_pkce
&client_id={clientID}
&redirect_uri={redirectUri}
&code_verifier={codeVerifier}
$code={code}
```



#### 登録済みユーザ(B2C Login)

![public-client-registered-user-b2c-fab0b3d7-08c7-43f2-b4ab-0f47fb7e40e3-7ccab931-3b53-4d73-9fdb-ebc662f1624b (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/cdfc3948-408b-01b0-8bf1-6de560c1fb43.png)



* まずは下記のようなリクエストでユーザーがログインをする。
    * `usid` はゲストユーザのトークン取得時のレスポンスボディにある `usid` に値を入力
    * `userCredential` は ユーザ ID / パスワード、それらを `id:password`のようにコロン(:)で結合したものを Base64 でエンコードした値です。

```http
REQUEST: 
POST /shopper/auth/v1/organizations/{orgID}/oauth2/login HTTP/1.1
Host: {shortCode}.api.commercecloud.salesforce.com 
Authorization: Basic {userCredential}
Content-Type: application/x-www-form-urlencoded 

REQUEST PARAMETER: 
grant_type=client_credentials
&client_id={clientID}
&redirect_uri={redirectUri}
&channel_id={siteID}
&code_challenge={codeChallenge}
&usid={usid}
```



* 上記のリクエストをすると HTTP ステータスが 303 でレスポンスヘッダーの `Location` に `{redirect_uri}?usid={}&state={}&scope=openid%20offline_access&code={}` のフォーマットでURLが入っているので、その URL にブラウザでリダイレクトさせる。
* 自身のアプリケーションで、 `/callback` を実装し、`code` の値を利用して下記のリクエストを行い、レスポンスボディ内の `access_token` を取得

```http
REQUEST: 
POST /shopper/auth/v1/organizations/{orgID}/oauth2/token HTTP/1.1
Host: {shortCode}.api.commercecloud.salesforce.com
Content-Type: application/x-www-form-urlencoded 

REQUEST PARAMETER:
grant_type=authorization_code_pkce
&client_id={clientID}
&redirect_uri={redirectUri}
&code_verifier={codeVerifier}
$code={code}
```



#### 登録済みユーザ(Federated Login)

![public-registered-user-federated-login-d8b425d1-7d3b-41c3-a9f9-5d6e21a9779c (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/af2de175-b32e-6024-f576-2c3b348a3f20.png)


* まずは下記のようなリクエストでユーザーがログインをする。
    * `IDPID`は **「4.(Federated Loginのために) IDP を登録」** で作成した `IDPID`。今回は`google`

```http
REQUEST: 
GET /shopper/auth/v1/organizations/{orgID}/oauth2/authorize
?redirect_uri={redirect_url}
&response_type=code
&client_id={clientID}
&hint={IDPID}
&channel_id={siteID}
&usid={usid}
&code_challenge={codeChallenge} HTTP/1.1
Host: {shortCode}.api.commercecloud.salesforce.com
```



* 上記のリクエストをすると HTTP ステータスが 303 でレスポンスヘッダーの `Location` に`https://accounts.google.com/o/oauth2/auth?scope=openid%20email%20profile&response_type=code&client_id={}&redirect_uri={}&state={}`のフォーマットで URL が入っているので、その URL にブラウザでリダイレクトさせる。
* すると画像のように Google のログイン画面に遷移するので、ログイン。

:::note warn
Google Cloud Platform の [OAuth 同意画面](https://console.cloud.google.com/apis/credentials/consent)ページで公開ステータスを「テスト」でテストユーザを設定している場合は、そのユーザでログインしてください。
:::


![スクリーンショット 2022-04-11 17.01.22 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2110894/a88a4630-0984-c0c7-bac1-2b4bbfa53c87.png)



* ログイン成功すると `http://localhost:3000/callback?usid={}&code={}` のフォーマットの URL にブラウザでリダイレクトさせる。
* 自身のアプリケーションで、 `/callback` を実装し、`code` の値を利用して下記のリクエストを行い、レスポンスボディ内の `access_token` を取得

```http
REQUEST: 
POST /shopper/auth/v1/organizations/{orgID}/oauth2/token HTTP/1.1
Host: {shortCode}.api.commercecloud.salesforce.com
Content-Type: application/x-www-form-urlencoded 

REQUEST PARAMETER:
grant_type=authorization_code
&redirect_uri={redirectUri}
&code={code}
&code_verifier={codeVerifier}
&channel_id={siteID}
```




### 7.  ショッパー系 API を呼ぶ

７ は、「[ショッパー系 API - SCAPI プライベートクライアント編](https://qiita.com/syunyama/items/34bd2a11dabb93bb1dc1#7--%E3%82%B7%E3%83%A7%E3%83%83%E3%83%91%E3%83%BC%E7%B3%BB-api-%E3%82%92%E5%91%BC%E3%81%B6)」と同じなので割愛します。