Skip to content

Technical

Components in the Add-on

Lime eSign uses the following different components in Lime CRM:

  • Web components
  • Static pages to host signing portal
  • Custom endpoints
  • Lime Newsletter for email templates
  • TRAML
  • Lime Gävle's BankID service
  • Task Handler
  • Data structure
  • Security policies
  • Lime Bootstrap apps
  • Actionpads
  • Runtime configuration in Lime Admin
  • Application configuration

Internal Integrity Checks

There are two main internal checks that is made to make sure the integrity of the data during the signing process, access token and document fingerprint.

Access Token

An access token is a sequence of numbers and letters and it contains credentials that identifies a user. Lime eSign is using python's secret library to generate a URL-safe text string that contains 32 random bytes to make sure that the user has correct access rights to transfer data between two parties.

When a signing is created with Lime eSign, an access token is created for each signer. This means that each signer on each signing has a unique access token. The access token is stored in a separate property on the signer object in Lime CRM.

A token is sent to the server everytime someone is doing one request to the server from the portal (for example when someone enters the portal). The server then validates if the token exists on a single signer in the database. If so the case, the request to the server will go through and the performed actions will be tied to that signer.

If the token doesn't exist on any signer or if it exists on several signers, an InvalidToken error will be raised and the request will return an HTTP 400 Bad Request error.

Document Fingerprint

A fingerprint is a sequence of numbers and letters and it is used to detect errors in the original data source. In Lime eSign, an industry standard 256 bit secure SHA256 hashing algorithm is used to generate fingerprints.

When a signing is created with Lime eSign, all documents that should be signed will be merged to a new PDF document called original document. The original document is stored as a file property on the signing object in Lime CRM. A fingerprint will be calculated based on this original document. This fingerprint will be stored in a separate property on the signing object in Lime CRM. This fingerprint is called Original Document Fingerprint and is used to check that the original document is not modified during the signing process.

Whenever a signer is requesting to view the original document (for example when the signer is entering the portal), a new fingerprint is calculated based on the original document that is currently stored on the signing object. This newly calculated fingerprint is then compared with the Original Document Fingerprint that is stored on the signing object. If the fingerprints match, the signer will get access to the original document.

If the fingerprints does not match, then either the Original Document Fingerprint or the original document stored on the signing has been modified and a TamperedFile error will be raised and the signer won't get access to the original document.

What happens if someone with bad intentions changes the original document on the signing object and also replace the Original Document Fingerprint on the signing object, so it matches with the new original document?

This is a case that is possible and it emphasizes the importance of installing Lime eSign according to the instructions! Lime eSign is tied with the same security level as Lime CRM.

Verifying a Signed Document

Method of Verification

Documents signed with Lime eSign use an industry standard 256 bit secure SHA256 hashing algorithm to generate a digital fingerprint. Together with unique data collected from the signer, such as precise time, IP address and platform used, a digital signature is created.

When a document has been signed by all parties, an email is sent to the signer(s), containing the signed document together with the unique fingerprint ID of this document. The ID is made up of 32 letters and numbers, also known as a hash. Using standard tools, provided with most operating systems, the ID can be calculated for the signed document file and matched against the ID provided in the e-mail.

Example ID:

b0b4fcae7531a0509fc1f29e814ea59487c38787df671e6bc04b17ee355b24f3

If the ID calculated for the signed document file matches the ID provided in the e-mail, and the e-mail is sent from a trusted source, there is strong evidence for the document being valid.

Using Microsoft Windows

Open the Command Prompt (cmd.exe) and change the directory to where the document file is located. To calculate the ID for the document, run:

>certutil -hashfile document.pdf SHA256

where document.pdf is the name of the document file. If successful, the result should look similar to:

SHA256 hash of document.pdf b0b4fcae7531a0509fc1f29e814ea59487c38787df671e6bc04b17ee355b24f3 CertUtil: -hashfile command completed successfully.

(the ID has been emphasised in red)

Using Linux or macOS

Open a terminal session and change the directory to where the document file is located. To calculate the ID for the document, run:

>shasum -a 256 document.pdf

where document.pdf is the name of the document file. If successful, the result should look similar to:

b0b4fcae7531a0509fc1f29e814ea59487c38787df671e6bc04b17ee355b24f3

BankID Signing

