Interaction with a Smart card via NFC and FIDO.
Component designed to handle interactions with Smart card via NFC by WebNFC or FIDO2. It provides a user interface for the interaction process and abstracts the complexity of communicating with these devices across different platforms (web browser, Android/iOS WebView).
Features
- Multi-platform Support: Works in standard web browsers (Chrome, Safari).
- Multiple Communication Protocols: Supports WebNFC and FIDO2 (WebAuthn) in browsers.
- Chunked Data Transfer: Handles large data payloads by splitting them into chunks for NFC communication.
- UI for User Guidance: Displays a modal window to guide the user through the process of tapping their card.
- Error Handling and Retries: Implements a retry mechanism for failed NFC read/write operations.
How it Works
To use the component, import it and place it on your page. Then, create a reference (ref) to the component — this reference allows you to call the nfcProgressHandler method. The method manages reading and writing data to the card and displays the visual interface for the NFC operation.
Exposed Methods
nfcProgressHandler(request, expectedSize, longNfc = false)
Description
Performs a single-step NFC interaction, where a single command/request is sent to the NFC card and a single response is received.
This is typically used for simple signing or data read/write operations.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
request | Uint8Array or object | ✅ Yes | The raw command/data to be sent to the NFC card. |
expectedSize | object | ✅ Yes | An object that must contain a parseResponse(responseBuffer) method, which transforms the NFC raw response (ArrayBuffer) into a readable format or parsed object. |
longNfc | boolean | ❌ Optional | Set to true if the NFC request is large and needs to be sent as a "long NFC request". |
nfcProgressChunksHandler(request, pinCode = null, longNfc = false)
Description
Handles multi-step (chunked) NFC interactions.
Used for larger transactions or signing processes that require sending multiple commands sequentially to the card.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
request | object | ✅ Yes | Must contain an array named chunks, where each chunk object defines how to build and process its NFC request/response. |
pinCode | string | null | ❌ Optional | The card PIN code, if required for authentication or signing. |
longNfc | boolean | ❌ Optional | Enables long NFC message mode for larger payloads. |
Chunk Object Structure
Each chunk inside request.chunks must implement two methods:
| Method | Description |
|---|---|
buildCardRequest({ pin }) | Async function that returns a Uint8Array representing the NFC command to send. |
processCardResponse(responseBuffer) | Function that processes the card’s response and prepares any necessary state for the next chunk. |
Props overview
These props allow you to customize its appearance, control its state, and handle error display from a parent component.
| Prop | Type | Default Value | Description |
|---|---|---|---|
modelValue | String | null | null | A standard prop for v-model usage. While declared, its direct implementation for data binding within the component's logic is not shown. |
title | String | null | 'Touch your card.' | The main title text displayed at the bottom of the handler window. This text guides the user on the primary action to take. It can be dynamically updated during retries. |
subTitle | String | null | 'Hold your card flat against the back of your device until this window is open.' | The subtitle text displayed below the main title. It provides more detailed instructions or context to the user. This also gets updated during retry attempts. |
errorMessage | String | null | null | A prop intended to receive an error message string. Its direct usage is not present in the template, but it's available for future implementation. |
error | String | null | null | Similar to errorMessage, this prop is designed to handle an error string passed from the parent. |
isActive | Boolean | true | Crucial for controlling the component. Use v-model:isActive to programmatically show or hide the NFC handler window. The component's internal logic watches this prop to start and stop the NFC process and manage its lifecycle. |
isLoading | Boolean | undefined | A prop intended to reflect a loading state. The component emits an update:isLoading event, suggesting it's designed to be used with v-model:isLoading for two-way binding with a parent component's state. |
Usage Example
Here’s how you would integrate and use the NFCHandlerWindow in a parent component to sign a transaction.
<template>
<div>
<button @click="signTransaction">Sign with NFC</button>
<!-- NFC handler window -->
<NFCHandlerWindow
v-model:isActive="isActive"
ref="nfcHandler"
:title="'Touch your card.'"
:subTitle="'Hold your card flat against your device until the window closes.'"
/>
</div>
</template>
<script setup>
import { ref } from 'vue'
import NFCHandlerWindow from '@/components/NFCHandlerWindow.vue'
import { TransactionSigner } from '@/api/card-communication.js'
const nfcHandler = ref(null)
const isActive = ref(false)
// Example transaction data
const transactionData = new Uint8Array([0x01, 0x02, 0x03, 0x04])
// Create a signer helper
const signer = new TransactionSigner(transactionData)
async function signTransaction() {
try {
// Build the raw NFC command
const request = signer.buildCardRequest()
// Start NFC operation
const result = await nfcHandler.value.nfcProgressHandler(
request, // raw data to send
{ parseResponse: signer.parseResponse }, // parser for the response
false // optional longNfc flag
)
console.log('✅ NFC operation completed successfully:', result)
} catch (error) {
console.error('❌ NFC operation failed:', error)
}
}
</script>