Overview


The Freja eID Signature Service allows you to securely deliver messages to users, and to prompt them to digitally sign data and documents. There are two important differences between transactions in the Authentication and Signature services.


Authentication transactions:

  • Only one transaction may be pending at any given time
  • They have a duration of up to 2 minutes


Signature transactions:

  • Multiple transactions may be pending simultaneously
  • They have a duration of up to 30 days (for transactions with INFERRED user info type maximum is 30 minutes)


For more detailed information about the Signature Service, please refer to Freja eID Relying Party REST API Documentation.


Calling the Service



This section describes how to make calls to the Freja eID Signature Service API and process the response.


Initiate Sign


The Signature Service is able to send signature requests to users both when:

  • the user initiated an action in your system themselves
  • you wish to send a signature request to user(s) regardless of whether they are doing something in your system at the time

Signature requests have configurable longevity. From the moment that a user receives the signature request, they have between 2 minutes and 30 days to sign the request (for transactions with INFERRED user info type maximum is 30 minutes).


Relying Parties that are Integrators must set relyingPartyId per request and that can be done only with a custom request. Read more about how Integrator and Integrated Relying Parties can integrate with Freja eID here.


/*
* Initiate sign request can be created with EMAIL and TITLE and TEXT to be signed.
* Change the values to match your setup.
*/

String email = "joe.black@verisec.com";
String title = "Title";
String text = "This text will be signed.";
InitiateSignRequest initiateSignRequest = 
    InitiateSignRequest.createDefaultWithEmail(EMAIL, title, text);
 
/*
* Initiate sign request can be created with SSN and TITLE and TEXT to be signed.
* Change the values to match your setup.
*/

String title = "Title";
String text = "This text will be signed.";
SsnUserInfo ssn = SsnUserInfo.create(Country.SWEDEN, "123456789001");
InitiateSignRequest initiateSignRequest = 
    InitiateSignRequest.createDefaultWithSsn(ssn, title, text);
 
/*
* In case of Initiate sign method, response type is String.
* The data in this response is the signature transaction reference.
*/

String transactionReference = signClient.initiate(initSignRequest);
/*
* Beside simple text that will be shown in the mobile application and
* signed by the end user, data to sign can be extended with binary data.
* This data is included in the signature but is not visible to the user.
* Create DataToSign object and set it by using the custom request builder.
*/

String dataToSignText = "Would you like to transfer 1000 EUR from account A to account B?”;
byte[] dataToSignBinaryData = "Binary data, not presented to the user.".getBytes(StandardCharsets.UTF_8);
DataToSign dataToSign = DataToSign.create(dataToSignText, binaryData);
 
/*
* Beside simple json signature that can sign text or binary data,
* advanced signature is supported for text.
*/

String dataToSignText = "Would you like to transfer 1000 EUR from account A to account B?”;
DataToSign dataToSign = DataToSign.create(dataToSignText, null);
String email = "joe.black@verisec.com";
InitiateSignRequest initSignRequest = 
    InitiateSignRequest.createCustom()
                       .setEmail(email)
                       .setDataToSign(dataToSign, SignatureType.XML_MINAMEDDELANDEN)
                       .build();
 
/*
* Initiate sign request can be created with phone number 
* by using the custom request builder.
* Change the phone number value ("+467123456789" in the example) 
* to match your setup. 
*/

String phoneNum = "+467123456789";
InitiateSignRequest initSignRequest = 
    InitiateSignRequest.createCustom()
                       .setPhoneNumber(phoneNum)
                       .setDataToSign(dataToSign)
                       .build();

/*
* Initiate sign request can be created as INFERRED
* by using the custom request builder.
* Inferred transactions are not bound to a specific user upon initiation, 
* they are bound to a user when a QR-code is scanned. That is, the first user that
* scans the QR-code of a pending inferred transaction gets bound to it. 
* As such you need to be aware of the privacy of the signature content: 
* if a signature content is sensitive and intended for a specific recipient 
* we strongly advise you to use one of the binding forms of the signature API.
*/

