Multipass integration - token generation in Java

Highlighted
Shopify Partner
2 0 0

Hi,

I am having trouble using Multipass to do the SSO and customer creation for my project.
I suspect something is wrong with my token generation.

Would really appreciate the help.

I took the algorithm described here https://docs.shopify.com/api/uiintegrations/multipass and implemented it in Java.

However when I add the generated token to https://dynacare-2.myshopify.com/account/login/multipass/
and do the GET with the resulting URL I receive the "422 Unprocessable Entity" response back.

The algorithm for the token generation:

        // Get the encryption and signature keys
        MessageDigest digest = MessageDigest.getInstance("SHA-256");

       // multipassSecret is defined at this point, the value comes from our store admin
        byte[] hash = digest.digest(multipassSecret.getBytes("UTF-8"));
        byte[] encryptionKey = Arrays.copyOfRange(hash, 0, 16);
        byte[] signatureKey= Arrays.copyOfRange(hash, 16, 32);
        
        // Get random IV
        SecureRandom random = new SecureRandom();
        byte iv[] = new byte[16];
        random.nextBytes(iv);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        
        // Encrypt user data
        SecretKeySpec skeySpec = new SecretKeySpec(encryptionKey, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
        byte[] encrypted = cipher.doFinal("{  email: \"ashulinsky@mediresource.com\", created_at: \"2015-07-24T12:36:40-0400\" }".getBytes());
        
        // Sign encrypted user data
        Mac sha256HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(signatureKey, "HmacSHA256");
        sha256HMAC.init(secretKeySpec);
        byte[] signature = sha256HMAC.doFinal(encrypted);
        
        // Combine the encrypted data with its signature and base64-encode it
        token = Base64.encodeBase64URLSafeString(ArrayUtils.addAll(encrypted, signature));

 

Thanks in advance.

0 Likes
Highlighted
Shopify Partner
2 0 0

Hi,

I have also tried the Ruby sample from here https://docs.shopify.com/api/uiintegrations/multipass

Got the same the 422 - Invalid Multipass request response.

My Ruby code with the HTTPS call

require "openssl"
require "base64"
require "time"
require "json"
# require "net/http"
require "net/https"
require "uri"

class ShopifyMultipass
  def initialize(multipass_secret)
    ### Use the Multipass secret to derive two cryptographic keys,
    ### one for encryption, one for signing
    key_material = OpenSSL::Digest::Digest.new("sha256").digest(multipass_secret)
    @encryption_key = key_material[ 0,16]
    @signature_key  = key_material[16,16]
  end

  def generate_token(customer_data_hash)
    ### Store the current time in ISO8601 format.
    ### The token will only be valid for a small timeframe around this timestamp.
    # customer_data_hash["created_at"] = Time.now.iso8601

    ### Serialize the customer data to JSON and encrypt it
    ciphertext = encrypt(customer_data_hash.to_json)

    ### Create a signature (message authentication code) of the ciphertext
    ### and encode everything using URL-safe Base64 (RFC 4648)
    Base64.urlsafe_encode64(ciphertext + sign(ciphertext))
  end

  private

  def encrypt(plaintext)
    cipher = OpenSSL::Cipher::Cipher.new("aes-128-cbc")
    cipher.encrypt
    cipher.key = @encryption_key

    ### Use a random IV
    cipher.iv = iv = cipher.random_iv

    ### Use IV as first block of ciphertext
    iv + cipher.update(plaintext) + cipher.final
  end

  def sign(data)
    OpenSSL::HMAC.digest("sha256", @signature_key, data)
  end
end

customer_data = {
    email: "bob@shopify.com",
    remote_ip: "107.20.160.121"
}

token = ShopifyMultipass.new("the Multipass token from the store").generate_token(customer_data)

puts token

url = URI.parse("https://dynacare-2.myshopify.com/account/login/multipass/" + token)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
req = Net::HTTP::Get.new(url.to_s)
res = http.request(req)

puts res.body

And the result of this GET request

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>422 - Invalid Multipass request</title>
  <style type="text/css">

    * { border:0; margin:0; padding:0; -moz-box-sizing:border-box; -webkit-box-sizing:border-box; box-sizing:border-box; }
    html,body { height:100%; border:0; margin:0; padding:0; font-family:"Helvetica Neue", Helvetica, Arial, sans-serif; font-weight:300; background:#fff; }
    body { min-height:100%; font-size:16px; line-height:22px; color:#6c6c6c; }
    a { color:#479ccf; }

    h1,h2,h3,h4,h5,h6 { text-align:left; margin:0 0 20px 0; color:#31373D; font-weight:700; }
    h1 { font-size:28px; line-height:48px; margin-bottom:7px; }
    h2 { font-size:20px; font-weight:300; line-height:30px; color:#6c6c6c; }
    h3 { font-size:17px; line-height:30px; position:relative; padding-bottom:18px; margin-bottom:22px; font-weight:400; }
    h3:after { content:""; position:absolute; left:0; bottom:0; height:2px; width:76px; background:#EAEAEA; }
    h4 { font-size:14px; margin-bottom:3px; }

    img { max-width:100%; }

    li { margin-bottom:5px; }

    .ico { display:inline-block; }
    .ico svg { background-size:contain; background-position:center; width:24px; height:24px; margin-bottom:5px; }

    .wrapper { min-width:320px; max-width:650px; margin:0 auto; padding:20px; }

    .hero { margin-bottom:30px; }

    .content--block { position:relative; margin-bottom:50px; }
    .content--desc { margin-bottom:32px; position:relative; }
    .content--desc-large { font-size:20px; line-height:28px; }

    .request-id { padding-top:100px; font-size:13px; color:#ccc; }

    @media all and (min-width:500px) {
      body { padding:60px 0; }
      .wrapper { padding:20px 20px 20px 100px; }
      .ico svg { width:40px; height:40px; margin-bottom:0; }
      .hero { margin-bottom:70px; }
      .content--block { margin-bottom:80px; }
      .content--desc .ico { position:absolute; left:-70px; top:-7px; }
    }

    @media all and (min-width:900px) {
      .wrapper { padding:20px; }
    }

  </style>
</head>

<body class="status-error status-code-500">

  <div class="wrapper">
    <div class="hero">
      <svg width="160px" height="176px" viewBox="0 0 160 176" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch=";
        <title>shopify-bag-outline</title>
        <desc>Created with Sketch.</desc>
        <defs></defs>
        <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
          <g id="user-action-required-2" sketch:type="MSArtboardGroup" transform="translate(-297.000000, -81.000000)" stroke="#979797" stroke-dasharray="5">
            <g id="shopify-bag-outline" sketch:type="MSLayerGroup" transform="translate(298.000000, 82.000000)">
              <path d="M138.817711,32.9976853 C138.371951,32.7161619 137.887187,32.6604147 137.887187,32.6604147 L123.887534,31.6151547 L113.584904,21.3716063 C113.200436,21.0733588 112.749104,20.9005425 112.286628,20.8085596 L104.647414,174.188624 L158.389365,162.551396 L139.402771,34.070819 C139.402771,34.070819 139.257899,33.2847834 138.817711,32.9976853" id="Fill-1" sketch:type="MSShapeGroup"></path>
              <path d="M104.652986,20.8643068 L99.4292354,22.483763 C97.1196409,15.7244147 93.9714603,10.8994944 90.0264836,8.10655958 C87.070537,6.01325214 83.8137024,5.13244635 80.3144857,5.408395 C79.5984836,4.46347992 78.8323334,3.59939829 77.9742453,2.90534562 C74.1100625,-0.222072416 69.1286936,-0.707073074 63.1694384,1.45591837 C45.436545,7.89750757 37.8224056,30.7622225 35.033619,42.4328993 L19.170132,47.3470151 C19.170132,47.3470151 15.5009693,48.3894878 14.6400951,49.4235984 C13.6956409,50.558054 13.5117649,53.615788 13.5117649,53.615788 L0.300550361,155.58857 L99.4988854,174.183049 L107.138099,20.7778986 C106.043201,20.5632719 104.926014,20.8001975 104.652986,20.8643068 L104.652986,20.8643068 Z M87.081681,12.7586636 C90.1602116,14.9383792 92.375082,19.3061725 93.9491723,24.1812653 L85.6218167,26.7595734 C85.6134587,26.1630783 85.6106727,25.5693706 85.5855987,24.9533641 C85.3850067,19.5932706 84.6550745,15.0777472 83.4153043,11.4207307 C84.7470126,11.5628861 85.9756388,11.9754154 87.081681,12.7586636 L87.081681,12.7586636 Z M62.4868683,33.9286636 C64.7825327,25.0620711 69.1621256,16.0561106 77.4671932,12.5273127 C79.1972995,17.0205372 79.6987796,23.1471547 79.6653476,28.6048058 L62.4868683,33.9286636 L62.4868683,33.9286636 Z M65.2115768,7.08638578 C68.8083035,5.77911389 71.558086,5.87109677 73.6531584,7.23969059 C62.5453743,12.3544964 57.6503714,25.0955194 55.513509,36.0888677 L41.7952423,40.3395918 C44.9099909,29.1929388 51.7774822,11.964266 65.2115768,7.08638578 L65.2115768,7.08638578 Z M74.6366166,82.0524358 C73.8509645,81.6705675 72.9204403,81.2608255 71.8673321,80.8705951 C70.8225819,80.4831521 69.6608197,80.1124332 68.4015474,79.8058236 C67.1506332,79.499214 65.8077809,79.2511389 64.3897067,79.1034088 C62.9883484,78.9612535 61.5173401,78.9138683 59.9906118,79.0030639 C58.5892535,79.0866847 57.3188373,79.3347597 56.2016511,79.7333522 C55.0956089,80.1291573 54.1344387,80.6726926 53.3432145,81.3472337 C52.5547764,82.0217749 51.9307123,82.8245346 51.4905242,83.7499381 C51.0531221,84.669767 50.79681,85.7122396 50.746662,86.8634194 C50.710444,87.7163515 50.8413861,88.5358354 51.1422741,89.3330204 C51.4431622,90.1302054 51.9112103,90.9106662 52.5519904,91.6883397 C53.1927705,92.4688005 54.0062827,93.246474 54.9925269,94.0380843 C55.984343,94.8352693 57.1572493,95.6519658 58.5112455,96.4965359 C60.4057259,97.7090375 62.3419963,99.0804187 64.1863286,100.65249 C66.055735,102.24686 67.8248453,104.044707 69.3460016,106.093417 C70.8838739,108.167213 72.1626481,110.489084 73.0263083,113.095265 C73.8955405,115.718171 74.3357286,118.614238 74.1964285,121.805766 C73.9707625,127.023704 72.8285023,131.522503 70.9368079,135.254778 C69.0701876,138.936881 66.4931371,141.832948 63.3895325,143.929043 C60.3555779,145.98054 56.8396452,147.254363 53.0144665,147.76445 C49.3035138,148.263388 45.319533,148.040399 41.2157542,147.134507 C41.1823222,147.126145 41.1488902,147.117783 41.1182442,147.112208 C41.0848122,147.106633 41.0541662,147.098271 41.0207342,147.089909 C40.9873022,147.084334 40.9538702,147.075972 40.9232242,147.06761 C40.8897921,147.059248 40.8591461,147.053673 40.8257141,147.045311 C38.9005878,146.579822 37.0423254,145.972178 35.2955031,145.266976 C33.5765407,144.570136 31.9606604,143.778525 30.4924382,142.922806 C29.0409319,142.075448 27.7287256,141.169556 26.5920374,140.230216 C25.4664932,139.302025 24.510895,138.340386 23.7614609,137.378747 L28.2914977,122.340939 C29.0548619,122.987606 29.9909581,123.720682 31.0552103,124.467695 C32.1306065,125.225856 33.3397307,126.000743 34.6352209,126.725456 C35.9446412,127.455745 37.3432135,128.13586 38.7835757,128.687758 C40.240654,129.248017 41.7423083,129.677271 43.2300326,129.897472 C44.5422388,130.0898 45.7151451,130.050777 46.7431793,129.819426 C47.7767855,129.585288 48.6599476,129.156034 49.3843078,128.570689 C50.1086679,127.982556 50.674226,127.235543 51.0642661,126.379824 C51.4598782,125.521317 51.6827582,124.554103 51.7273342,123.519992 C51.7719102,122.483094 51.6771862,121.510305 51.4180882,120.562603 C51.1589901,119.614901 50.735518,118.700646 50.1225979,117.780818 C49.5124638,116.866564 48.7212396,115.949522 47.7210655,115.00182 C46.7320353,114.059692 45.542413,113.089691 44.1326968,112.061155 C42.4053764,110.770607 40.7783521,109.368565 39.3240598,107.846666 C37.8836976,106.341492 36.6104953,104.713673 35.5657451,102.9437 C34.5321389,101.193238 33.7186268,99.2978328 33.1920727,97.2435484 C32.6655186,95.1948387 32.4231365,92.9788874 32.5290045,90.5650336 C32.7045226,86.5289361 33.5124627,82.8078104 34.860887,79.4574036 C36.2232413,76.0735484 38.1567256,73.0353259 40.5805461,70.4207821 C43.0545146,67.7532785 46.0578231,65.5038789 49.5236078,63.7729282 C53.0869025,61.9918051 57.1656073,60.7430678 61.6789281,60.1493601 C63.7767865,59.8761988 65.7854929,59.7451929 67.6883313,59.7368308 C69.6162437,59.7284687 71.42993,59.8427505 73.1015303,60.0573772 C74.7926326,60.2720039 76.3332909,60.5869756 77.6984312,60.9716313 C79.0775015,61.3618618 80.2699097,61.8245635 81.2533679,62.3262883 L74.6366166,82.0524358 L74.6366166,82.0524358 Z" id="Fill-10" sketch:type="MSShapeGroup"></path>
          </g>
        </g>
      </g>
    </svg>
    </div>
    <div class="content">
      <div class="content--block">
        <div class="content--desc">
          <i class="ico ico-svg ico-40-svg">
            <svg viewBox="0 0 40 36" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch=";
              <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
                <g id="back-soon-3" sketch:type="MSArtboardGroup" transform="translate(-230.000000, -519.000000)">
                  <g id="what-went-wrong?" sketch:type="MSLayerGroup" transform="translate(231.000000, 444.000000)">
                    <g id="warning" transform="translate(0.000000, 77.000000)" sketch:type="MSShapeGroup">
                      <path d="M17.593,0.492 C18.217,-0.589 19.778,-0.589 20.402,0.492 L37.766,30.567 C38.39,31.648 37.61,33 36.361,33 L1.634,33 C0.386,33 -0.395,31.648 0.229,30.567 L17.593,0.492 L17.593,0.492 Z" id="Stroke-1" stroke="#E9BE33" stroke-width="2" stroke-linejoin="round"></path>
                      <path d="M20.75,28 C20.75,28.966 19.966,29.75 19,29.75 C18.033,29.75 17.25,28.966 17.25,28 C17.25,27.034 18.033,26.25 19,26.25 C19.966,26.25 20.75,27.034 20.75,28" id="Fill-2" fill="#E9BE33"></path>
                      <path d="M19,23 L19,8" id="Stroke-3" stroke="#E9BE33" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
                    </g>
                  </g>
                </g>
              </g>
            </svg>
          </i>
          <p class="content--desc-large">Oops, something went wrong.</p>
        </div>
      </div>
      <div class="content--block">
        <h3>What happened?</h3>
        <div class="content--desc">
          Invalid Multipass request: 
        </div>
      </div>
      <div class="content--block">
        <h3>What can I do?</h3>
        <div class="content--desc">
          <ul>
            <li>Press the back button on your browser.</li>
            <li> <a href="javascript:history.back()">Return to the previous page.</a></li>
          </ul>
        </div>
      </div>
    </div>
    <div class="request-id">Request ID: 72036722-1c55-4c16-b2b4-a545fb63ee57</div>
  </div>
</body>
</html>

 

0 Likes
Highlighted
New Member
1 0 0

Hi, We were able to get working in Java by byte[] iv as part of the encrypted value and also replace +/ with -_

 

Here was the final code:

        // Get the encryption and signature keys
        MessageDigest digest = MessageDigest.getInstance("SHA-256");

        // multipassSecret is defined at this point, the value comes from our store admin
        byte[] hash = digest.digest(multipassSecret.getBytes("UTF-8"));
        byte[] encryptionKey = Arrays.copyOfRange(hash, 0, 16);
        byte[] signatureKey= Arrays.copyOfRange(hash, 16, 32);
        
        // Get random IV
        SecureRandom random = new SecureRandom();
        byte iv[] = new byte[16];
        random.nextBytes(iv);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        
        // Encrypt user data
        SecretKeySpec skeySpec = new SecretKeySpec(encryptionKey, "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);

        String json = "{ \"email\": \"ashulinsky@mediresource.com\", \"created_at\": \"2015-07-24T12:36:40-0400\" }";
        byte[] encrypted = ArrayUtils.addAll(iv, cipher.doFinal(json.getBytes()));

        // Sign encrypted user data
        Mac sha256HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(signatureKey, "HmacSHA256");
        sha256HMAC.init(secretKeySpec);
        byte[] signature = sha256HMAC.doFinal(encrypted);
        
        // Combine the encrypted data with its signature and base64-encode it
        token = Base64.encodeBase64URLSafeString(ArrayUtils.addAll(encrypted, signature));

        token = token.replace('+', '-')  // Replace + with -
                     .replace('/', '_'); // Replace / with _

 

0 Likes