Lime Technologies Gävle AB is storing all information connected to a BankID signature made with Lime eSign. The url to the digital quittance of the BankID signing is included on the verification page in the signed pdf.

Lime eSign is connecting each BankID signature with the original document's fingerprint. This information is accessible via the user_non_visible_data field at Lime Technologies Gävle AB and can be used to match the original document's fingerprint in the verification pages.

Note

The user_non_visible_data field does not exist if you use Lime Signatures service (Criipto) as signing service.

The user_non_visible_data value in Lime Technologies Gävle AB is base64 encoded. To retrieve the original document's fingerprint do as follows:

Using Microsoft Windows

Put the user_non_visible_data string from Lime Technologies Gävle AB in a txt file, input.txt for example.

Open the Command Prompt (cmd.exe) and change the directory to where the input.txt file is located. To decode the file, run:

>certutil -decode input.txt output.txt

where input.txt is the name of the file where the user_non_visible_data from Lime Technologies Gävle AB is stored. output.txt is the name of the file where the result will end up. If successful, the content of output.txt should look similar to:

{"file": number, "file_name": string, "original_document_fingerprint": string}

Using Linux or macOS

Open a terminal session and run:

>echo <user_non_visible_data> | base64 --decode

where <user_non_visible_data> is the string retrieved from Lime Technologies Gävle AB. The result should look something like this:

{"file": number, "file_name": string, "original_document_fingerprint": string}

Table and Field Definitions Lime CRM

These tables and fields must be created before you can use Lime eSign.

Table database name: signing

Field Field type Note
title Text (1024)
metadata Text (4000)
originaldocumentfingerprint Text (300)
signeddocumentfingerprint Text (300)
signingstatus Option Options: empty, created, sent, opened, partlysigned, signed, canceled, error
order Integer Default value = 1
methods Set Options: empty, bankid_se, bankid_no, mitid_da, ftn_fi,checkbox, signature
originaldocument File
sentdate Date & Time
signeddate Date & Time
coworker Relation
signeddocument Relation
document Relation
signer Relation
history Relation
additional limetype Relation Can be configured during the installation.

Table database name: signer

Field Field type Note
name Text (83)
email Text (100)
token Text (64)
methoddata Text (2048)
role Option Options: empty, signer, viewer, approver
signerstatus Option Options: created, sent, notified, opened, signed, approved, canceled, error
method Option Options: empty, bankid_se, bankid_no, mitid_da, ftn_fi, checkbox, signature
order Integer Default value = 1
sentdate Date & Time
notifieddate Date & Time
lastopeneddate Date & Time
approveddate Date & Time
signeddate Date & Time
signing Relation
history Relation
signer parent Relation Can be configured during the installation.

Signing Portal

Browser support

The signing portal is supporting the same browsers as lime-elements since it is built based on these components. Click here to see which browsers that are supported. It is impossible to access the signing portal with a browser that is not supported.

Signing Verification Pages

Lime eSign will generate verification pages when the signing is completed. These pages are attached to the original document and will together make up the signed document. Below are tables that explains the content of the verification pages.

Document information

Parameter Description
Name The descriptive name for current document that has been signed.
Sent by Person who has sent the document for signing.
Sent date UTC formatted timestamp when the document was sent for signing.
Signed by all parties UTC formatted timestamp when the document was signed by all parties.
Signing/transaction ID The ID of the signing object in the application.
Original document file ID The ID of the actual file.
Original document fingerprint The unique fingerprint for the document that has been sent for signing. This fingerprint is taken without the verification pages!

Signer information

Parameter Available for signing method Description
Name All The name of the signer.
E-mail All The e-mail to the signer.
Signed date All UTC formatted timestamp when the signer signed the document.
Signing method All Which signing method the signer used.
IP address All For Swedish BankID: The IP address is fetched from the signing service which means that the IP address is from the device that the signer signed with. For other signing methods: The IP address is fetched from the device that was used to finalize the signing in the signing portal. Several IP addresses could occur, when the signing request goes through several proxies.
Browser All The browser that was used to view the document when the signer signed.
Platform All The platform that was used to view the document when the signer signed.
Personal identification All electronic signatures The personal identification of the signer
Transaction id All electronic signatures Lime Gävle's BankID service's unique transaction ID that is connected to the official BankID signature.
Receipt url All electronic signatures URL that displays the recipe of Lime Gävle's BankID service's transaction.

