Overview

Guide on integrating with the DeSo Identity iframe API

The iframe allows you to perform actions such as signing transactions or encrypting/decrypting messages without user interaction, as is the case in the Identity: Window API.

The iframe is usually entirely invisible to the user.

However, the iframe does need to render on some browsers such as Safari as the user needs to click on the iframe to grant it storage access.

We will explain how to implement this later in the guide.

In order to communicate with the iframe API, you need to include the iframe window HTML component into your app and point it to the https://identity.deso.org/embed URL.

Below is an example component.

We also provided you with an example with CSS styling.

<iframe
  id="identity"
  frameborder="0"
  src="https://identity.deso.org/embed"
  style="height: 100vh; width: 100vw; display: none; position: fixed; 
    z-index: 1000; left: 0; top: 0;"
></iframe>

Take notice of the CSS styling of the iframe component. As mentioned, the iframe is typically invisible to the user. That's why we set the display: none in the CSS style.

We also want the iframe window to be on top of your application and take the entire display, hence the other CSS attributes.

You should modify the z-index attribute to fit your application. In case that we will have to show the iframe to the user, you will set the attribute display: block

For example, document.getElementById("identity.style.display = "block");

Messages

Communication with the iframe context is done through sending postMessage() requests. Similarly, the iframe context will send you responses by sending message events.

When you open the iframe context for the first time, the Identity will send you an initialize message, which requires you to respond.

When sending requests to the Identity iframe, you will need to include an id field. The id should be in UUID v4 format.

We recommend using the uuid npm package, or you can also use the following implementation in Vanilla JavaScript:

function uuid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

Here's an example message format that you can send to the Identity iframe.

{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  method: 'info',
}

Let's take a look at what each of these fields mean:

  • id should be generated to follow the UUID v4 format.

  • service this should always be set to "identity" so that the DeSo Identity Service knows it's supposed to read this message.

  • method this is the API type that you'll request, in this case it's "info" but it could be"sign", "encrypt", etc. as outlined in the #api section

You should index requests by id so that you can match them with responses.

We recommend looking at the DeSo Protocol sourcecode to see how this could be implemented.

In particular, you could trace through the send() method on line #257 in src/app/identity.service.ts.

Storage Access

Besides initialize, you will need to send an info message to the iframe context.

The DeSo Identity uses local storage and cookies to share information about users between the window and iframe contexts.

However, some browsers such as Safari and Chrome on iOS prevent storing data in such a way without user's explicit permission.

For example, Apple's Intelligent Tracking Prevention (ITP) places strict limitations on cross-domain data storage and access.

This means the Identity iframe must request storage access every time the page reloads.

This can be accomplished by showing the iframe to the user, i.e. setting display: "block", and having the user click on the iframe.

When a user visits a DeSo application in Safari they will see a "Tap anywhere to unlock your wallet" prompt which is a giant button in the iframe. When the user clicks on the button, he will give Identity the required access.

Here's how it looks for the user:

To simplify this process, there's a special API call that you should perform, called info, that will indicate if you should display the iframe window to the user.

The best practice is to send the info message just when you're about to send the first non-initialize request (sign, encrypt, etc.) to the iframe API.

We recommend tracing through the identity/iframe-info-storage-access code snippet in the examples repository, which implements this communication pattern in Vanilla JavaScript using promises.

If you're familiar with RxJS, you can also trace through the Deso Protocol code, starting with the storageGranted variable on line #32. Here's how the info request looks like:

Request

{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  method: 'info',
}

And here's the response that the iframe will send you:

Response

{
  id: '21e02080-0ef4-4056-a319-a66403f33768',
  service: 'identity',
  payload: {
    browserSupported: true,
    hasCookieAccess: true,
    ​​hasLocalStorageAccess: true,
    ​​hasStorageAccess: true
  },
}

Let's take a look at the above payload fields:

  • browserSupported tells you if DeSo Identity Service is compatible with the user's browser. If it's set to false you should notify the user that Identity won't work for them. Most modern browsers will output true.

  • hasCookieAccess indicates if user browser allows cookies. Identity might store some information in cookies if local storage is unavailable.

  • hasLocalStorageAccess will be true if local storage is available on user's browser.

  • hasStorageAccess indicates if browser has access to storage. If it's set to false you will need to show the iframe window to the user so he can grant access. We will get to this next.

If the info message returns hasStorageAccess: false, your application should make the iframe take over the entire page.

You could do that by setting:

document.getElementById("identity").style.display = "block"

The info message also detects if a user has disabled third party cookies.

Third party cookies are required for Identity to securely sign transactions.

If neither localStorage nor cookies are available, the info returns browserSupported: false and your application should inform the user they will not be able to use Identity to sign or decrypt anything.

When a user clicks "Tap anywhere to unlock your wallet," the iframe will indicate it by sending a storageGranted message.

This request does not expect a response. When your application receives the storageGranted message it can hide the iframe window from the user and the iframe is now ready to receive sign and decrypt, etc. messages.

To hide the iframe, simply call:

document.getElementById("identity").style.display = "none"

storageGranted Message

{
  service: 'identity',
  method: 'storageGranted',
}

User Credentials

The user credentials include three fields, namely encryptedSeedHex, accessLevel, andaccessLevelHmac.

Last updated