InitiateSignRequest initiateSignRequest = InitiateSignRequest.createCustom()
                    .setInferred()
                    .setDataToSign(dataToSign)
                    .build();

/*
* Parameter minRegistrationLevel, optional, describes the
* minimum required registration level of a user in order to
* approve/decline signing transaction. If not present, default level will be PLUS.
*/

RegistrationState minRegistrationLevel = 
    RegistrationState.EXTENDED;
  
/*
* Parameter title, optional, describes the title to display in the transaction
* if presented to the user on the mobile device. 
* The title will be presented regardless of the
* confidentiality setting. If not present, a default text 
* "Confirm action" will be presented.
*/

String title = "Transaction title";
 
/*
* Parameters pushNotificationTitle and pushNotificationText, optional, describe
* the title and the text of the notification sent to the mobile
* device to alert the user of a signature request.
* If not present, a default title 
* "Sign" and text "You have an action to sign in Freja eID"
* will be presented.
*/

String pushNotificationTitle = "Sign notification title";
String pushNotificationText = "Sign notification text";
PushNotification pushNotification = 
    PushNotification.create(pushNotificationTitle, pushNotificationText);
 
/*
* Parameter expiry, optional, describes the time until which the Relying Party
* is ready to wait for the user to confirm the signature request.
* Expressed in milliseconds since January 1, 1970, 00:00 UTC.
* Min value is current time +2 minutes, max value is current
* time +30 days. If not present, defaults to current time +2 minutes.
*/

Long expiry = Instant.now().plus(3,ChronoUnit.MINUTES).getEpochSecond() * 1000;
 
/*
* Parameter attributesToReturn is used to request additional information about the user.
* Interpreted as a set of attributes that represent that extra information is required.
* The requested information is returned when fetching signature results.
*/

AttributeToReturn[] attributes = {AttributeToReturn.BASIC_USER_INFO,
                                  AttributeToReturn.EMAIL_ADDRESS,
                                  AttributeToReturn.ALL_EMAIL_ADDRESSES,
                                  AttributeToReturn.ALL_PHONE_NUMBERS,
                                  AttributeToReturn.DATE_OF_BIRTH,
                                  AttributeToReturn.AGE,
                                  AttributeToReturn.PHOTO,
                                  AttributeToReturn.ADDRESSES,
                                  AttributeToReturn.SSN,
                                  AttributeToReturn.DOCUMENT
                                  AttributeToReturn.RELYING_PARTY_USER_ID,
                                  AttributeToReturn.CUSTOM_IDENTIFIER,
                                  AttributeToReturn.REGISTRATION_LEVEL,
                                  AttributeToReturn.COVID_CERTIFICATES
};

/*
* For the custom initiate sign request with all parameters, see the example below.
*/

String email = "joe.black@verisec.com";
InitiateSignRequest initSignRequest = 
    InitiateSignRequest.createCustom()
                .setEmail(email)
                .setDataToSign(dataToSign)
                .setExpiry(expiry)
                .setMinRegistrationLevel(minRegistrationLevel)
                .setAttributesToReturn(attributes)
                .setPushNotification(pushNotification)
                .setTitle(title)
                .build();
 
/*
* In case of Initiate sign method, response type is String.
* The data in this response is the signature transaction reference.
*/

String transactionReference = 
    signClient.initiate(initSignRequest);

For each Integrated Relying Party, as well for the Integrator Relying Party itself, Freja eID generates a unique identifier called relyingPartyId. The Integrator Relying Party must pass this identifier in each request.


/*
* Parameter relyingPartyId represents a unique ID of the Relying Party
* for which the signing request should be initiated.
*/

String relyingPartyId = "relying_party_id";
InitiateSignRequest initSignRequest = 
    InitiateSignRequest.createCustom()
                .setEmail(email)
                .setDataToSign(dataToSign)
                .setRelyingPartyId(relyingPartyId)
                .build();