Internal Endpoints

The following endpoints are used by the Lime clients and use regular sessions as authentication.

Initialize Signing

GET

/signing/init/

Get all relevant information to initialize a signing from document ids. It's used by the create signing dialog in the client apps. The response could be used as the base of a new signing and sent to the POST signing endpoint to create the signing.

Payload:

{
  "documents": [1003]
}

Response:

{
  "signers": [
    {
      "limetype": "coworker",
      "id": 1002,
      "name": "Carlito Jakobsson",
      "email": "[email protected]",
      "default": false,
      "limetypeLocalname": "Medarbetare"
    },
    {
      "limetype": "person",
      "id": 1039,
      "name": "Mari Ahna",
      "email": "[email protected]",
      "default": false,
      "limetypeLocalname": "Person"
    },
    {
      "limetype": "person",
      "id": 1051,
      "name": "Peter Johansson",
      "email": "[email protected]",
      "default": false,
      "limetypeLocalname": "Person"
    }
  ],
  "methods": [
    {
      "text": "Swedish BankID",
      "value": "bankid_se",
      "default": true
    },
    {
      "text": "Checkbox",
      "value": "checkbox",
      "default": false
    }
  ],
  "title": "JAS 39",
  "languages": ["da", "de", "en_us", "fi", "nl", "no", "sv"],
  "message": "Carlito Jakobsson wants you to sign JAS 39.",
  "documents": [
    {
      "limetype": "document",
      "id": 2044,
      "type": {
        "value": "agreement",
        "text": "Agreement"
      },
      "name": "JAS 39",
      "file": {
        "filename": "JAS.pdf",
        "extension": "pdf",
        "id": 48164,
        "size": 1149314,
        "mimetype": "application/pdf"
      },
      "url": "https://lime_server/app_name/api/v1/file/48164/contents/"
    }
  ]
}

Signing

GET

/signing/<int:signing_id>/

Fetch a specific signing.

Response:

{
  "coworker": {
    "limetype": "coworker",
    "id": 1002,
    "name": "Nisse Jensen",
    "email": "[email protected]",
    "phone": "046-123456",
  },
  "originalDocument": {
    "extension": "pdf",
    "filename": "JAS 39 (bundle).pdf",
    "id": 49275,
    "mimetype": "application/pdf",
    "size": 1149314,
    "url": "https://lime_server/app_name/api/v1/file/49275/contents/"
  },
  "signingService": "criipto",
  "methods": [{ "text": "Checkbox", "value": "checkbox" }],
  "signedDocument": {
    "file": {
      "extension": "pdf",
      "filename": "JAS 39 (signed).pdf",
      "id": 49276,
      "mimetype": "application/pdf",
      "size": 1402673,
      "url": "https://lime_server/app_name/api/v1/file/49276/contents/"
    },
    "id": 3071,
    "limetype": "document",
    "name": "JAS 39 (signed)",
    "type": { "text": "Signed agreement", "value": "signedagreement" }
  },
  "signers": [
    {
      "email": "[email protected]",
      "name": "Camilla Bangsgaard",
      "order": 1,
      "role": {
        "value": "viewer",
        "text": "Viewer"
      },
      "duty": null
    },
    {
      "name": "Peter Johansson",
      "email": "[email protected]",
      "order": 2,
      "role": {
        "value": "viewer",
        "text": "Viewer"
      },
      "duty": null
    }
  ],
  "id": 1007,
  "status": { "text": "Signed", "value": "signed" },
  "title": "JAS 39",
  "portalUrl": "https://lime_server/app_name/limepkg-esign/portal/?app=app_name&token=adshg8j233ej" // Personal portal URL for the logged in coworker if he/she is one of the signers
}

POST

/signing/

Creates a signing, preferably to be based on a response from the Init endpoint. Example payload:

