Server-to-server consent
As stated before, many operations, such as initiating a payment, are sensitive and would normally require a user consent. This is obtained by sending a text message to the user. The user then consents via the web browser, following the procedure previously described. All these operations have to be performed by the users themselves. It can get extremely tedious if thousands of operations are awaiting a consent, conducted by a human.
This is where server-to-server consent comes into play. More precisely, it avoids the intervention of a human being in all interactions and opens up new opportunities: generation of single use virtual cards to pay merchants, batch payments, send refund transfers, etc...
Please note that for security & regulatory reasons, server-to-server consent is bound to the legal representative of a project (i.e no consents with key from project 1 on project 2). More specifically, this feature is ONLY accepted for operations performed by your project's legal representative. It cannot be implemented in your final customers' accounts.
This feature relies on key cryptography. This model involves a pair of keys, public and private. These are both associated with an entity (legal representative, in our case). The public key is stored in the project settings, and its corresponding private key has to be kept secret on your side.
Optionally, you can save in your dashboard a list of trusted IP addresses.
Any operation required to set up or modify the feature (public key and IP addresses setup) must be performed with strong customer authentication performed by the project legal representative.
You must provide a public key that will be used to verify the server signature.
The cryptographic keys have to follow the following algorithm:
- ECDSA with reputed strong curve (such as p-256)
- Key type must be exported in JWK
Any key not respecting the above requirements will not be accepted.
Swan strongly advises the partner to renew the key pair every 730 days the latest
Below is a simple example using your browser crypto API.
await crypto.subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, ["sign", "verify"])
.then(async ({ publicKey, privateKey }) => ({
publicKey: await crypto.subtle.exportKey("jwk", publicKey),
privateKey: await crypto.subtle.exportKey("jwk", privateKey),
}))
.then(keys => ({
publicKey: JSON.stringify(keys.publicKey),
privateKey: JSON.stringify(keys.privateKey),
}));
You should obtain a pair of keys like the following:
{
'{"crv":"P-256","d":"{{dVALUE}}","ext":true,"key_ops":["sign"],"kty":"EC","x":"{{xVALUE}}","y":"{{yVALUE}}"}'
'{"crv":"P-256","ext":true,"key_ops":["verify"],"kty":"EC","x":"{{xVALUE}}","y":"{{{yVALUE}}}"}'
}
You can use the above keys to:
- install the public key in your server consent settings, and
- the private key to sign your consent challenges
Generate a pair of keys for testing purposes
Generating your pair of keys using these cryptographic standards can be done using various libraries or packages.
As an example, https://git.coolaj86.com/coolaj86/eckles-cli.js or https://git.coolaj86.com/coolaj86/rasha.js provide similar mechanisms to generate your pair of keys using the right methods in the flavor of your choice.
To use server-to-server consent, you must:
- 1.Connect to your dashboard
- 2.Access the Developers tab where you will find the Server Consent menu entry
- 3.From there, if you are in Sandbox, installation is straightforward
- 1.Simply copy and paste your Public key
- 2.Add one or more IPs to whitelist
- 4.You're ready!
In order to save your Server-to-Server Consent configuration on your live environment, a consent is sent by sms to the project Legal Representative.
This consent notification will contain:
- your first & last name : "who's requesting the installation of the key"
- the key : "what's requested to be reviewed and installed"
You now have a private key (installed on your server) and a public key (installed in your Swan Dashboard).
If expiring user access tokens interrupt your automations, consider impersonating the user with a project access token instead.
To sign your first server-to-server consent, you must:
- When retrieving the consent as seen in the Workflows, you will be provided with a consent '
challenge
'
{
"data": {
"consents": {
"edges": [
{
"node": {
"id": "{{CONSENT_ID}}",
"challenge": "{{CONSENT_CHALLENGE}}",
"purpose": "AddCard",
"status": "Created"
}
}
]
}
}
}
- You must now sign the
challenge
field using your private key
You can sign the challenge using the following script
function toBase64url(message, toStringify) {
let buffer = toStringify ? JSON.stringify(message) : message;
if (typeof buffer === "string") {
const textEncoder = new TextEncoder("utf-8");
buffer = textEncoder.encode(buffer);
}
const bitString = String.fromCodePoint(...buffer);
return window
.btoa(bitString)
.replace(/=/gi, "")
.replace(/\//gi, "_")
.replace(/\+/gi, "-");
}
function getMessage(composer) {
return `${toBase64url(composer.header, true)}.${toBase64url(
composer.payload,
true
)}`;
}
function toBuffer(message) {
return new TextEncoder().encode(message);
}
async function signAndExportJwtToken(jwtPrivateKey, composer) {
const jsonPrivateKey = JSON.parse(jwtPrivateKey);
const privateKey = await crypto.subtle.importKey(
"jwk",
jsonPrivateKey,
{
name: "ECDSA",
namedCurve: jsonPrivateKey.crv,
},
false,
["sign"]
);
// ---
const message = getMessage(composer);
const signatureBuffer = await crypto.subtle.sign(
{
name: privateKey.algorithm.name,
hash: privateKey.algorithm.namedCurve.replace(/P/gi, "SHA"),
},
privateKey,
toBuffer(message)
);
// ---
const signatureUint8 = new Uint8Array(signatureBuffer);
return `${message}.${toBase64url(signatureUint8)}`;
}
Signing the consent challenge
1
await signAndExportJwtToken("{{PRIVATE_KEY_JWK}}", {
2
header: { alg: "ES256", typ: "JWT" },
3
payload: { challenge: "{{CONSENT_CHALLENGE}}" },
4
});
5
Request
Response
mutation MyMutation {
GrantConsentWithServerSignature {
consentId: "{{CONSENT_ID}}" ,
signature: "{{SIGNED_CONSENT_CHALLENGE}}",
}
) {
... on CreateMultiConsentSuccessPayload {
__typename
consent {
consentUrl
}
}
}
}
{
"data": {
"grantConsentWithServerSignature": {
"__typename": "GrantConsentWithServerSignatureSuccessPayload",
"consent": {
"id": "{{CONSENT_ID}},
"status": "Accepted"
}
}
}
}

Consent workflow with server consent
Any mutation not listed below will throw a rejection if a server consent is attempted.
Once the public key is installed, Swan provides a fast and easy way to revoke it.
This revoking mechanism will instantly remove your public key from your project, and any new consent signed will be rejected.
Please note that you will not be able to reuse this public key in the future for your live project.
You must make sure that:
- all operations and consents to be granted are paused before you install your new public key and restart calling
GrantConsentWithServerSignature
- You have a new pair of keys ready to be installed on your systems and project.
Last modified 28d ago