Signed URLs

Overview

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

This adds an additional layer of security for interactions between your Application and the our ecosystem.


 

1. Generate the URL Signing Secret

First you must generate the URL Signing Secret for your Application. Navigate to your Application in the Developer Portal and on the Basic Details page locate the URL Signing Secret section.

830

A URL Signing Secret can be added on the basic Details page in the Developer Portal

Upon clicking “Create”.

A pop-up will appear for confirmation.

1004

Confirming the generated of a URL Signing Secret

 

Once confirmed, the platform will generate the Signing Secret and display it to you in plain text.

835

Signing Secret

 

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.

 

2. Verifying a signed URL

Once you have generated a URL Signing Secret, any future redirects from the App Store to your Application 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:

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(urlToVerify)
    .digest('hex')

  // 4. Compare your generated signature with the signature parsed from the URL
  const isValidSignature = calculatedSignature === receivedSignature
  return isValidSignature
  }
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;
      }
    }
}