@sanjarbarakayev/vue-esignature
v2.0.0
Published
Vue 3 plugin for E-IMZO electronic digital signature (EDS) integration - Uzbekistan's national digital signature system
Maintainers
Readme
Vue E-Signature
Vue 3 plugin for E-IMZO electronic digital signature (EDS) integration - Uzbekistan's national digital signature system.
Features
- 🔐 Full E-IMZO Support - PFX certificates, USB tokens, BAIK tokens, CKC devices
- 🎯 Vue 3 Integration - Plugin and composable with full TypeScript support
- ⚡ Promise-based API - Modern async/await pattern
- 📦 Tree-shakeable - Import only what you need
- 🔒 Type-safe - Full TypeScript definitions included
Requirements
- Vue 3.3+
- E-IMZO Application installed on user's computer
- Download from: https://e-imzo.soliq.uz/download/
- Minimum version: 3.37
Installation
# npm
npm install @sanjarbarakayev/vue-esignature
# yarn
yarn add @sanjarbarakayev/vue-esignature
# pnpm
pnpm add @sanjarbarakayev/vue-esignatureQuick Start
1. Register the Plugin
// main.ts
import { createApp } from 'vue'
import { VueESignature } from '@sanjarbarakayev/vue-esignature'
import App from './App.vue'
const app = createApp(App)
app.use(VueESignature)
app.mount('#app')2. Use in Components
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useESignature, type Certificate } from '@sanjarbarakayev/vue-esignature'
const {
isInstalled,
isLoading,
error,
certificates,
install,
listKeys,
loadKey,
signData
} = useESignature()
const selectedCert = ref<Certificate | null>(null)
onMounted(async () => {
// Initialize E-IMZO
const success = await install()
if (!success) {
console.error('E-IMZO not installed:', error.value)
return
}
// Get available certificates
await listKeys()
})
const handleSign = async () => {
if (!selectedCert.value) return
try {
// Load the certificate key
const { id } = await loadKey(selectedCert.value)
// Sign data
const signature = await signData(JSON.stringify({ data: 'to sign' }))
console.log('Signature:', signature)
} catch (e) {
console.error('Signing failed:', e)
}
}
</script>
<template>
<div>
<div v-if="isLoading">Loading...</div>
<div v-else-if="error" class="error">{{ error }}</div>
<div v-else-if="isInstalled">
<select v-model="selectedCert">
<option v-for="cert in certificates" :key="cert.serialNumber" :value="cert">
{{ cert.CN }} ({{ cert.TIN }})
</option>
</select>
<button @click="handleSign" :disabled="!selectedCert">
Sign Document
</button>
</div>
<div v-else>E-IMZO not installed</div>
</div>
</template>Plugin Options
app.use(VueESignature, {
apiKeys: [
{ domain: 'myapp.example.com', key: 'YOUR_API_KEY_HERE' },
{ domain: 'api.example.com', key: 'ANOTHER_API_KEY' }
]
})API Reference
useESignature() Composable
Reactive State
| Property | Type | Description |
|----------|------|-------------|
| signer | ESignature | E-Signature instance |
| isInstalled | Ref<boolean> | Whether E-IMZO is initialized |
| isLoading | Ref<boolean> | Operation in progress |
| error | Ref<string \| null> | Current error message |
| certificates | Ref<Certificate[]> | Available certificates |
| loadedCert | Ref<Certificate \| null> | Loaded certificate |
| loadedKeyId | Ref<string \| null> | Current key ID |
Methods
| Method | Returns | Description |
|--------|---------|-------------|
| install() | Promise<boolean> | Initialize E-IMZO |
| listKeys() | Promise<Certificate[]> | Get certificates |
| loadKey(cert) | Promise<LoadKeyResult> | Load certificate key |
| signData(data, keyId?) | Promise<string> | Sign with loaded key |
| signWithUSB(data) | Promise<string> | Sign with USB token |
| signWithBAIK(data) | Promise<string> | Sign with BAIK token |
| signWithCKC(data) | Promise<string> | Sign with CKC device |
| checkUSBToken() | Promise<boolean> | Check USB connection |
| checkBAIKToken() | Promise<boolean> | Check BAIK connection |
| checkCKCDevice() | Promise<boolean> | Check CKC connection |
| clearError() | void | Clear error state |
| reset() | void | Reset all state |
ESignature Class
For direct class usage without the composable:
import { ESignature } from '@sanjarbarakayev/vue-esignature'
const signer = new ESignature()
// Add custom API keys
signer.addApiKey('myapp.example.com', 'API_KEY')
// Initialize
await signer.install()
// List certificates
const certs = await signer.listAllUserKeys()
// Load and sign
const { id } = await signer.loadKey(cert)
const signature = await signer.createPkcs7(id, data)Certificate Type
interface Certificate {
serialNumber: string; // Certificate serial number
validFrom: Date; // Validity start date
validTo: Date; // Validity end date
CN: string; // Common Name (owner's full name)
TIN: string; // Tax Identification Number (INN)
PINFL: string; // Personal ID Number
UID: string; // Unique Identifier
O: string; // Organization
T: string; // Title/Position
type: 'pfx' | 'ftjc'; // Certificate type
}Hardware Token Support
USB Token (ID Card)
const { checkUSBToken, signWithUSB } = useESignature()
const isPlugged = await checkUSBToken()
if (isPlugged) {
const signature = await signWithUSB(dataToSign)
}BAIK Token
const { checkBAIKToken, signWithBAIK } = useESignature()
const isPlugged = await checkBAIKToken()
if (isPlugged) {
const signature = await signWithBAIK(dataToSign)
}CKC Device
const { checkCKCDevice, signWithCKC } = useESignature()
const isPlugged = await checkCKCDevice()
if (isPlugged) {
const signature = await signWithCKC(dataToSign)
}Error Handling
const { install, error, clearError } = useESignature()
const success = await install()
if (!success) {
if (error.value?.includes('E-IMZO')) {
// E-IMZO not installed
showInstallPrompt()
} else if (error.value?.includes('version')) {
// Version too old
showUpdatePrompt()
}
clearError()
}Common Error Messages
| Message | Meaning | Solution | |---------|---------|----------| | "Ошибка соединения с E-IMZO" | E-IMZO not running | Install/start E-IMZO | | "ВНИМАНИЕ !!! Установите новую версию" | Version too old | Update E-IMZO | | "Пароль неверный" | Wrong password | Re-enter password | | "Браузер не поддерживает WebSocket" | Old browser | Update browser |
Key Caching
For better UX, cache the key ID to avoid repeated password prompts:
import Cookies from 'js-cookie'
const CACHE_KEY = `key_${cert.UID}`
const cachedKeyId = Cookies.get(CACHE_KEY)
if (cachedKeyId) {
try {
return await signData(data, cachedKeyId)
} catch {
// Key expired, reload
}
}
const { id } = await loadKey(cert)
Cookies.set(CACHE_KEY, id, { expires: 0.25 }) // 6 hoursTypeScript Support
Full TypeScript support with exported types:
import type {
Certificate,
PfxCertificate,
FtjcCertificate,
LoadKeyResult,
SignPkcs7Result,
VersionInfo,
ESignaturePluginOptions
} from '@sanjarbarakayev/vue-esignature'Browser Support
| Browser | Version | |---------|---------| | Chrome | 60+ | | Firefox | 55+ | | Edge | 79+ | | Safari | 11+ |
Note: WebSocket support required. Internet Explorer is not supported.
Security Notes
- API Keys - Keep API keys secure. Don't commit to public repositories.
- HTTPS - Use HTTPS in production (E-IMZO uses
wss://for secure connections). - Passwords - Certificate passwords are entered via E-IMZO native dialog, never in browser.
Troubleshooting
E-IMZO not detected
- Ensure E-IMZO application is installed
- Check if E-IMZO service is running
- Try restarting the browser
- Check firewall settings (ports 64443/64646)
No certificates found
- Check if certificates are installed in E-IMZO
- Verify certificate validity dates
- Ensure certificates have TIN or PINFL
Signing fails
- Check certificate expiration
- Verify password is correct
- Ensure key ID hasn't expired (reload if needed)
Contributing
Contributions are welcome! Please read our Contributing Guide for details.
License
MIT © Sanjar Barakayev
