ES512 JWS request signing for the TrueLayer Payments, Payouts, and Mandates APIs.
Uses Erlang's :crypto and :public_key OTP modules — zero external dependencies.
TrueLayer signing specification
- Algorithm: ES512 (ECDSA with P-521 curve and SHA-512)
- Format:
<base64url_header>..<base64url_p1363_signature> - JWS protected header:
{"alg":"ES512","kid":"<key_id>","tl-version":"2","tl-headers":"<header_names>","iat":<unix_ts>} - Signing payload:
<METHOD>\n<PATH>\n<HEADER_LINES>\n<BODY>
Obtaining a signing key
Generate a P-521 EC key pair using OpenSSL:
openssl ecparam -name secp521r1 -genkey -noout -out signing_private.pem
openssl ec -in signing_private.pem -pubout -out signing_public.pemUpload the public key to the TrueLayer Console and note the returned Key ID.
Summary
Functions
Parse a PEM-encoded EC private key (PKCS8 or SEC1) and return a signer map.
Produce the value of the Tl-Signature request header.
Types
Functions
@spec new_signer(binary(), String.t()) :: {:ok, signer()} | {:error, TruelayerClient.Error.t()}
Parse a PEM-encoded EC private key (PKCS8 or SEC1) and return a signer map.
Example
pem = File.read!("keys/signing_private.pem")
{:ok, signer} = TruelayerClient.Signing.new_signer(pem, "my-key-id")
@spec sign(signer(), String.t(), String.t(), map(), binary()) :: {:ok, String.t()} | {:error, TruelayerClient.Error.t()}
Produce the value of the Tl-Signature request header.
Parameters
signer- signer map fromnew_signer/2method- HTTP method in uppercase, e.g."POST"path- request path without query string, e.g."/v3/payments"headers- map of header names → values to include in the signaturebody- raw request body bytes (use""for no body)
Example
{:ok, sig} = TruelayerClient.Signing.sign(signer, "POST", "/v3/payments", %{
"idempotency-key" => "idem-001",
"content-type" => "application/json"
}, body_bytes)
# Use sig as the value of the Tl-Signature header