{
  "signers": [
    {
      "limetype": "person",
      "id": 1004,
      "email": "[email protected]",
      "name": "Camilla Bangsgaard",
      "order": 1,
      "role": "signer",
      "duty": "sign"
    },
    {
      "limetype": "person",
      "id": 1051,
      "name": "Peter Johansson",
      "email": "[email protected]",
      "order": 2,
      "role": "viewer",
      "duty": null
    },
    {
      "limetype": "coworker",
      "id": 1010,
      "name": "Nisse Jensen",
      "email": "[email protected]",
      "order": 1,
      "role": "approver",
      "duty": "approve"
    }
  ],
  "documents": [1006],
  "meta": {
    "subject": "Document to sign",
    "message": "Greetings friend, please sign this document or else...",
    "language": "en_us"
  },
  "title": "Protection agreement",
  "methods": ["bankid_se", "checkbox"]
}

Returns the signing in the same format as the GET method.

DELETE

/signing/<int:signing_id>/

Cancels a signing. Returns the signing in the same format as the GET method.

Status

GET

/status/<string:limetype>/<int:limeobject_id>/

Fetches the status and the context of the limeobject. If there's one or more signings connected to the limeobject, a list of signings will be returned. This endpoint is used to quickly see if a limeobject is/has a signing or if it's qualified to create a signing from.

Context can be one of the following:

  • signing - the limetype in the URL is configured as the Signing limetype
  • document - the limetype in the URL is configured as the Document limetype
  • relation - the limetype in the URL configured as a Additional limetype
  • not_configured - the limetype in the URL is not configured to be used with eSign in any context

If there's possibility to create a signing, a list of potential documents will be returned with the following rules depending on context:

  • document returns a list of potential documents
  • relation returns a list of potential documents only if the optional argument force_docs=1 is supplied (this is due to performance reasons)
  • in all other cases the potential documents list will be empty

Example on an existing signing:

/status/signing/1006/
{
  "context": "signing",
  "potentialDocuments": [],
  "signings": [
    {
      "id": 1006,
      "limetype": "signing",
      "status": {
        "text": "signing.signingstatus.option.created",
        "value": "created"
      },
      "title": "The Sign"
    }
  ],
  "coworker": {
    "limetype": "coworker",
    "id": 1002,
    "name": "Nisse Jensen",
    "email": "[email protected]",
    "phone": "046-123456",
  }
}

Example on a document:

/status/document/1033/
{
  "context": "document",
  "potentialDocuments": [
    {
      "file": {
        "extension": "pdf",
        "filename": "mothership.pdf",
        "id": 40101,
        "mimetype": "application/pdf",
        "size": 2372002,
        "url": ""
      },
      "id": 1033,
      "type": "other"
    }
  ],
  "signings": [],
  "coworker": {
    "limetype": "coworker",
    "id": 1002,
    "name": "Nisse Jensen",
    "email": "[email protected]",
    "phone": "046-123456"
  }
}

Example on a relation:

/status/deal/2089/?force_docs=1
{
  "context": "relation",
  "potentialDocuments": [
    {
      "file": {
        "extension": "pdf",
        "filename": "mothercar.pdf",
        "id": 1,
        "mimetype": "application/pdf",
        "size": 2371234562,
        "url": ""
      },
      "id": 2089,
      "type": "other"
    }
  ],
  "signings": [],
  "coworker": {
    "limetype": "coworker",
    "id": 1002,
    "name": "Nisse Jensen",
    "email": "[email protected]",
    "phone": "046-123456"
  }
}

Example on a relation (without force_docs):

/status/deal/2089/
{
  "context": "relation",
  "potentialDocuments": [],
  "signings": [],
  "coworker": {
    "limetype": "coworker",
    "id": 1002,
    "name": "Nisse Jensen",
    "email": "[email protected]",
    "phone": "046-123456"
  }
}

Resume

POST

/signing/resume/<int:signing_id>/

Resumes a signing. Returns the checkpoint the resuming starts from, eg the next after the last succesful one.

Response:

{
  "isoDatetime": "",
  "path": "signing_complete.create_signed_document_on_signing"
}

Portal Endpoints

The following endpoints are used by the portal and uses a token as authentication.

Signing

GET

/portal/signing/<string:token>/

Get the signing for a specific signer using the signer's token.

