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:
| Field | What it is |
|---|---|
| Sigla | A short name a call uses: lowercase letters, digits and _, at most 16, starting with a letter. prod, uat4, dev_5. It never changes. |
| Base URL | https, 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. |
| Authentication | One of the four types below, with its credentials. |
| Type | What we send |
|---|---|
| No authentication | Nothing 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 token | Authorization: Bearer <your token> |
| API key in a header | <the header you name>: <your key>, for example X-API-Key |
| OAuth2 client credentials | Authorization: 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
envyou do not have, or paths with no default environment:CALLBACK_ENVIRONMENT_UNKNOWN(1625). Anenvthat 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. Anhttp://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 withenv, 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, plusX-Signer-Environmentwith 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)