ディープリンク経由の認証設定

ディープリンクは、ユーザーIDまたはエクソーラログイン経由での認証プロセスの代わりに、ゲームを通じてウェブショップでワンクリックで認証できるようになります。

ユーザーのモバイルデバイスにゲームがインストールされている場合、認証トークンを取得するために、ディープリンク経由でゲームにリダイレクトされます。

ユーザーフロー

  1. ウェブショップで未認証のユーザーがログインボタンまたは購入ボタンをクリックします。ユーザーIDを入力するか、モバイルゲームからログインするためのモーダルウィンドウが開きます。
  1. ユーザーはゲームを通してログインボタンをクリックします。
  2. ユーザーは、認証ユーザーとして自動的にウェブショップにリダイレクトされます。

  1. ウェブショップで未認証のユーザーがログインボタンまたは購入ボタンをクリックします。ユーザーIDを入力するか、QRコードを使ってモバイル版ゲームにログインするためのモーダルウィンドウが開きます。

  1. ユーザーはモバイルデバイスを使用してQRコードをスキャンすると、モバイルデバイスでウェブショップが開きます。
  2. モバイル版のゲームは、ユーザーのモバイルデバイスで開きます。
  3. ユーザーは、認証されたユーザーとして自動的にモバイルデバイス上のウェブショップにリダイレクトされます。
  1. ゲームのモバイルアプリ設定で、ディープリンク経由でゲームを開くためのURLスキームを新規登録してください:
    • Androidアプリ — AndroidManifest.xmlファイル
    • iOSアプリ — Info.plistファイル
スキームを登録した後、ユーザーがゲームを介してウェブショップで認証すると、ゲームは指定されたアドレスでゲームが開きます。 ゲームを登録するためのURLスキームの例: gamename://authorize、そこに:
  • gamename — ユーザー認証のためにモバイルデバイスで開くゲーム名。
  • authorize — ゲーム名のゲームが開いた後に実行されるアクション名の例。アプリケーションのオペレーティングシステムのアクションと一致するアクション名を使用してください。
