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.
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}