Accept 3DS authentication

Accepts a 3D Secure authentication request with cryptographic signatures.

This endpoint is used to confirm a 3DS authentication after the user has
reviewed the transaction details in their wallet application. The request
must include valid cryptographic signatures proving the user's consent.

Example with Ethersjs:

const wallet = ethers.Wallet.createRandom();
const types = {
  Authenticate: [{ name: 'id', type: 'string' }],
};
const domain = {
  name: 'Kulipa Wallet Authentication',
  version: '1',
  chainId: 1, // this is the chain ID of the wallet network
};
const message = {
  id: '3ds-e259ee22-f857-444d-9c38-e0bf2ee669e3', // the 3DS authentication ID
};

const signature = await wallet.signTypedData(domain, types, message);

Example with ECDSA signature (when signing from the user wallet is not possible):

Make sure to use the correct private key and passphrase from the public key you shared with Kulipa.

const crypto = require('crypto');
const canonicalize = require('canonicalize');

const payload = {
  primaryType: 'Authenticate',
  message: {
    id: '3ds-e259ee22-f857-444d-9c38-e0bf2ee669e3'
  }
};

const canonicalizedPayload = canonicalize(payload);
const sign = crypto.createSign('SHA256');
sign.update(canonicalizedPayload);
sign.end();

const signature = sign.sign({
  key: privateKey, // your private key
  format: 'pem',
  type: 'pkcs8',
  passphrase: 'your-passphrase', 
}, 'hex');

Example with Solana kit:

const keys = await generateKeyPair();
const address = await getAddressFromPublicKey(keys.publicKey);
const validTypedData = {
  cardAuthenticationId: '3ds-e259ee22-f857-444d-9c38-e0bf2ee669e3',
  purpose: 'Card 3DS Authentication',
  organisation: 'Kulipa',
  userId: 'usr-595f5f00-8471-4676-90b0-61a9277e2f78',
  nonce: getUnixTime(new Date()), // we validate the nonce is within +/- 5 minutes of the current timestamp to allow for server drift
  wallet: address,
};
const structCodec = getStructCodec([
  ['organisation', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
  ['userId', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
  ['purpose', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
  ['nonce', getU64Codec()],
  ['wallet', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
  ['cardAuthenticationId', addCodecSizePrefix(getUtf8Codec(), getU32Codec())],
]);
const encodedData = structCodec.encode(validTypedData);
const signedBytes = await signBytes(keys.privateKey, encodedData);
const signature = getBase58Decoder().decode(signedBytes);
console.log(signature);

For more details about the 3DS process, see the 3DS documentation.

Language
Credentials
Header