Getting started in Sandbox

API Guides

Overview

When you build an application to be used on Narmi's platform, you're building a web app which will be served inside an <iframe></iframe> container from your own domain inside of digital banking. Since Narmi only serves apps to logged in users, this means that you are guaranteed to have a logged in user available for authentication.

All apps must be served over TLS (a https:// url). This ensures the security of requests.

Understanding App Launch

When your app is loaded on Narmi's platform, a HTTP POST request is made to your specified app URL. This POST request will contain some parameters in the body, including the signed_request parameter which you should decode for user information, and a signature to verify the security and authenticity of this data.

The signed_request is base64 encoded and signed with an SHA256 HMAC of your App Secret (sometimes this is called a JSON Web Token). You can parse this parameter like this:

  1. Split the signed request into three parts delineated by a '.' character (eg. 34k324nsfsfm.238fsdfsd.oijdoifjsidf899).
  2. Calculate the expected signature of the request, and compare it to the third part - the encoded signature.
  3. If the expected signature and signature match, decode the second part - the payload - from base64 and then decode the resultant JSON object.

This JSON object has several keys:

Name Type Description Example
exp number expiration, a Unix epoch timestamp 1291840400
iat number issued at, a Unix epoch timestamp 1516239022
aud string client id of the application “7ugpYTwyIoFkhz6bLnzQJGYUEaJGtcnrv8pfOJCb”
sub string subject, the Narmi user id “0b0b893f-9885-4789-b26d-6e879f0fc693”
user.institution_user_identifier string uniquely identifies the current user on the core “555555”
user.institution_business_identifier string uniquely identifies the current user's business on the core (if any). Is not the EIN “555556”
user.narmi_business_identifier string UUID, uniquely identifies the business to Narmi "823686a9-6412-4a3e-b1bc-79371702f7fb"

If exp is greater than the current time, then the request should be considered invalid.

These steps are possible in any modern programming languages. Here are some examples:

PHP:

function parse_signed_request($signed_request) {
 list($header, $payload, $encoded_sig) = explode('.', $signed_request, 3);
 $secret = "appsecret";

 // Use your app secret here
 $sig = base64_url_decode($encoded_sig);

 // confirm the signature  $expected_sig = hash_hmac('sha256', $header.".".$payload, $secret, $raw = true);
 if ($sig !== $expected_sig) {
   error_log('Bad Signed JSON signature!');
   return null;
 }

 // decode the data  $data = json_decode(base64_url_decode($payload), true);
 return $data;
}

function base64_url_decode($input) {
 return base64_decode(strtr($input, '-_', '+/'))
;}

Then to use it:

parse_signed_request($_REQUEST['signed_request'])

For example:

parse_signed_request("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyOTE4NDA0MDAsInN1YiI6IjBiMGI4OTNmLTk4ODUtNDc4OS1iMjZkLTZlODc5ZjBmYzY5MyIsInVzZXIiOnsiaW5zdGl0dXRpb25fdXNlcl9pZGVudGlmaWVyIjoiOTk2MjcifSwiaWF0IjoxNTE2MjM5MDIyfQ.SUxrDJW6Q7Uylefh6aEbodxRpeeJ8bHTIT1Hs-RrYMQ")

Will produce a JSON payload of:

{
 "exp": 1291840400,
 "sub": "0b0b893f-9885-4789-b26d-6e879f0fc693",
 "user": {
   "institution_user_identifier": "99627"
 },
 "iat": 1516239022
}

ASP.NET

This example uses the .NET class HMACSHA256.

static string ParseSignedRequest(string signedRequest){
   string[] split = signedRequest.Split('.');
   string header = split[0];
   string data = split[1];
   string dataRaw = FixBase64String(data);
   string signatureRaw = FixBase64String(split[2]);

   // the decoded signature
   byte[] signature = Convert.FromBase64String(signatureRaw);
   byte[] dataBuffer = Convert.FromBase64String(dataRaw);

   // JSON object    string dataJson = Encoding.UTF8.GetString(dataBuffer);
   byte[] appSecretBytes = Encoding.UTF8.GetBytes("appsecret"); // Use your app secret here
   HMAC hmac = new HMACSHA256(appSecretBytes);
   byte[] expectedHash = hmac.ComputeHash(Encoding.UTF8.GetBytes(header + "." + data));
   bool areEqual = expectedHash.SequenceEqual(signature);

   if (areEqual) {
       return dataJson;
   } else {
       return "";
   }
}

static string FixBase64String(string str){
   string result = str;
   while (result.Length % 4 != 0)
   {
       result = result.PadRight(result.Length + 1, '=');
   }
   result = result.Replace("-", "+").Replace("_", "/");
   return result;
}

For example:

using System;
using System.Text;
using System.Linq;
using System.Security.Cryptography;

public class Program{
 public static void Main()
 {    Console.WriteLine(ParseSignedRequest("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyOTE4NDA0MDAsInN1YiI6IjBiMGI4OTNmLTk4ODUtNDc4OS1iMjZkLTZlODc5ZjBmYzY5MyIsInVzZXIiOnsiaW5zdGl0dXRpb25fdXNlcl9pZGVudGlmaWVyIjoiOTk2MjcifSwiaWF0IjoxNTE2MjM5MDIyfQ.SUxrDJW6Q7Uylefh6aEbodxRpeeJ8bHTIT1Hs-RrYMQ"));
 }
 //...
}

Will produce a string that can be JSON parsed:

{"exp": 1291840400,"sub": "0b0b893f-9885-4789-b26d-6e879f0fc693","user": {"institution_user_identifier": "99627"},"iat": 1516239022}

Narmi Inc.
P.O. Box 231517
New York, NY 10023