DoConure

How do I make our callbacks authenticate at my system?

When a signature closes we POST to your system (How do I know when something finished?). Every callback is signed with our HMAC (X-Signer-Signature), so you can tell it is ours. But many receivers also want the caller to authenticate: an OAuth token, an API key, a fixed Bearer token. Salesforce Apex REST on your org's domain is the common case. A callback environment is how you give us that, once, in the console.

Set one up

In the console, open Environments in the left menu and add one:

FieldWhat it is
SiglaA short name a call uses: lowercase letters, digits and _, at most 16, starting with a letter. prod, uat4, dev_5. It never changes.
Base URLhttps, optionally a path prefix: https://myorg.my.salesforce.com/services/apexrest. No user name, no query string. The host must be a public address: that is checked when a callback is sent, and a private one abandons the callback with the reason in the Webhooks log.
AuthenticationOne of the four types below, with its credentials.
TypeWhat we send
No authenticationNothing but our HMAC. Allowed, at your risk: anybody who learns the URL can post to it, and checking the signature is then your only proof. The console warns you.
Bearer tokenAuthorization: Bearer <your token>
API key in a header<the header you name>: <your key>, for example X-API-Key
OAuth2 client credentialsAuthorization: Bearer <access token>, a token we fetch from your token URL with your client id and secret (in the form body or as HTTP Basic), with an optional scope, audience and extra form parameters

The secret (the token, the key or the client secret) is stored encrypted and never shown again; to change it, type a new one. The first environment you add is the default. Adding a second never changes the default: only you do, with Make default.

Use it in a call

Name the environment and send only the end of the URL. The paths are appended to the base URL:

"callbackUrl": {
  "env": "uat4",
  "onSuccess": "/doconure/ok",
  "onError": "/doconure/ko"
}

The same block works in POST /api/v1/sign/envelopes (in settings), in POST /api/v1/flow (in signature) and as a bulk job's completion webhook. Without env, paths go to your default environment. A call that sends no callback at all uses the default paths of the default environment (set on the environment's own form, On success and On failure). A full https://... URL still works as it always did, with no environment and no authentication.

What is refused, at the call

  • An env you do not have, or paths with no default environment: CALLBACK_ENVIRONMENT_UNKNOWN (1625). An env that is not a valid sigla at all (upper case, a dash, more than 16 characters) is refused by the request's shape, INVALID_REQUEST_BODY (1101), and so is a URL whose scheme is neither http nor https. An http:// URL is accepted at the call but never called: a callback goes only to https, so use https.
  • A path that could change the host (a scheme, //, @, .., a backslash, a #), a full URL together with env, or a path mixed with a full URL: CALLBACK_PATH_INVALID (1626). This is what keeps your credentials going only to your own host.

Both are refused before anything is created or charged: you find out on the call, not two days later in the delivery log. There is no type in the call: the type of authentication belongs to the environment.

Which siglas can I send?

Ask before you are refused: GET /api/v1/callback-environments lists your organisation's environments, the default first, readable by any live key.

{ "environments": [
    { "env": "uat4", "isDefault": true, "authType": "bearer",
      "defaultSuccessPath": "/doconure/ok", "defaultErrorPath": "/doconure/ko" },
    { "env": "prod", "isDefault": false, "authType": "oauth2_client_credentials",
      "defaultSuccessPath": null, "defaultErrorPath": null } ],
  "count": 2 }

Read-only, and it says nothing a credential could leak through: no host, no header name, no token or client secret, only the sigla, which is the default, the kind of authentication and the default paths. Creating or changing an environment stays in the console. To be told when a signer is replaced, add onEvent beside the other two paths (see Being told when a signer is replaced).

How a callback is delivered

  • The environment is read when the callback is sent, so changing its base URL or rotating its secret also applies to callbacks already waiting.
  • An OAuth2 token is fetched when it is first needed, kept until it expires, and fetched again once if your receiver answers 401. A token endpoint that is down or answers an error is retried on the ordinary schedule; your receiver is never called without a token.
  • The token URL is held to the same rules as the callback: https only, public addresses only, redirects never followed. A token URL on a private address abandons the callback (it is your configuration to fix, not something time will).
  • The default success and failure paths belong to the default environment. Without a default environment there are no default paths, and a call that sends only a path is refused with 1625.
  • Our HMAC and the X-Signer-* headers travel on every callback, plus X-Signer-Environment with the sigla.
  • An environment that open envelopes, running batches or waiting callbacks still name cannot be deleted (CALLBACK_ENVIRONMENT_IN_USE).

The Webhooks page shows every delivery with its environment, and can send a sample event through one, so you can check the authentication before a real envelope closes.

Salesforce, as an example

In your org, create an External Client App (or a connected app) with the client credentials flow enabled and a run-as user, and expose an Apex REST class at, say, /doconure/ok. Then add an environment:

Sigla           prod
Base URL        https://myorg.my.salesforce.com/services/apexrest
Authentication  OAuth2 client credentials
Token URL       https://myorg.my.salesforce.com/services/oauth2/token
Client id       (the consumer key)
Secret          (the consumer secret)

and send "callbackUrl": {"onSuccess": "/doconure/ok", "onError": "/doconure/ko"}. No Site, no guest user, no relay in between. The details of the app depend on your org's release and settings: check them in Salesforce's own setup.

The callback body and its signature: How do I know when something finished? · Salesforce (Apex)