Transaction Confirmation Guide
Overview
Transaction confirmation is a way to dynamically capture customer consent specific for a given action, which provides verifiable proof the customer consented to a given action using FIDO certified authentication.
Transaction confirmation requires a backend API call, therefore it is recommended to leverage the LoginID server SDK. However, the LoginID APIs can be called directly if required.
Prerequisites
- Create an application on LoginID Dashboard
- Download Client SDK
- Download Server SDK (optional)
With Server SDK
Step 1: Create Transaction
When the contents of the transaction is finalized, you must call LoginID to generate a transaction identifier.
The tx_payload
should be persisted on your backend to be able to verify the transaction at the end of the flow.
Server SDK: .createTx(tx_payload, nonce?)
If desired, you can include a unique identifier for the transaction in the form of a nonce
.
This method creates the transaction in our system, and returns a tx_id
. This identifier must be passed to your front end for use in Step 2.
Step 2: Confirm Transaction
Client SDK: .confirmTransaction(tx_id)
This method will prompt the customer to authenticate using their FIDO2 credential. When the user authenticates, the user’s private key signs the tx_challenge
, generating a verifiable signature. The tx_challenge
is a combination of the hash of the tx_payload
, nonce
, and server_nonce
.
LoginID stores the signature, nonce, server_nonce, and payload hash for 2 years to allow for clients to resolve dispute claims.
The result of this operation is a transaction token, in the form of a JWT signed by LoginID.
The LoginID SDK does not display the raw transaction information to the user, it only prompts for FIDO authentication. It is your responsibility to display the transaction information.
Step 3: Verify Result
The JWT returned in Step 2 can be validated through the Server SDK.
Server SDK: .verifyTransaction(jwt)
With Client SDK Only
Step 1: Create and Confirm Transaction
When the details of the transaction are finalized, you can call LoginID with the transaction information, and the SDK will prompt the user for verification and return back a signed token.
Client SDK: .createAndConfirmTransaction(username, tx_payload, nonce?, authorization_token?)
The tx_payload
should be persisted on the client backend to be able to verify the transaction at the end of the flow.
If an API credential is assigned to this integration, you must first generate an authorization token. You can do that using the .generateTxAuthToken
server SDK method or by generating the token on your backend yourself. If a token is provided, a nonce must not be provided.
This method will prompt the customer to authenticate using their FIDO2 credential. When the user authenticates, the user’s private key signs the tx_challenge
, generating a verifiable signature. The tx_challenge
is a combination of the payload_hash
, nonce
, and server_nonce
.
LoginID stores the signature, nonce, server_nonce, and payload hash for 2 years to allow for clients to resolve dispute claims.
The result of this operation is a transaction token, in the form of a JWT signed by LoginID.
The LoginID SDK does not display the raw transaction information to the user, it only prompts for FIDO authentication. It is your responsibility to display the transaction information.
Step 2: Verify Result
The JWT returned in Step 1 can be validated in two ways: using the server SDK or the LoginID public key. The server SDK method is:
Server SDK: .verifyTransaction(tx_token, tx_payload)
The LoginID public key can be obtained:
curl https://jwt.[base url]/certs?kid=<key id here>
where the kid is obtained from the JWT header:
{
"alg": "ES256",
"typ": "JWT",
"kid": "<example kid>"
}
Once the public key has been obtained, this can be used to verify the original transaction payload. The JWT returned from the createAndConfirmTransaction SDK methods is of the form:
{
"iss": "loginid.io",
"sub": "d285bd82-6da8-47dd-a8d5-af44cb462faf",
"aud": "a93791e15ef07929",
"nid": "a93791e15ef07929",
"iat": <issue date of the token>,
"username": "<username>",
"action": "tx_confirmation",
"nonce": "<client generated nonce, only included in response if provided in request>",
"server_nonce": "<loginID generated nonce>",
"tx_hash": "<hased transaction value>"
}
The tx_hash
is generated using the following formula:
- If
nonce
is provided:tx_hash = base64url(sha256(tx_payload + nonce + server_nonce))
- If
nonce
is not provided:tx_hash = base64url(sha256(tx_payload + server_nonce))
Where the tx_payload
value is the tx_payload
sent in the createAndConfirmTransaction
method.
Calling APIs Directly (i.e. no Server SDK)
Step 1: Create Transaction
An Auth token must be created before calling the LoginID endpoint to initiate the transaction confirmation flow. This token is sent as the Authorization header.
{
"scope": "tx.create",
"nonce": <generated nonce value>,
"payload_hash": <hashed and encoded raw_tx_payload>,
"iat": <long unix time in seconds>
}
where payload_hash
is the base64 URL safe encoded value of the hashed (SHA256) tx_payload
. The tx_payload
is the transaction information in string format.
The tx_payload
should be persisted on the client backend to be able to verify the transaction at the end of the flow.
Auth token header:
{
"alg": "ES256",
"typ": "JWT"
}
Once the token is created, it must be signed with the ES256 algorithm using your API_PRIVATE_KEY
.
Request:
POST /tx
Header:
Authorization: Bearer <auth_token>
Body:
{
"client_id": <string >
"tx_payload": <string>
"nonce": <string>
}
Response:
tx_id
Step 2: Confirm Transaction
Client SDK: .confirmTransaction(tx_id)
This method will prompt the customer to authenticate using their FIDO2 credential. When the user authenticates, the user’s private key signs the tx_challenge
, generating a verifiable signature. The tx_challenge
is a combination of the hash of the tx_payload
, nonce
, and server_nonce
.
LoginID stores the signature
, nonce
, server_nonce
, and hashed tx_payload
for 2 years to allow for clients to resolve dispute claims.
The result of this operation is a transaction token, in the form of a JWT signed by LoginID.
The LoginID SDK does not display the raw transaction information to the user, it only prompts for FIDO authentication. It is your responsibility to display the transaction information.
Step 3: Verify result
The JWT returned in Step 2 can be validated using LoginID's public key, which can be obtained:
curl https://jwt.[base url]/certs?kid=<key id here>
For example, the URL for the LoginID sandbox environment is:
curl https://jwt.sandbox-usw1.api.loginid.io/certs?kid=<key id here>
where the kid
is obtained from the JWT header:
{
"alg": "ES256",
"typ": "JWT",
"kid": "<example kid>"
}
Once the public key has been obtained, this can be used to verify the original transaction payload. The JWT returned from the create/confirm SDKs methods is of the form:
{
"iss": "loginid.io",
"sub": "d285bd82-6da8-47dd-a8d5-af44cb462faf",
"aud": "a93791e15ef07929",
"nid": "a93791e15ef07929",
"iat": <issue date of the token>,
"username": "<username>",
"action": "tx_confirmation",
"nonce": "<client generated nonce>",
"server_nonce": "<loginID generated nonce>",
"tx_hash": "<hashed transaction value>"
}
The tx_hash
is generated using the following formula:
tx_hash = base64url(sha256(tx_payload + nonce + server_nonce))
Where the tx_payload
value is the tx_payload
sent in the POST /tx
call.