【Shopify】Multipass ログイン時に「マルチパスログインを使用する権限が付与されていません」とエラーが発生した場合の解決方法

## 概要

![スクリーンショット 2022-03-27 0.03.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/688854/b9ee6630-2eaa-1e18-352e-60d91b53b18b.png)

とあるサービスの開発において、Shopify の Multipass ログインを利用した際に生じた `「マルチパスログインを使用する権限が付与されていません」` というエラーに長時間ハマる事になったため、その原因や解決方法に関してメモ書き。

https://shopify.dev/api/multipass

## 背景

- [Auth0](https://auth0.com/jp) を認証基盤とした Shopify へのシングルサインオン（SSO）

Multipass を用いた Auth0 と Shopify の連携方法については下記の記事を参考にしました。

https://rovani.net/posts/2019/authenticate-shopify-customers-with-auth0/

## 原因

結論から言ってしまうと、直接的な原因は Auth0 の Rules 内に記述していたスクリプト内にありました。

```js:./Auth0/Auth Pipeline/Rules
function (user, context, callback) {
  if (context.clientMetadata && context.clientMetadata.shopify_domain && context.clientMetadata.shopify_multipass_secret)
  {
    const RULE_NAME = 'shopify-multipasstoken';
    const CLIENTNAME = context.clientName;
    console.log(`${RULE_NAME} started by ${CLIENTNAME}`);

    const now = (new Date()).toISOString();
    let shopifyToken = {
      email: user.email,
      created_at: now,
      identifier: user.user_id,
      remote_ip: context.request.ip
    };
    if (context.request && context.request.query && context.request.query.return_to){
      shopifyToken.return_to = context.request.query.return_to;
    }

    if (context.user_metadata)
    {
      shopifyToken.first_name = user.user_metadata.given_name;
      shopifyToken.last_name= user.user_metadata.family_name;
    }

    const hash = crypto.createHash("sha256").update(context.clientMetadata.shopify_multipass_secret).digest();
    const encryptionKey = hash.slice(0, 16);
    const signingKey = hash.slice(16, 32);

    const iv = crypto.randomBytes(16);
    const cipher = crypto.createCipheriv('aes-128-cbc', encryptionKey, iv);
    const cipherText = Buffer.concat([iv, cipher.update(JSON.stringify(shopifyToken), 'utf8'), cipher.final()]);

    const signed = crypto.createHmac("SHA256", signingKey).update(cipherText).digest();

    const token = Buffer.concat([cipherText, signed]).toString('base64');
    const urlToken = token.replace(/\+/g, '-').replace(/\//g, '_');

   context.redirect = {
     url: `https://${context.clientMetadata.shopify_domain}/account/login/multipass/${urlToken}`
   };
  }
  return callback(null, user, context);
}
```

注目すべきは shopifyToken の部分で、

```js
let shopifyToken = {
  email: user.email,
  created_at: now,
  identifier: user.user_id,
  remote_ip: context.request.ip
};
```

この中に `remote_ip` という値を含めてしまっていたのが問題だったみたいです。

どうやらこの remote_ip をトークン内に含めると、リクエスト元のブラウザのIPアドレスと一致しなかった場合に権限エラーを吐くようになるとの事。

> Multipass returns the error "You are not authorized to use Multipass login" if the remote_ip doesn't match the IP specified in the customer data hash.

この辺は Shopify のドキュメント内やフォーラム内にも記載されていました。

https://community.shopify.com/c/shopify-apis-and-sdks/multipass-remote-ip-ipv6-support/m-p/749273/highlight/true#M49874

## 解決方法

shopifyToken の中から `remote_ip` を削除。

元々、Multipass ログイン時の必須パラメータは

- email
- created_at

の2つのみなので、不要であれば取り除いてもOKみたいです。

セキュリテイ的な意味では弱くなるかもしれませんが、止むを得ない場合もあるのでそうしました。

## まとめ

Shopify 関連のエラーはググっても日本語の情報があまり出てこないため、英語で検索する事の重要性を改めて感じました。

たとえば、今回のケースでも`「マルチパスログインを使用する権限が付与されていません」`と検索してもほとんど有力な情報は得られませんでしたが、それを英語に直して`「You are not authorized to use multipass login」`と検索した途端に回答が出てきたので、今後は注意したいところです。