React hook for E-IMZO digital signatures. Simple API, zero UI dependencies — works with any component library.
npm install @islom929/react-eimzoNo additional setup required. SDK is bundled and auto-injected.
import { EimzoProvider } from '@islom929/react-eimzo'
function App() {
return (
<EimzoProvider
apiKeys={['yourdomain.uz', 'YOUR_API_KEY_HERE']}
>
<YourApp />
</EimzoProvider>
)
}Default keys for localhost and 127.0.0.1 are always included.
import { useEimzo } from '@islom929/react-eimzo'
import type { ICertificate } from '@islom929/react-eimzo'
function SignDocument() {
const { sign, loadKeys, keyList, isInstalled, isLoading } = useEimzo()
const handleSign = (cert: ICertificate) => {
sign({
keyId: cert,
data: JSON.stringify({ document: 'content' }),
onSuccess: (pkcs7) => {
console.log('Signed:', pkcs7)
},
onError: (err) => {
console.error('Error:', err)
},
})
}
return (
<div>
<button
onClick={() => void loadKeys()}
disabled={!isInstalled || isLoading}
>
Load keys
</button>
{keyList.map((cert) => (
<button key={cert.serialNumber} onClick={() => handleSign(cert)}>
{cert.CN}
</button>
))}
</div>
)
}User selects a certificate from the list. E-IMZO app prompts for password.
import { useEimzo } from '@islom929/react-eimzo'
import type { ICertificate } from '@islom929/react-eimzo'
function PfxSign() {
const { sign, loadKeys, keyList, isInstalled, isLoading } = useEimzo()
const [result, setResult] = useState('')
useEffect(() => {
if (isInstalled) loadKeys()
}, [isInstalled])
const handleSign = (cert: ICertificate) => {
sign({
keyId: cert,
data: JSON.stringify({ orderId: 123, amount: 50000 }),
verifyPassword: true,
onSuccess: (pkcs7) => {
setResult(pkcs7)
// Send to backend
fetch('/api/verify', {
method: 'POST',
body: JSON.stringify({ pkcs7 }),
})
},
onError: (err) => {
alert(err) // "Ввод пароля отменен" if user cancels
},
})
}
return (
<div>
<h3>Select certificate:</h3>
{keyList.map((cert, i) => (
<div key={`${cert.serialNumber}-${i}`}>
<p>{cert.CN} — {cert.O}</p>
<p>PINFL: {cert.PINFL} | STIR: {cert.TIN}</p>
<p>Valid until: {new Date(cert.validTo).toLocaleDateString()}</p>
<button
onClick={() => handleSign(cert)}
disabled={cert.expired || isLoading}
>
{cert.expired ? 'Expired' : 'Sign'}
</button>
</div>
))}
</div>
)
}No certificate selection needed. Pass device type directly. Device status is checked automatically on mount.
function TokenSign() {
const { sign, deviceStatus, isLoading } = useEimzo()
const handleTokenSign = (device: 'idcard' | 'baikey' | 'ckc') => {
sign({
keyId: device,
data: JSON.stringify({ document: 'content' }),
onSuccess: (pkcs7) => console.log('Signed:', pkcs7),
onError: (err) => console.error(err),
})
}
return (
<div>
<button
onClick={() => handleTokenSign('idcard')}
disabled={!deviceStatus.idcard || isLoading}
>
ID Card {deviceStatus.idcard ? '(connected)' : '(not connected)'}
</button>
<button
onClick={() => handleTokenSign('baikey')}
disabled={!deviceStatus.baikey || isLoading}
>
BAIK Token {deviceStatus.baikey ? '(connected)' : '(not connected)'}
</button>
<button
onClick={() => handleTokenSign('ckc')}
disabled={!deviceStatus.ckc || isLoading}
>
CKC {deviceStatus.ckc ? '(connected)' : '(not connected)'}
</button>
</div>
)
}function EimzoStatus() {
const { isInstalled, error, version } = useEimzo()
if (error) {
return (
<div>
<p style={{ color: 'red' }}>{error}</p>
<a href="https://e-imzo.uz/main/downloads/">Download E-IMZO</a>
</div>
)
}
if (!isInstalled) {
return <p>Loading...</p>
}
return <p>E-IMZO v{version?.major}.{version?.minor} ready</p>
}Errors from E-IMZO SDK are passed directly to onError. Common errors:
sign({
keyId: cert,
data: '...',
onSuccess: (pkcs7) => { /* success */ },
onError: (err) => {
// err contains the SDK error message:
// "Ввод пароля отменен" — user cancelled password dialog
// "BadPaddingException" — wrong password
// Other SDK-native errors
console.error(err)
},
})| When | Error | Description |
|---|---|---|
| Install | "E-IMZO не запущен. Убедитесь, что приложение E-IMZO установлено и запущено." |
E-IMZO app is not running or not installed |
| Install | "Версия E-IMZO устарела (X.XX). Минимальная версия: 3.36" |
E-IMZO version is too old |
| loadKeys | "Please install new version of E-IMZO" |
SDK version check failed |
| sign | "Ввод пароля отменен" |
User cancelled password dialog |
| sign | "BadPaddingException" |
Wrong password entered |
| sign | WebSocket error code (number) | Connection to E-IMZO lost |
The package automatically checks E-IMZO version on mount. Minimum required version is 3.36.
function VersionInfo() {
const { version, isInstalled } = useEimzo()
if (!isInstalled || !version) return null
const v = parseInt(version.major) * 100 + parseInt(version.minor)
return (
<div>
<p>E-IMZO v{version.major}.{version.minor}</p>
<p>PFX: supported</p>
<p>ID-card: {v >= 412 ? 'supported' : 'not supported (need v4.12+)'}</p>
<p>BAIK/CKC: {v >= 486 ? 'supported' : 'not supported (need v4.86+)'}</p>
</div>
)
}E-IMZO version determines which key types are available:
| Version | PFX | ID-card | BAIK | CKC |
|---|---|---|---|---|
| v3.36+ | yes | no | no | no |
| v4.12+ | yes | yes | no | no |
| v4.86+ | yes | yes | yes | yes |
Wraps your app. Initializes E-IMZO SDK automatically.
| Prop | Type | Description |
|---|---|---|
apiKeys |
string[] |
Optional. Additional domain + API key pairs |
children |
ReactNode |
Required |
| Property | Type | Description |
|---|---|---|
isInstalled |
boolean |
E-IMZO app detected and running |
isLoading |
boolean |
Key loading, preparation, or signing is in progress |
error |
string | null |
Latest E-IMZO operation error, null if OK |
version |
IEimzoVersion | null |
E-IMZO version { major, minor } |
keyList |
ICertificate[] |
Available certificates |
deviceStatus |
IDeviceStatus |
Connected hardware devices |
loadKeys |
(options?) => Promise<void> |
Load certificates into keyList; cached unless force is true |
reloadKeys |
(options?) => Promise<void> |
Force-refresh certificates; rejects if the refresh fails |
prepareKey |
(certificate, verifyPassword?) => Promise<string> |
Load a certificate and optionally verify its password/PIN |
signAsync |
(params) => Promise<string> |
Promise-first signing API; resolves with PKCS#7 |
sign |
(params: ISignParams) => void |
Sign data |
Device status (idcard, baikey, ckc) is probed in the background once
installation succeeds. A slow or unavailable hardware probe does not block
PFX key loading or signing.
| Param | Type | Description |
|---|---|---|
keyId |
ICertificate | string |
Certificate object or 'idcard' / 'baikey' / 'ckc' |
data |
string |
Data to sign (usually JSON.stringify) |
verifyPassword |
boolean |
Optional. Verify PFX password or FTJC PIN before signing |
onSuccess |
(pkcs7: string) => void |
Called with base64 PKCS#7 signature |
onError |
(error: string) => void |
Optional. Called on failure |
Use signAsync when the surrounding code already uses async/await:
const { signAsync } = useEimzo()
const pkcs7 = await signAsync({
keyId: certificate,
data: JSON.stringify(payload),
verifyPassword: true,
})Use prepareKey(certificate, true) when password/PIN verification must happen
before another operation, such as requesting a short-lived server challenge.
Pass the returned key ID string to signAsync.
loadKeys({ includeLegacyTokens: true }) includes legacy FTJC certificates.
Use reloadKeys(...) when a certificate or token may have been attached after
the first list operation.
Starting with v0.6, the bundled SDK no longer modifies native Date.prototype
or String.prototype objects. The documented React API (EimzoProvider,
useEimzo, loadKeys, and sign) is unchanged.
Applications that used undocumented SDK globals directly must migrate:
- Use an application-local date formatter instead of legacy date extensions.
- Use
Base64.encode(value)/Base64.decode(value)instead of legacy string extensions. - The legacy certificate-field splitting extension was internal and has no public replacement.
Install is deduplicated per page load. Parallel mounts (including React
StrictMode double-invocation) share one installation promise. A failed
attempt is cleared, so a later key load can retry after the user starts E-IMZO.
loadKeys() is cached. Once the first successful call populates keyList,
later calls resolve immediately. Use reloadKeys() or
loadKeys({ force: true }) for a fresh device/certificate list. Requesting
includeLegacyTokens: true also refreshes a cache that only contains PFX
certificates. For compatibility with v0.5, loadKeys() records an error but
resolves after a failed load; the new reloadKeys() API rejects so callers can
handle refresh failures explicitly.
apiKeys are managed as domain/key pairs. Reusing a domain during a later
provider initialization updates its key instead of corrupting the flat SDK key
list. Treat apiKeys as initialization configuration rather than a frequently
changing prop.
import type {
ICertificate,
ILoadKeysOptions,
ISignAsyncParams,
ISignParams,
IDeviceStatus,
IEimzoContext,
IEimzoProviderProps,
IEimzoVersion,
TKeyType,
} from '@islom929/react-eimzo'| Field | Type | Description |
|---|---|---|
major |
string |
Major version (e.g. "4") |
minor |
string |
Minor version (e.g. "86") |
| Field | Type | Description |
|---|---|---|
CN |
string |
Full name |
PINFL |
string |
Personal ID number |
TIN |
string |
Tax ID (STIR) |
O |
string |
Organization |
T |
string |
Title/Position |
UID |
string |
User ID |
serialNumber |
string |
Certificate serial number |
validFrom |
Date |
Start of validity |
validTo |
Date |
End of validity |
type |
'pfx' | 'ftjc' |
Certificate type |
expired |
boolean |
Whether certificate has expired |
| Field | Type | Description |
|---|---|---|
idcard |
boolean |
ID card / EIMZO-Token connected |
baikey |
boolean |
BAIK-Token connected |
ckc |
boolean |
CKC device connected |
| Type | Description | E-IMZO Version |
|---|---|---|
| PFX | Local certificate file (ERI) | v3.36+ |
| ID-card / EIMZO-Token | Physical smart card | v4.12+ |
| BAIK-Token | BAIK hardware token | v4.86+ |
| CKC | CryptKeyContainer (universal) | v4.86+ |
Your React App
↓ useEimzo()
@islom929/react-eimzo
↓ WebSocket (wss://127.0.0.1:64443)
E-IMZO Desktop App
↓
PFX files / USB tokens / ID cards
- Package injects E-IMZO SDK into the page automatically
- SDK connects to E-IMZO desktop app via WebSocket
loadKeys()fetches available certificatessign()sends data to E-IMZO app for signing- E-IMZO app prompts user for password/PIN
- Signed PKCS#7 (base64) returned via
onSuccess
- React 18+
- E-IMZO desktop application installed on user's computer
MIT