Integrator-specific User ID


This section only applies to you if you are an Integrator Relying Party - one acting as an Integrator for multiple other Relying Parties. If you are a Relying Party or Partner who is acting only on your own behalf, feel free to skip this section.


The Integrator Relying Party can ask for an additional user attribute called INTEGRATOR_SPECIFIC_USER_ID. This is a unique, user-specific value that allows the Integrator to identify the same user across multiple sessions regardless of the Integrated Relying Party service that the user is using.


/*
* Parameter relyingPartyId represents a unique ID of the Relying Party
* for which the signing request should be initiated.
*/

String relyingPartyId = "relying_party_id";
 
/*
* When initiating signature, you have to set relyingPartyId for every request.
* See the example below.
*/

String email = "joe.black@verisec.com";
 
AttributeToReturn[] attributes = {AttributeToReturn.INTEGRATOR_SPECIFIC_USER_ID};
InitiateSignRequest initSignRequest = InitiateSignRequest.createCustom()
                .setEmail(email)
                .setDataToSign(dataToSign)
                .setAttributesToReturn(attributes)
                .setRelyingPartyId(relyingPartyId)
                .build();
String transactionReference = signClient.initiate(initSignRequest);


Get One Signature Result


This method is used to fetch a single result for a specified signature transaction reference (signRef returned from a call to Initiate Sign method).


/*
* A reference unique to the transaction that can be used to
* query the result of a transaction.
*/

String signRef ="reference";
   
/*
* In case of getResult method, response type is SignResult.
* The response contains the signature transaction reference of the signing request,
* the status of the action and details (can be used for extra validation of response).
* The response contains additional attributes basicUserInfo, emailAddress, 
* allEmailAddresses, dateOfBirth, age, photo, relyingPartyUserId, customIdentifier, 
* ssn, integratorSpecificUserId, allPhoneNumbers, addresses, registrationLevel, 
* documentInfo and/or covidCertificates.
*/

SignResultRequest signResultRequest = SignResultRequest.create(signRef);
SignResult response = signClient.getResult(signResultRequest);
String receivedSignRef = response.getSignRef();
ActionStatus status = response.getStatus();
String details = response.getDetails();
RequestedAttributes requestedAttributes = response.getRequestedAttributes();
BasicUserInfo basicUserInfo = requestedAttributes.getBasicUserInfo();
String emailAddress = requestedAttributes.getEmailAddress();
SsnUserInfo ssn = requestedAttributes.getSsn();
String relyingPartyUserId = requestedAttributes.getRelyingPartyUserId();
String dateOfBirth = requestedAttributes.getDateOfBirth();
Integer age = requestedAttributes.getAge();
String photo = requestedAttributes.getPhoto();
String customIdentifier = requestedAttributes.getCustomIdentifier();
String integratorSpecificUserId = requestedAttributes.getIntegratorSpecificUserId();
List<AddressInfo> addresses = requestedAttributes.getAddresses();
List<Email> allEmailAddresses = requestedAttributes.getAllEmailAddresses();
List<PhoneNumberInfo> allPhoneNumbers = requestedAttributes.getAllPhoneNumbers();
RegistrationLevel registrationLevel = requestedAttributes.getRegistrationLevel();
DocumentInfo document =
requestedAttributes.getDocument();
CovidCertificates covidCertificates = requestedAttributes.getCovidCertificates();
String vaccinationCertificateBase45 = covidCertificates.getVaccines().getCertificate();
String testsCertificateBase45 = covidCertificates.getTests().getCertificate();
String recoveryCertificateBase45 = covidCertificates.getRecovery().getCertificate();


Only Integrator Relying Parties can request integratorSpecificUserId, and relyingPartyId has to be passed as a part of the request.

Get Final Signature Result

