Display sensitive card information and manage PINs securely in your client application using PSE SDK (PSE version 3 with EIP-712 two-factor authentication).
If you want to display sensitive information (such as card numbers or PINs) in your front-end, you’ll need to interact with our Partner Secure Elements (PSE) service. The easiest way to do this is by using the PSE SDK from Gnosis Pay.To initialize the SDK, you’ll need:
An App ID provided to you upon registration with Gnosis Pay
An ephemeral-token retrieved from the PSE private API using mTLS authentication
An EIP-712 signature and nonce obtained from the challenge flow described below
PSE version 3 adds an EIP-712 wallet signature as a second factor for every sensitive operation. Pass pseVersion: 3 when constructing the SDK and include eip712Signature and eip712Nonce obtained from the challenge flow described below.Note: pseVersion refers to the PSE SDK protocol version and is unrelated to the Gnosis Pay API path (which remains /v2).
Backend Required: mTLS authentication can only be performed from a
back-end. You need a back-end responsible for retrieving the
ephemeral-token and sending it to your front-end upon request. We’ll go
through each step in this guide.
Once your front-end has the ephemeral-token and auth module token, it can initialize the PSE SDK and use it to display secure elements.Here’s a diagram showing each step:
Mutual TLS (mTLS) is a type of authentication in which two parties in a connection authenticate each other using the TLS protocol. Your back-end will establish an mTLS authentication with the Gnosis Pay private PSE API to receive an ephemeral-token.
After signing up through the Partners Dashboard, you will receive an App ID instantly, which will be used in the certificate generation below. You must first create a private key and then generate a Certificate Signing Request (CSR) using the App ID as follows:
# APP_ID is a string starting with `gp_` that you have received from Gnosis Payexport APP_ID="gp_woop_123"# Create a private key (NEVER share with anyone)openssl ecparam -name prime256v1 -genkey -noout -out "${APP_ID}.key.pem"# Create the CSR (OK to share)openssl req -new -sha256 -key "${APP_ID}.key.pem" -out "${APP_ID}.csr.pem" -subj "/CN=${APP_ID}"
You can now share the ${APP_ID}.csr.pem file with the Gnosis Pay team. DO NOT EVER share the .key.pem file with ANYONE.Once we receive your Certificate Signing Request, we will sign it and send you back the signed certificates. These signed certificates, along with your private key, are used to establish the connection with the PSE API.
How to Establish an mTLS Authentication (in Node.js)
You should securely store the certificates in your environment along with your private key.Your environment should expose the certificates and private key, for example:
PSE version 3 requires a wallet signature before each sensitive operation. This acts as a second factor: even if an authModuleToken is compromised, an attacker cannot view card data or change a PIN without also controlling the user’s wallet.
Request a one-time challenge from the auth module.
Ask the user’s wallet to sign the returned EIP-712 typed data.
Pass the resulting signature and nonce to the SDK constructor.
The PSE service forwards both values to the auth module, which verifies the signature and marks the nonce as consumed. Each challenge is single-use and expires after 5 minutes.
import { useSignTypedData } from "wagmi";const { signTypedDataAsync } = useSignTypedData();// 1. Fetch the challenge (authModuleToken is sent automatically via client config)const { data, error } = await getPciCardsByCardIdChallenge({ path: { cardId }, query: { action: "view-details" },});if (error || !data) throw new Error("Failed to get EIP-712 challenge");// 2. Sign — convert nonce to BigInt for the uint256 typeconst signature = await signTypedDataAsync({ domain: data.domain, types: data.types, primaryType: data.primaryType, message: { authorization: data.message.authorization, nonce: BigInt(data.message.nonce), },});// 3. Pass to SDK constructorconst eip712Signature = signature;const eip712Nonce = data.message.nonce; // keep as decimal string
The challenge must be fetched immediately before each SDK initialization.
Do not reuse a nonce across different operations or SDK instances — it will be
rejected after the first use.
After completing the EIP-712 challenge/sign step above, initialize the SDK with pseVersion: 3:
import GPSDK, { ElementType } from "@gnosispay/pse-sdk";// 1. Get the auth module access token from your SIWE auth flowconst authModuleToken = getAccessToken(); // your auth implementation// 2. Fetch ephemeral token from your backendconst response = await fetch("/api/ephemeral-token");const { data } = await response.json();// 3. Fetch and sign an EIP-712 challenge (see section above)// Use the action matching the operation you are about to perform:// "view-details" | "view-pin" | "change-pin"const { eip712Signature, eip712Nonce } = await getSignedChallenge(cardId, "view-details");// 4. Initialize the SDK with PSE version 3const gpSdk = new GPSDK({ pseVersion: 3, // PSE version 3 — required for EIP-712 2FA appId: "gp_your_app_id", // Your Partner App ID ephemeralToken: data.ephemeralToken, authModuleToken: authModuleToken, // Auth module access token eip712Signature: eip712Signature, // Hex signature from wallet eip712Nonce: eip712Nonce, // Decimal nonce string from challenge onActionSuccess: (action) => { console.log("Action completed:", action); }, onInvalidToken: (message) => { console.error("Token invalid:", message); // Refresh the ephemeral token and reinitialize }, onError: (message, details) => { console.error("PSE error:", message, details); },});
The authModuleToken expires every 15 minutes. Handle the onInvalidToken
callback to refresh your access token via the token refresh flow
and re-initialize the SDK.
Use ElementType.CardData to display the full card number, expiration date, and security code.
Use action: "view-details" when fetching the EIP-712 challenge for this element.
// cardId is a UUID obtained from GET /cardsconst { destroy } = gpSdk.init(ElementType.CardData, "#card-data-container", { cardId: "019c9578-a8ce-7445-9961-51b945605f70",});// Call destroy() when unmounting or cleaning updestroy();
How to Customize the Style of Secure Elements in the iframe
For security reasons, the only way to apply custom styling to iframe elements is to prepare and share a CSS file with the Gnosis Pay team. This file, named <partner_name>.css, will be incorporated into the iframe.Standard styling is applied to the iframe elements by default. You can override the style of these classes and IDs as needed. Here are some of them:
Here is a suggested workflow to customize the styling:
In your front-end, load the element you wish to customize (e.g., the card data).
Locate the custom CSS file with your name in either the “Style Editor” in Firefox or the “Sources” panel on Chrome/Brave. In the example below, the file is gnosis_pay_ui.css.
Apply your desired styling. The changes will be reflected in your interface immediately.
Save the file and send it to Gnosis Pay for application in production.
Here is an example of overriding the .pse-card-field class in Firefox: