Sign text with BankID, NemID, right in your front-end

Niels Flensted-Jensen, Mar 24, 2017

All of the national identity services integrated by easyID in addition to providing 2-factor authentication, also provide signing services. This post shows how you may leverage that immediately in your front-end code with just an iframe and a few lines of Javascript.

If you just need to see the code and run it, simply get the finished example from GitHub.

The following highlights the areas where you will add code to your app to introduce signing.

1. Simple application ready for signing

So you are certainly not a style wizard, you prefer to keep things simple - just like me. That’s why you would put together a site like this one:

Simple, stylish web site ready for signing logic

As is probably evident, you simply enter some text, choose how you want to sign - and then the signing should happen when you click the button. In the following we will add the signing capability to this web page.

Before we move on let’s briefly inspect the nature of a few key pieces of the above web page:

<div>
    <textarea id="signtext" placeholder="Enter the text you want to sign" cols="80" rows="8" onchange="enableButton()" onkeyup="enableButton()"></textarea>
</div>
<select id="signmethod">
    <option value="urn:grn:authn:dk:nemid:poces">DK NemID personal</option>
    <option value="urn:grn:authn:dk:nemid:moces">DK NemID employee code card</option>
    <option value="urn:grn:authn:dk:nemid:moces:codefile">DK NemID employee code file</option>
    <option value="urn:grn:authn:no:bankid:central">NO BankID hardware token</option>
    <option value="urn:grn:authn:no:bankid:mobile">NO BankID mobile</option>
    <option value="urn:grn:authn:se:bankid:same-device">SE BankID same device</option>
    <option value="urn:grn:authn:se:bankid:another-device">SE BankID another device</option>
</select>
<button id="signbutton" onclick="signNow()" disabled>Sign the text</button>

<!-- This is where we will embed the easyID signing -->
<iframe id="signhere" style="display:block" width="600px" height="500px" frameborder="0"></iframe>

Basically we have four elements: The signtext textarea, the signmethod dropdown selector, the actual signing button, signbutton, and finally the signhere iframe which eventually will host the easyID signing logic.

We’ve added a few event handlers to the textarea simply to avoid having to check for missing text. Not so interesting, it just enables and disables the button.

2. Hooking in the signing logic

More interesting is what happens when the user clicks the button and the signNow() function is called. But first a few script tags:

<head>
    <!-- ... -->
    <!-- Use this if you want to peek inside the JWT
         containing the counter signed native signature -->
    <script src="https://grean.com/scripts/jwt-decode.js"></script>
    <!-- Simple easyID utility -->
    <script src="https://grean.com/scripts/easyid.js"></script>
    <!-- ... -->
</head>

And then a few lines of initialization code:

 <script>
    var domain = "<YOUR EASYID DOMAIN>"; // E.g. "mytenant.grean.id"
    var clientID = "<YOUR CLIENT ID>"; //  E.g. "urn:easyid:mycompany:app7"
    var easyID = new EasyID(domain, clientID);
</script>

The domain and the client id is picked from your easyID tenant. See below for more on how this is set up.

With that we’re ready to add the signing logic to the same page:

function signNow() {
    var selected = document.getElementById("signmethod");  // pick out the signing method
    const options = {
      signMethod: selected.options[selected.selectedIndex].value,
      iframeID: "signhere"
    };
    // Supply a callback function to have the result delivered right here in front end ...
    easyID.sign(document.getElementById("signtext").value, options, function (err, response) {
        if (!err) {
          // This is where you process the signature result
          doSomethingWithSignature(response);  
        }
    });
    }
}

The response is a JSON Web Token, JWT, signed by your easyID tenant. The JWT contains both the native signature from the national or bank identity service as well as the text that was signed.

How is this safe?

The JWT returned by easyID contains the native signature and the original text the user was asked to sign. The entire JWT is signed by the token signing key specific to your easyID tenant.

For the security minded it is worth noting that this easyID signing key - used to generate the JWT signature - is backed by a hardware security module, HSM. This means your private key will never be exposed. This is in essence how easyID is able to guarantee the integrity of your signatures.

This makes the signature safe to trust from a crypto point of view. Still, it will be up to you to verify that the text signed by the user is in fact the same as the text you intended for the user to sign.

Since the communication between your web application and easyID goes through the browser, the tech savvy user may in fact change data in transit, thus actually signing a different text than what you asked for.

In summary, to be safe you must do two things:

  1. Verify the JWT signature. How to do that is the subject for a separate post, but it involves retrieving the signing keys from the OpendID Connect configuration endpoint. This other signing demo (in C#) at https://github.com/GreanTech/easyid-signing-demo shows how this may be done. Specifically you want to take a look at the easyIDSignature.cs file.
  2. Verify in your backend, that the signed text corresponds to the text you asked to be signed

Running the code

As mentioned in the beginning you may download a working sample from GitHub. In that sample the handling of the signature response is as simple as displaying the native signature along with the entire easyID issued JWT.

function doSomethingWithSignature(response) {
    var token = jwt_decode(response);
    var signedText = token.signtext;

    document.getElementById("signhere").style.display = "none";
    document.getElementById("tokendisplay").style.display = "block";
    document.getElementById("evidence").value = window.atob(token.evidence);
    document.getElementById("jwt").value = response;
}

This code basically hides the signing iframe and shows a div tag with a couple of textareas to display the response and the native signature.

That’s it!

If you just want to try your hand at signing stuff not coding, just go to this other live demo. Also this time made by an engineer with limited design beautification interest :) And to dive deeper you may want to check the corresponding source code.

3. Setting up your easyID account

As no shared standard for text signing exists, different, proprietary, protocols are used by the various national and bank identity services, we use Grean easyID as the identity service in the middle.

So, if you haven’t done so already, sign up for easyID: grean.com/easyid

A note on test users

In order to test the use of Norwegian BankID, Swedish BankID, and Danish NemID you need test identities.

As an example consider obtaining a test identity for Swedish BankID by going to https://demo.bankid.com. (Note that to install a test identity on your phone you will have to follow the guidelines on the site).

Also, feel free to get in touch if you need help getting your own test identities, and we will help you set them up. Just go to grean.com/easyid and sign up. Once signed up you can join our Slack channel from the easyID dashboard.

Setting up your easyID account

Name your first domain which will be a subdomain of grean.id. This will be the domain name we will use in the following.

Sign up

Once signed up, go to the Applications tab to register your application. At the time of writing the UI is focused on authentication, but you still need to register an application to make the signing process run.

For this exercise we create a new application using the manual option.

Create application

Remember to copy the Client ID value - you will need it when configuring your EasyID object as shown in th above front end code. For the Callback URLs just enter the root URL where your application resides. In this Node.JS example that would be http://localhost:3000/

With this you will be able to set up your application as shown above for signing using any of the enabled identity services: Danish NemID, Swedish BankID and/or Norwegian BankID.


Go to criipto.com to sign up today to quickly enable your applications to accept real people’s real identities. We run a tight ship to ensure that you get the same level of security and safety that you get from the various proprietary bank and government solutions!