This is a blocking method and is used to fetch a single result with a final status (can be one of: rejected, approved, cancelled or expired) for a specified signature reference. The method keeps polling until it receives the final status of the signature request. If the maximum polling time expires before the action is completed, the method will throw an exception.


/*
* A reference unique to the transaction that can be used to
* query the result of that transaction.
*/

String signRef ="reference";
  
/*
* A maximum time in seconds to wait for a final status of action
* (to be approved, cancelled, rejected or expired).
*/

int maxWaitingTimeInSec = 120;

/*
* In case of pollForResult method, response type is SignResult.
* The response contains signature transaction reference of the signing request,
* the status of the action and details (can be used for extra validation of response).
* The response contains additional attributes basicUserInfo, emailAddress, 
* allEmailAddresses, dateOfBirth, age, relyingPartyUserId, customIdentifier, ssn, 
* integratorSpecificUserId, allPhoneNumbers, addresses, registrationLevel, photo
* documentInfo and/or covidCertificates. 
* If maxWaitingTimeInSec passes and signature action is not completed with one of the 
* final statuses, this method will throw FrejaEidClientPollingException.
*/

SignResultRequest signResultRequest = SignResultRequest.create(signRef);
SignResult response = signClient.pollForResult(signResultRequest, maxWaitingTimeInSec);
String receivedSignRef = response.getSignRef();
ActionStatus status = response.getStatus();
String details = response.getDetails();
RequestedAttributes requestedAttributes = response.getRequestedAttributes();
BasicUserInfo basicUserInfo = requestedAttributes.getBasicUserInfo();
String emailAddress = requestedAttributes.getEmailAddress();
SsnUserInfo ssn = requestedAttributes.getSsn();
String relyingPartyUserId = requestedAttributes.getRelyingPartyUserId();
String dateOfBirth = requestedAttributes.getDateOfBirth();
Integer age = requestedAttributes.getAge();
String photo = requestedAttributes.getPhoto();
String customIdentifier = requestedAttributes.getCustomIdentifier();
String integratorSpecificUserId = requestedAttributes.getIntegratorSpecificUserId();
List<AddressInfo> addresses = requestedAttributes.getAddresses();
List<Email> allEmailAddresses = requestedAttributes.getAllEmailAddresses();
List<PhoneNumberInfo> allPhoneNumbers = requestedAttributes.getAllPhoneNumbers();
RegistrationLevel registrationLevel = requestedAttributes.getRegistrationLevel();
DocumentInfo document =
requestedAttributes.getDocument();
CovidCertificates covidCertificates = requestedAttributes.getCovidCertificates();
String vaccinationCertificateBase45 = covidCertificates.getVaccines().getCertificate();
String testsCertificateBase45 = covidCertificates.getTests().getCertificate();
String recoveryCertificateBase45 = covidCertificates.getRecovery().getCertificate();


Only Integrator Relying Parties can request integratorSpecificUserId, and relyingPartyId has to be passed as a part of the request.

Get Signature Results


This method is used to fetch the results of multiple signature requests.


Integrator Relying Parties must pass relyingPartyId as part of the request.


/*
* Response type is list of sign result.
* The response will contain a complete list of signature requests
* successfully initiated by the Relying Party.
* The time period during which a specific signature reference is available for checking will * depend on the longevity of the signature operation (see the expiry parameter in the 
* Initiate sign method) and is calculated as expiry time plus 3 days.
*/

SignResultsRequest signResultsRequest = 
    SignResultsRequest.create();
        List<SignResult> response = signClient.getResults(signResultsRequest);


Cancel Signature


This method is used to cancel an initiated signature request.


Integrator Relying Parties must pass relyingPartyId as part of the request.


/*
* A reference unique to the transaction that can be used to query the result of the transaction.
*/

String signRef ="reference";
CancelSignRequest cancelSignRequest = 
    CancelSignRequest.create(signRef);
        signClient.cancel(cancelSignRequest);