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 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. You may control the size, scrolling, and other properties of the iframe by using the iframe resizer API.
All apps must be served over TLS (a https:// url). This ensures the security of requests.
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:
This JSON object has several keys:
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}