iOSアプリケーションでURLスキームを登録する例:
Copy
Full screen
Small screen
    <key>CFBundleURLTypes</key>
      <array>
        <dict>
          <key>CFBundleTypeRole</key>
          <string>Editor</string>
          <key>CFBundleURLSchemes</key>
          <array>
            <string>gamename</string>
          </array>
        </dict>
      </array>
    

    AndroidアプリケーションでURLスキームを登録する例:

    Copy
    Full screen
    Small screen
      <intent-filter>
          <action android:name="android.intent.action.VIEW" />
          <category android:name="android.intent.category.DEFAULT" />
          <category android:name="android.intent.category.BROWSABLE" />
          <data android:scheme="gamename" android:host="authorize" />
      </intent-filter>
      

      1. ゲームのユーザーIDを使用したJWT形式の認証トークンの生成を実装します。

      パラメータ種類説明文
      stringアドミンページからの認証メソッドのID。必須
      stringウェブショップでのユーザー検証ウェブフックを受信するためのURL。URLは、ユーザーIDによる認証の設定で指定したアドレスと一致する必要があります。エクソーラは、ウェブフックへの応答としてHTTPコード200を期待しており、これによりウェブショップのユーザーが認証されます。エクソーラが404 HTTPコードで応答を受信した場合、または応答を受信しなかった場合、ユーザーは認証されません。

      ディープリンク経由で認証する際にウェブフックを無効にするには、"webhookUrl": "https://nowebhook.com"の値を指定できます。この場合、エクソーラはユーザーの存在を確認しませんので、 user.idパラメータにはゲーム内に存在するユーザーIDを渡すようにしてください。
      必須
      stringブラウザのアドレスバーでプロジェクト名の横に指定されている、アドミンページで確認できるプロジェクトID。URLの形式は次のようになります:https:​//publisher.xsolla.com/merchant ID/Publisher Account section必須
      stringゲーム内のユーザーID。必須
      stringユーザー名。必須

      curlを使用してユーザートークン生成APIメソッドを呼び出す例:

      Copy
      Full screen
      Small screen
      curl --location 'https://sb-user-id-service.xsolla.com/api/v1/user-id' \
      --header 'Content-Type: application/json' \
      --data '{
       "loginId": "000001aa-001a-0ab0-00001-01a01a01a01a",
       "webhookUrl": "https://nowebhook.com",
       "settings": {
         "projectId": 123456,
         "merchantId": 123456
       },
       "user": {
         "id": "123",
         "name": "a-user-name"
       }
      }'
      

      {token=“JWT_TOKEN”}のような応答が返されます。

      1. 認証成功の通知を含むポップアップウィンドウを追加します(任意)。
      2. 取得したユーザートークンを使用して、「ブラウザでウェブショップを開く」を実装します。

      認証されたユーザーがブラウザでウェブショップを開くためのURLを作成する例:

      • https:​//example.com/?token={token}、カスタムドメインを使用する場合
      • https:​//example.xsollasitebuilder.com/?token={token}、エクソーラドメインを使用する場合
      ここで、{token}はユーザーの認証トークンです。以下のコード例を使用して、サイトビルダー側で設定を行うことができます。
      セットアップの支援が必要な場合は、カスタマーサクセスマネージャーに連絡するか、 csm@xsolla.comまでメールでお問い合わせください。
      お知らせ
      まず、ユーザーIDによる認証を設定します。これは、ユーザーがディープリンク認証を利用できない場合、別の認証方法を提供するために必要です。例えば、ユーザーのモバイルデバイスにゲームがインストールされていない場合などです。
      1. アドミンページであなたのプロジェクトを開きます。
      2. サイドメニューで、「サイトビルダー」をクリックします。
      3. ウェブショップサイトのカード上で、ユーザーID経由の認証が設定されている場合、「構成」をクリックしてください。
      4. カスタムコードブロックを使用してディープリンク認証を追加します。
      5. JavaScript」タブの「カスタムコード」ブロックに、モバイル版とデスクトップ版のディープリンク認証を実装する以下のカスタムコードを追加します。
      1. コード内の定数の値を実際の値に置き換えます。そこに:
        • DEEPLINK_URL — ディープリンクでゲームを開くためのURLスキーム。
        • QR_CODE — SVG形式のゲームを開くためのQRコード。QRコードにはsource = pcパラメータでウェブショップへのリンクが含まれていなければなりません。
        • deeplink__description — モバイルアプリケーションのゲーム認証ボタンの下に表示される説明。
        • qr-code-auth__description — デスクトップ版のゲームのQRコードの下に表示される説明。
      Copy
      Full screen
      Small screen
      {
          const DEEPLINK_URL = 'gamename://authorize';
          const QR_CODE = `YOUR_SVG_WITH_QR_CODE`;
          handleQRCodeRedirect();
      
      // Event handlers are set up for opening the authentication modal or for successful authentication.
      // If the event of opening the authentication modal occurs, the handler is triggered and a button or QR code is added to this window.
      // If the event of successful authentication occurs, the handler is triggered and the successful authentication modal is opened.
      
          window.addEventListener('custom-event:modal:render', updateLoginModal);
          window.addEventListener('custom-event:authorization:login', showLoginSuccessPopup);
          let getToken;
      
          const searchParams = new URLSearchParams(window.location.search);
          const tokenParam = searchParams.get('token');
          if (tokenParam) {
              showLoginSuccessPopup(tokenParam);
          }
      
          window.SB.subscribe(api => {
              getToken = api.getToken;
          });
      
      // Customization of the authentication modal window (adding a QR code for the desktop version of the game or a login button for the mobile version of the game).
      
          function updateLoginModal({detail}) {
              const {name, element} = detail;
              if (name !== 'user-id' || element.dataset.isQrAdded === 'true') return;
              const isMobile = checkMobileDevice();
              const ModalBody = element.querySelector('.ui-site-modal-window__body');
              const ModulInput = ModalBody.querySelector('.user-id-modal__input');
              element.classList.toggle('mobile-layout', isMobile);
              ModalBody.append(getTemplate(isMobile));
      
              element.dataset.isQrAdded = true;
          }
      
      // Function to display the successful authentication modal window.
      
        function showLoginSuccessPopup(t) {
          let username = 'Gamer';
          try {
            const token = getToken?.() || t;
            if (token) {
              const jwtData = parseJwt(token);
              const payload = JSON.parse(jwtData.payload);
              if (payload.userInfo.name) {
                username = payload.userInfo.name;
              } else if (jwtData.username) {
                username = jwtData.username;
              } else if (jwtData.server_custom_id) {
                username = jwtData.server_custom_id;
              }
            }
          } catch (e) {
            console.log('error', e);
          }
      
          const Modal = document.querySelector('.deeplink-auth');
          const ModalTitle = Modal.querySelector('.deeplink-auth__title');
      
          ModalTitle.textContent = ModalTitle.textContent.replace(/\{username}/g, username);
      
          Modal.classList.add('_visible');
          Modal.querySelector('.deeplink-auth__button').addEventListener('click', closeModal);
      
          function closeModal() {
            Modal.classList.remove('_visible');
          }
        }
      
      // Function that displays a QR code for the desktop version of the game or a login button for the mobile version of the game. Your_game should be replaced with the actual name of your game. To continue with the authentication, the game has to be installed on the user's phone.
      
        function getTemplate(isMobile) {
          const Deeplink = document.createElement('div');
      
          if (isMobile) {
            Deeplink.innerHTML = `
              <div class="deeplink__title"><span class="deeplink__title-text">or login via game</span></div>
              <a href="${DEEPLINK_URL}" class="deeplink__button" rel="noopener">Login via Mobile Game</a>
              <div class="deeplink__description">
                You need to have the Your_game installed on your phone in order to proceed with authorization and purchase
              </div>
            `;
      
            return Deeplink;
          }
      
          Deeplink.innerHTML = `
            <div class="separator">
              <span class="separator__text">or login via game</span>
            </div>
            <div class="qr-code-auth">
              <div class="qr-code-auth__image">${QR_CODE}</div>
              <span class="qr-code-auth__description">
              Scan the QR code with your phone and you will continue purchasing on your mobile device
              </span>
            </div>
          `;
      
          return Deeplink;
        }
      
        function checkMobileDevice() {
          return (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent));
        }
      
      //  Function that decodes the JWT token and returns its payload as a JavaScript object.
      
        function parseJwt(token) {
          const base64Url = token.split('.')[1];
          const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
          const jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function (c) {
            return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
          }).join(''));
      
          return JSON.parse(jsonPayload);
        }
      
      // Function to verify the vent occurred when the user scanned the QR code.
      
        function handleQRCodeRedirect() {
          const url = new URL(window.location.href);
          const source = url.searchParams.get('source');
          if (source === 'pc') {
            if (checkMobileDevice()) {
              const button = document.getElementById("deeplink-redirect");
              button.click();
            }
      
            setTimeout(function () {
              url.searchParams.delete('source');
              window.history.pushState({}, '', url);
            }, 2000);
          }
        }
      }
      
      1. HTML」タブの「カスタムコード」ブロックに、ウェブショップで認証に成功したことを示すモーダルウィンドウのコードを追加します。独自のテキスト値を設定することができます。
      Copy
      Full screen
      Small screen
      <div class="ui-site-modal-window deeplink-auth">
        <div class="deeplink-auth__body">
          <div class="deeplink-auth__image"></div>
          <div class="deeplink-auth__title">Hi, {username}!</div>
          <div class="deeplink-auth__description">You’ve successfully logged in to the Web Shop</div>
          <button class="deeplink-auth__button">Continue</button>
        </div>
      </div>
      
      <a href="gamename://authorize" id="deeplink-redirect" style="display: none;"></a>
      
      1. CSS」タブの「カスタムコード」ブロックに、新しいインターフェースコンポーネント用のスタイルを追加します。推奨スタイルは以下の通りです。認証に成功したときに表示される独自の画像のURLを指定します。
      Copy
      Full screen
      Small screen
      --deeplink-success-image-url: url("Successful_authorization_image_url");
      
      .html-v2:has(.deeplink-auth._visible) {
        z-index: var(--modalsZIndex);
      }
      
      .user-id-modal__content {
        padding: 0 16px !important;
      }
      
      @media (min-width: 768px) {
        .user-id-modal__content {
          max-width: 460px !important;
          padding: 0 3.8rem 4rem !important;
          overflow: auto;
          justify-content: center;
        }
      }
      
      .mobile-layout .user-id-modal__close {
        right: 8px;
        top: 16px;
      }
      
      .user-id-modal__logo {
        width: 109px;
        height: 38px;
        margin: 4rem auto 2rem;
      }
      
      .user-id-modal.mobile-layout .user-id-modal__logo {
        margin: 3rem auto 2.5rem;
      }
      
      .user-id-modal__wrapper {
        margin-top: 0;
      }
      
      .user-id-modal__title {
        margin-bottom: 3rem;
      }
      
      .user-id-modal__input-wrapper .ui-site-input {
        height: 41px;
      }
      
      .user-id-modal__input {
        margin-top: 0;
        border-radius: var(--border-radius-16);
      }
      
      .user-id-modal__button {
        height: auto;
        margin: 12px auto 0;
        padding: 1.25rem;
        border-radius: var(--border-radius-16);
      }
      
      .user-id-modal__button .simple-button__text {
        font-size: 1.8rem;
        font-weight: 500;
        line-height: 2.5rem;
        letter-spacing: 0.5px;
      }
      
      .user-id-modal .ui-site-instruction-cut__title .ui-site-description {
        margin-bottom: 3rem;
        font-size: 1.2em;
      }
      
      .user-id-modal .ui-site-instruction-cut__steps {
        overflow-y: visible;
      }
      
      .user-id-modal .ui-site-instruction-card:first-child {
        margin-top: 0;
      }
      
      .user-id-modal .ui-site-instruction-card:last-child {
        padding-bottom: 4rem;
      }
      
      .user-id-modal .separator {
        display: flex;
        margin-bottom: 3.8rem;
        align-items: center;
      }
      
      .user-id-modal .separator__text {
        padding: 0 1.5rem;
        font-family: var(--main-font);
        font-size: 1.8rem;
        font-weight: 500;
        line-height: 2.5rem;
        letter-spacing: 0.8px;
      }
      
      .user-id-modal .separator::before,
      .user-id-modal .separator::after {
        content: "";
        background-color: #797979;
        height: 1px;
        flex-grow: 1;
      }
      
      .user-id-modal .qr-code-auth__image {
        display: block;
        width: 160px;
        height: 160px;
        margin: 0 auto 20px;
      }
      
      .user-id-modal .qr-code-auth__image svg {
        display: block;
        width: 100%;
        height: 100%;
      }
      
      .user-id-modal .qr-code-auth__description {
        display: inline-block;
        font-family: var(--main-font);
        font-size: 1.5rem;
        font-weight: 400;
        line-height: 2.5rem;
        text-align: center;
        color: rgba(255, 255, 255, 0.7);
      }
      
      .deeplink__title {
        display: flex;
        margin-bottom: 3.8rem;
        align-items: center;
      }
      
      .deeplink__title-text {
        padding: 0 1.5rem;
        font-family: var(--main-font);
        font-size: 1.8rem;
        font-weight: 500;
        line-height: 2.5rem;
        letter-spacing: 0.8px;
      }
      
      .user-id-modal .deeplink__title::before,
      .user-id-modal .deeplink__title::after {
        content: "";
        background-color: #797979;
        height: 1px;
        flex-grow: 1;
      }
      
      .deeplink__button {
        display: block;
        margin-bottom: 2.2rem;
        padding: 1.3rem;
        font-family: var(--main-font);
        font-size: 1.8rem;
        font-weight: 500;
        line-height: 2.5rem;
        letter-spacing: 0.5px;
        text-align: center;
        color: var(--button-text-color);
        background: var(--accent-color);
        border-radius: var(--border-radius-16);
        text-decoration: none;
        transition: transform .2s cubic-bezier(.509, .001, .25, 1);
      }
      
      .deeplink__button:hover {
        transform: scale(.95);
      }
      
      .deeplink__description {
        margin-bottom: 2rem;
        font-family: var(--main-font);
        font-size: 1.6rem;
        line-height: 2.3rem;
        text-align: center;
        color: rgba(255, 255, 255, 0.7);
        letter-spacing: 0.5px;
      }
      
      .deeplink__cta-wrapper {
        display: flex;
        flex-direction: row;
        gap: 1.8rem;
        padding: 0 1.2rem;
      }
      
      .deeplink__cta-wrapper .ui-site-calltoaction__item {
        margin: 0;
        flex-grow: 2;
      }
      
      .deeplink__cta-wrapper .ui-site-calltoaction {
        width: 100%;
        min-width: auto;
        height: auto;
        min-height: auto;
        padding-bottom: 36%;
        background-size: contain;
        border-radius: 0;
      }
      
      .deeplink-auth {
        display: none;
      }
      
      .deeplink-auth._visible {
        display: flex;
      }
      
      .deeplink-auth__body {
        position: relative;
        width: 100%;
        max-width: 336px;
        padding: 16px;
        border-radius: 12px;
        background-color: var(--colors-core-background-secondary-rgb);
        border: var(--border-size) solid var(--border-color);
        font-family: var(--main-font);
        color: var(--colors-core-text-primary);
      }
      
      @media (min-width: 768px) {
        .deeplink-auth__body {
          max-width: 460px;
          padding: 24px 30px;
        }
      }
      
      .deeplink-auth__image {
        margin-bottom: 20px;
        padding-bottom: 49%;
        border-radius: 12px;
        background-image: var(--deeplink-success-image-url);
        background-repeat: no-repeat;
        background-position: center;
        background-size: cover;
      }
      
      @media (min-width: 768px) {
        .deeplink-auth__image {
          padding-bottom: 37%;
        }
      }
      
      .deeplink-auth__title {
        margin-bottom: 10px;
        font-size: 20px;
        font-weight: 500;
        line-height: 24px;
        text-align: center;
        letter-spacing: 0.7px;
      }
      
      @media (min-width: 768px) {
        .deeplink-auth__title {
          margin-bottom: 20px;
          font-size: 24px;
          line-height: 30px;
        }
      }
      
      .deeplink-auth__description {
        margin-bottom: 20px;
        font-size: 13px;
        font-weight: 400;
        line-height: 18px;
        text-align: center;
        letter-spacing: 0.5px;
        color: rgba(255, 255, 255, 0.7);
      }
      
      .deeplink-auth__button {
        display: block;
        width: 100%;
        padding: 1.3rem;
        font-family: var(--main-font);
        font-size: 1.8rem;
        font-weight: 500;
        line-height: 2.5rem;
        letter-spacing: 0.5px;
        text-align: center;
        color: var(--button-text-color);
        background: var(--accent-color);
        border-radius: var(--border-radius-16);
        text-decoration: none;
        transition: transform .2s cubic-bezier(.509, .001, .25, 1);
      }
      
      @media (min-width: 768px) {
        .deeplink-auth__button {
          padding: 12px;
          font-size: 16px;
          line-height: 24px;
        }
      }
      
      .deeplink-auth__button:hover {
        transform: scale(.95);
      }
      
      この記事は役に立ちましたか?
      ありがとうございます!
      改善できることはありますか? メッセージ
      申し訳ありません
      この記事が参考にならなかった理由を説明してください。 メッセージ
      ご意見ありがとうございました!
      あなたのメッセージを確認し、体験を向上させるために利用させていただきます。
      このページを評価する
      このページを評価する
      改善できることはありますか?

      答えたくない

      ご意見ありがとうございました!
      最終更新日: 2024年4月10日

      誤字脱字などのテキストエラーを見つけましたか? テキストを選択し、Ctrl+Enterを押します。

      問題を報告する
      当社は常にコンテンツを見直しています。お客様のご意見は改善に役立ちます。
      フォローアップ用のメールをご提供してください
      ご意見ありがとうございました!