URL signing is a technique that can be used by Apps to verify the authenticity of HTTP requests originating from Tapico, using information contained in the URL itself.

This adds an additional layer of security for interactions between your App and the Tapico ecosystem.


Step 1 - Generate the URL Signing Secret


First you must generate the URL Signing Secret for your App. Navigate to your App on the Tapico platform:


Scroll down to the heading named “URL Signing Secret”.

Click on “Create”. 


A pop-up will appear for confirmation. Once confirmed, the Tapico platform will generate the Signing Secret and display it to you in plain text.


This is the only time the secret will appear in plain text, you must copy it and store it somewhere safe. The generated secret is unrecoverable. If the secret is lost, you’ll have to generate a new one using this process.


Step 2 - Verifying a signed URL 


Once you have generated a URL Signing Secret, any future redirects from the App Store to your App will include an additional query string parameter named signature.

https://your.app.com

?accountServicerId=0f1011ea-6701-4a7c-ab92-bdc01600dfc8

&timestamp=1630687797463

&signature=9466417f6b0a4fbe82bd0d701c62ea80fb353693976f3ef3bd01f95571221f1f

This parameter contains a signature which is generated by signing the original URL with the URL Signing Secret generated in Step 1.


The following steps are required to verify the signature:

  1. Parse the signature query string parameter from the URL.

  2. Remove the signature query string parameter from the URL so you’re just left with the original URL.

  3. Compute the HMAC SHA256 hash of the original URL, using the Signing Secret generated in Step 1. We’ve provided code snippets below outlining how to do this.

  4. Compare your generated hash with the signature parsed from the URL. If it matches then the signature is valid.

Here’s a couple example code snippets outlining how to verify the signature:

Node.js

import crypto from 'crypto'

/**
 * Validate the signature of the given url
 * @param url the signed url to validate
 * @param signingSecret your Application's signing secret
 * @returns
 */
function validateSignedContext(url: string, signingSecret: string) {
  if (!url) {
    throw new Error('Missing url')
  }

  if (!signingSecret) {
    throw new Error('Missing signingSecret')
  }

  const parsedURL = new URL(url)

  // 1. Parse the signature query string parameter from the URL
  const receivedSignature = parsedURL.searchParams.get('signature')

  // 2. Remove the signature parameter from the URL
  parsedURL.searchParams.delete('signature')

  const urlToVerify = parsedURL.toString()

  // 3. Compute the HMAC SHA256 hash of the original URL, using the signing secret from your Application
  const calculatedSignature = crypto
    .createHmac('sha256', signingSecret)
    .update(Buffer.from(urlToVerify, 'utf-8'))
    .digest('hex')

  // 4. Compare your generated signature with the signature parsed from the URL
  const isValidSignature = calculatedSignature === receivedSignature
  return isValidSignature
}

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Collections.Specialized;
using System.Security.Cryptography;

namespace VerifySignatureExample
{
    public class SignatureVerifier
    {       

      /**
      * Validate the signature of the given url
      * @param url the signed url to validate
      * @param signingSecret your Application's signing secret
      * @returns
      */
      public static bool validateSignedContext(string url, string signingSecret) {
        if (string.IsNullOrEmpty(url)){
          throw new Exception("Missing url");
        }

        if (string.IsNullOrEmpty(url)){
          throw new Exception("Missing signingSecret");
        }

        var parsedURL = new UriBuilder(url);
        NameValueCollection query = HttpUtility.ParseQueryString(parsedURL.Query);

        // 1. Parse the signature query string parameter from the URL
        var receivedSignature = query.Get("signature");

        // 2. Remove the signature parameter from the URL
        query.Remove("signature");          
        parsedURL.Query = query.ToString();          
        
        var urlToVerify = parsedURL.ToString();
        
        // 3. Compute the HMAC SHA256 hash of the original URL, using the signing secret from your Application
        System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
        byte[] secretAsBytes = encoding.GetBytes(secret);
        
        HMACSHA256 hmacsha256 = new HMACSHA256(secretAsBytes);
        
        byte[] urlToVerifyBytes = encoding.GetBytes(urlToVerify);
        byte[] computedHash = hmacsha256.ComputeHash(urlToVerifyBytes);

        // BitConverter is used to convert the byte array into a hexadecimal string. 
        // We need to strip out any - characters and make sure it's all lower case
        var calculatedSignature = BitConverter.ToString(computedHash).Replace("-", "").ToLower();          

        // 4. Compare your generated signature with the signature parsed from the URL
        var isValidSignature = calculatedSignature == receivedSignature;
        return isValidSignature;
      }
    }
}