{
  "signer": {
    "duty": "view",
    "email": "[email protected]",
    "name": "Camilla Bangsgaard",
    "order": 1,
    "role": {
      "value": "viewer",
      "text": "Viewer"
    },
    "status": {
      "text": "Notified",
      "value": "notified"
    }
  },
  "signing": {
    "coworker": {
      "email": "[email protected]",
      "id": 1001,
      "limetype": "coworker",
      "name": "Carlito Jakobsson",
      "phone": "08-7020090"
    },
    "id": 3065,
    "signingService": "criipto",
    "methods": [
      {
        "text": "Checkbox",
        "value": "checkbox"
      }
    ],
    "originalDocument": {
      "extension": "pdf",
      "filename": "JAS (bundle).pdf",
      "id": 729301,
      "mimetype": "application/pdf",
      "size": 1147798,
      "url": "https://lime_server/limepkg-esign/app_name/portal/original_document/RpBvgNLpxED3DVEklgI89BQCl-w7cw5_WxvAeCHTy_g/"
    },
    "signers": [
      {
        "duty": "view",
        "email": "[email protected]",
        "name": "Camilla Bangsgaard",
        "order": 1,
        "role": {
          "value": "viewer",
          "text": "Viewer"
        },
        "status": {
          "text": "Notified",
          "value": "notified"
        }
      }
    ],
    "status": {
      "text": "Sent",
      "value": "sent"
    },
    "title": "JAS 39"
  }
}

Original Document

GET

/portal/original_document/<string:token>/

Gets the original document file.

Signed Document

GET

/portal/signed_document/<string:token>/

Gets the signed document file.

BankID Signing Method

POST

/portal/sign/bankid/<string:personal_number>/<string:token>/

Initiate a BankID signing using Lime BankID SV Service.

Response:

{
  "success": "bool",
  "transaction_id": "string",
  "auto_start_token": "string"
}

The BankID transaction_id is then used with the GET endpoint below.

GET

/portal/sign/bankid/<string:personal_number>/<string:transaction_id>/<string:token>/

Gets the status of an ongoing BankID signing with Lime BankID SV Service.

Response:

{
  "bankidStatus": "PENDING"
}

Keep polling the endpoint if "PENDING".

{
  "bankidStatus": "COMPLETE",
  "signer": {...},
  "signing": {...}
}

Successful BankID signing when "COMPLETE".

Criipto Signing Method

POST - Initialize

/portal/sign/criipto/initialize/<string:auth_type>/<string:token>/

Initialize a BankID signing using Lime Signatures Service. See the swagger documentation of Lime Signatures Service for all available auth_types.

Response:

{
  "redirect_url": "string"
}

The application should redirect the user to the redirect_url.

POST - Finalize

/portal/sign/criipto/finalize/<string:state>/<string:token>/

Finalize a BankID signing using Lime Signatures Service. State parameter can be fetched from the query parameters in the return url that the user is redirected to after the signing is performed.

Response:

{
  "signer": {...},
  "signing": {...}
}

The transaction is now completed.

GET - AuthTypes

/portal/sign/criipto/auth_types/<string:signing_method>/<string:token>/

Get available authentication types from Lime Signatures Service for one signing method.

Response:

[
  {
    "text": "string",
    "value": "string"
  }
]

Checkbox Signing Method

POST

/portal/sign/checkbox/<string:token>/

Sign the signing with checkbox.

Payload:

{
  "signed": true
}

Response:

{
  "signer": {..},
  "signing": {..}
}

Translation

Gets all translations for eSign from the .po-files. Used by the portal.

GET

/portal/translation/

Events

The events below are published by eSign.

esign.signing.created

A new signing was created.

{
  "signing_id": 90
}

esign.signing.sent

The signing was sent to everyone at the current or lower order.

{
  "signing_id": 90
}

esign.signer.reminded

A signer is reminded about the signing process.

{
  "signer_id": 70200,
  "signing_id": 90
}

esign.signing.completed

A signing has been completed.

{
  "signing_id": 90
}

esign.signing.canceled

A signing has been canceled.

{
  "signing_id": 80
}

esign.signer.opened

A signer opened the portal.

{
  "signer_id": 70200,
  "signing_id": 90
}

esign.signer.signed

A signer has signed.

{
  "signer_id": 70200,
  "signing_id": 90
}

esign.signing.error

A signing has changed status to error.

{
  "signing_id": 80
}

Signing Versioning

1

With the introduction of checkpoints, the following properties were added to metadata:

  • version - used for versioning the signing
  • previous_status - keeps track of the previous status of the signing
  • checkpoint - object storing the name of the last completed checkpoint and the datetime

0

The original signing structure.