Implementation Best-Practises
Validate Input Parameters before processing
Keep in mind that the callback could have been fired from malicious sources. Therefore, validate all input parameters received via the callback. This includes:
- Is the action one of the expected ones?
- Note that we might add other action codes in the future. Ignore those which should not be handled by your callback handler.
- Is the envelope ID in the proper format?
- We are using the GUID format for envelope IDs
- Is the envelope in the expected status?
- The "envelopeCallback" indicates that the envelope was completed. But don't trust just the occurance of an inbout callback. Validate via API calls if the envelopeId exists, and if the envelope is in the expected status.
- Implement proper error handling, e.g. for cases where the envelope has been deleted before the callback handler was invoked.
- As we recommend to implement asynchronous callback handling (see next topic), basic validation of the parameters should be done when noting down the callback - but another validation should be done before processing the event in the service job, as the envelope status or its existence might change.
Asynchronous Callback Handling
Whenever a callback is received, the callback handler should just note down the event and return to eSignAnyWhere that the callback event was successfully noted down. But the event processing should be done asymetric, e.g. in a background service call.
If the implementation is done in the callback handler directly (in a synchronous processing), you may run in situations where the handling of a callback takes longer than the standard network timeouts configured on eSignAnyWhere side. When eSignAnyWhere receives a timeout due to longer ongoing processing activities in a callback handler, eSignAnyWhere is noting down the failure and starting a retry mechanism. In standard configurations, there are up to 30 retries of the callback. This may lead to situations where the callback processing of the same envelope, for the same event, is done up to 30 times or even higher with different system configuration. In case a callback handler is e.g. downloading signed documents from eSignAnyWhere, and uploading the documents to a document management system, an improper integration may result in storing the same document multiple times in the document management system.
Therefore, note down in a database which event was received, and for which envelope (or workstep, in case of WorkstepEventCallbacks). Let the callback handler return a HTTP 200 directly after the event was noted down in persistent storage. Implement a periodic serverside job which gets activated on a timed schedule, or on adding entries to the noted down events table. The serverside job then should asynchronously perform the necessary actions.
Authentication retrieved via OAuth 2.0 Code Grant & note down the sender user
In some scenarios, e.g. those where the envelope is sent from WebUI, a callback handler implementation needs to deal with envelopes sent by different senders. While in scenarios where envelopes are sent via API, the sender's API key is well known at that time already (obtained via OAuth code or configuration), the user specific API key is unknown when sending via WebUI. We do therefore recommend to implement a BeforeSendRedirect page that implements the OAuth Code Grant flow, to obtain the consent from the sender to grant access via OAuth. The implementation then can retrieve, if unknown for the sender, the API key. We recommend to store the obtained API key per user in the database, under consideration of OWASP recommendations on how to persist passwords (e.g. encrypt them). Furthermore, note down in a different table which envelope (by envelopeId) was sent by which sender, as this information is necessary for the callback handler implementation.
In the callback handler implementation, do a lookup based on envelopeId which user was the sender; and then authenticate with the apiKey noted down for the sender. In case of an authentication error, trigger an error handling procedure to obtain a new apiKey (read below).
Alternative techniques such as using teams or using organization keys, are listed as "not recommended" for the following reasons:
- Having one team that contains all users and with a "technical user" as teamlead, so that the technical users as a teamlead has API access to all envelopes of the other senders, is not recommended because of privacy considerations, and in addition because of severe negative performance impact when using large teams with more than 20 or 30 users.
- The use of Organization Keys is not recommended for security considerations, and therefore the use of organization keys is by default disabled on newly generated organizations by settings that can be changed via administrative web only (on SaaS: Namirial staff only). Also, Organization Key authentication is not supported any longer with REST API v6.
- Using a "user determination service" which does the lookup per envelopeId directly on the database is not recommended as we don't guarantee to have a compatible DB schema with future product versions.
Error Handling
Don't forget to think about proper error handling in your asynchronous callback handler. A callback handler is a serverside job which does not involve the user typically. But for situations where an error occured, think if the sender or an administrator needs to be involved. If a person has to be involved, as we are talking about automatic serverside processing, think about a proper way to trigger a human interaction - probably with some user specific or administrative UI of the callback handler, and a notification sent via e-mail. Typical scenarios you might consider in the implementation:
- API key is not valid any more, e.g. because a user revoked the permission for the OAuth a
- Unexpected technical errors e.g. in communication with the external system to be integrated
For some of them the automatic retry might solve it, therefore note down how often the event occured to understand if there will be another retry anyways (e.g. if a remote system is not available).
For those where all retries failed, a notification to someone checking system status and fixing the issue could be necessary.