API request signing#
We require API Request Signing to secure your communication to the GoCardless API and to comply with the Strong Customer Authentication requirement. This section will walk you through how to:
- Generate public and private keys and upload the public key to GoCardless
- Build the signature base that will be used to generate the Gc-Signature header
- Build and attach the Gc-Signature and Gc-Signature-Input headers and send them with your API request
Sandbox developer bypass#
For ease of development (e.g. testing our endpoints with Postman or curl), it is possible to bypass request signing in the sandbox environment using the following header:
Generate your key pair#
- We use ECDSA keys for API request signing. You must generate an ES512 key pair using the P-521 elliptic curve without a passphrase. Use the following commands in a terminal to generate your key pair:
- Securely save your private key.
- Upload your public key to GoCardless via the dashboard.
- Go to Settings → Account settings.
- Under "API request signing", add a new public key.
When you've added a new public key, a corresponding request_signing_key ID (e.g. RSK00123456789300123456789300) is generated. You will need this for building the request signature.
Signing the API request#
We follow the RFC-9421 specification for HTTP Message Signatures.
- Create the signature base. This is a raw string containing all the components covered by the signature. It must be in the format shown in the example below.
Requirements:
- Each line is concatenated with a newline character (
\n). - You must respect the format (e.g., respect every character like
",@, or spaces). @method,@authority, and@request-targetare required components in building the signature base.
You can add any other signed headers you want to include into the signature base. They must appear in the same order as listed in @signature-params. For any additional signed headers, you must pass them as HTTP headers in the request itself.
The following table describes how the signature base is built:
| Key | Value |
|---|---|
"@method" | The HTTP method in uppercase, e.g. GET or POST. |
"@authority" | The target URI host, usually conveyed via the Host header (e.g. api.gocardless.com). |
"@request-target" | The full path including any query parameters. Query parameters must be ordered deterministically by sorting keys. |
"content-digest" | Only needed if the request has a body (e.g. POST/PUT). SHA-256 base64-encoded hash of the body, wrapped as sha256=:CONTENT_DIGEST:. The body must be serialised deterministically (sorted keys) to produce a consistent digest. |
"content-type" | Only needed if the request has a body. The content type, e.g. application/json. |
"content-length" | Only needed if the request has a body. Size of the message body in bytes. |
"@signature-params" | The following signature parameters should be passed as follows and separated by semicolon: (<signature components>);<signature param1>;<signature param2> Signature Components In brackets — the components of the request that are included in the signature process. This would be "@method" "@authority" "@request-target", followed by any additional request headers, each separated by a space. They should appear in the order as you used to build the rest of the signature base. Signature Parameters keyid — the identifier of your public request signing key. created — a Unix timestamp (e.g. 1675688690) in UTC. nonce — a random unique value generated for this signature as a String value. This must be a random base64-encoded string of at least 128 bits of data from a cryptographically secure random number generator. |
More details on building the signature base can be found in section 2.5 of RFC-9421.
- Sign the signature base with your private key.
- Encode the signature in base64.
- Set the
Gc-SignatureandGc-Signature-InputHTTP headers.
Requirements:
Gc-Signatureis the base64 encoded signature. It must be in the formatGc-Signature: sig-1=:<SIGNATURE>:wheresig-1identifies the signature and the value is wrapped in colons.Gc-Signature-Inputis the same string as@signature-paramsused in building the signature base. It must be in the formatsig-1=<SIGNATURE_INPUT>.
- Send your request with the attached headers.
If making a request with a payload, the payload sent must have the same structure as used to generate the content-digest to ensure they match during verification.
Code Example#
Example methods for building the signature headers:
You can then use this code to generate the HTTP Signature headers and attach them to your request:
API Response#
API requests that are correctly signed will be processed normally. If the signature is invalid, the API will return 401 Unauthorized.
Test your request signing#
To test whether you are correctly building request signatures, make a POST request to the /test-signature endpoint. It will validate the Gc-Signature and Gc-Signature-Input headers and return 204 No Content if valid. No further validation is performed on any request body passed.