TruelayerClient.Signing (truelayer_client v1.0.0)

Copy Markdown View Source

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.pem

Upload 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

signer()

@type signer() :: %{key: term(), key_id: String.t()}

Functions

new_signer(pem, key_id)

@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")

sign(map, method, path, headers, body)

@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 from new_signer/2
  • method - 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 signature
  • body - 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