npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

arca-cert

v0.1.0

Published

Generá certificados para los web services de ARCA (ex AFIP) con solo tu CUIT y clave fiscal

Downloads

127

Readme

arca-cert

Generá certificados para los web services de ARCA (ex AFIP) con solo tu CUIT y clave fiscal.

Sin proxies, sin servicios de terceros, sin Chrome. Todo se ejecuta localmente.

Instalación

npm install arca-cert

Uso rápido

import { createCertificate, authenticate } from 'arca-cert';

// 1. Crear certificado
const { cert, key } = await createCertificate({
  cuit: '20123456789',
  password: process.env.CLAVE_FISCAL!,
  alias: 'mi-sistema',
  environment: 'production',
});

// 2. Autenticarse con un web service
const credentials = await authenticate({
  cert,
  key,
  service: 'wsfe',
  environment: 'production',
});

// credentials.token y credentials.sign están listos para usar

API

createCertificate(options)

Crea un certificado nuevo. Genera la clave RSA y el CSR localmente, se logea al portal de ARCA, y obtiene el certificado firmado.

const result = await createCertificate({
  cuit: '20123456789',         // 11 dígitos (acepta guiones)
  password: 'mi-clave-fiscal', // Clave fiscal nivel 2+
  alias: 'mi-sistema',         // Alfanumérico, guiones y guiones bajos
  environment: 'production',   // 'testing' o 'production' (default: 'testing')
  organization: 'Mi Empresa',  // Opcional (default: "CUIT {cuit}")
  debug: true,                 // Opcional, muestra logs de cada paso
});

result.cert        // string — Certificado X.509 PEM
result.key         // string — Clave privada RSA 2048 PEM
result.alias       // string
result.cuit        // string
result.environment // 'testing' | 'production'

renewCertificate(options)

Crea un certificado nuevo con un alias con sufijo timestamp. ARCA no permite revocar por API, así que la renovación crea uno nuevo y el viejo expira solo.

const renewed = await renewCertificate({
  cuit: '20123456789',
  password: process.env.CLAVE_FISCAL!,
  alias: 'mi-sistema',
  environment: 'production',
});
// renewed.alias → 'mi-sistema-r1743220800'

authenticate(options)

Autentica con WSAA usando un certificado existente. Devuelve token + sign válidos por ~12 horas.

const credentials = await authenticate({
  cert: certPem,
  key: keyPem,
  service: 'wsfe',
  environment: 'production',
});

credentials.token          // string — Token para Auth header
credentials.sign           // string — Firma para Auth header
credentials.expirationTime // Date — Válido ~12 horas

getCertExpiry(certPem)

Parsea un certificado X.509 y devuelve sus fechas de validez.

import { getCertExpiry } from 'arca-cert';

const { notBefore, notAfter } = getCertExpiry(certPem);
const daysLeft = Math.floor((notAfter.getTime() - Date.now()) / 86_400_000);
if (daysLeft < 30) {
  await renewCertificate({ ... });
}

parseSoapFault(body)

Parsea respuestas SOAP Fault de ARCA en un error estructurado. Útil si hacés llamadas SOAP propias (wsfe, padrón, etc.) fuera del SDK.

import { parseSoapFault } from 'arca-cert';

const error = parseSoapFault(soapResponseXml);
if (error) {
  console.log(error.message);                // "WSAA: Certificado no emitido..."
  console.log(error.code);                   // "WSAA_ERROR"
  console.log(error.soapFault?.faultcode);   // "cms.cert.untrusted"
  console.log(error.soapFault?.faultstring); // "Certificado no emitido por AC de confianza"
}

validateCuit(cuit)

Valida formato y dígito verificador de un CUIT argentino.

import { validateCuit } from 'arca-cert';

validateCuit('20278650988');    // '20278650988'
validateCuit('20-27865098-8');  // '20278650988' (acepta guiones)
validateCuit('12345678901');    // throws ArcaCertError (dígito verificador inválido)

Uso avanzado

import { generateCSR, signTRA, loginWsaa } from 'arca-cert';

// Generar CSR sin crear certificado (para subir manualmente al portal)
const { csr, keyPair } = generateCSR('20123456789', 'mi-alias', 'Mi Empresa SA');

// Firmar TRA para WSAA manualmente
const signedCms = signTRA(traXml, certPem, privateKeyPem);

// Login WSAA directo
const credentials = await loginWsaa(certPem, keyPem, 'wsfe', 'production');

Servicios WSAA

| Servicio | Descripción | |---|---| | wsfe | Factura electrónica (WSFEv1) | | wsfex | Factura electrónica de exportación | | ws_sr_padron_a4 | Padrón alcance 4 | | ws_sr_padron_a5 | Padrón alcance 5 | | ws_sr_padron_a10 | Padrón alcance 10 | | ws_sr_padron_a13 | Padrón alcance 13 | | ws_sr_constancia_inscripcion | Constancia de inscripción |

También acepta cualquier string para servicios no listados.

Ambientes

| Ambiente | Login | Certificados | WSAA | | --- | --- | --- | --- | | testing | authhomo-ext.afip.gob.ar | WSASS (wsass-homo.afip.gob.ar) | wsaahomo.afip.gov.ar | | production | auth.afip.gob.ar | arfe_certificado (serviciosweb.afip.gob.ar) | wsaa.afip.gov.ar |

Los certificados de un ambiente no funcionan en el otro.

Manejo de errores

Todos los errores son ArcaCertError con code tipado y, para errores SOAP, un soapFault con el detalle original de ARCA:

import { ArcaCertError } from 'arca-cert';

try {
  await authenticate({ ... });
} catch (err) {
  if (err instanceof ArcaCertError) {
    console.log(err.code);    // Código tipado
    console.log(err.message); // Mensaje legible con hint

    if (err.soapFault) {
      // Detalle original de ARCA
      console.log(err.soapFault.faultcode);   // "coe.notAuthorized"
      console.log(err.soapFault.faultstring); // "Computador no autorizado..."
    }
  }
}

Códigos de error

| Código | Descripción | |---|---| | INVALID_CUIT | CUIT con formato o dígito verificador inválido | | INVALID_ALIAS | Alias con caracteres no permitidos o muy largo | | INVALID_SERVICE | Nombre de servicio WSAA inválido | | LOGIN_FAILED | Credenciales incorrectas o cuenta bloqueada | | PORTAL_ERROR | Error en el portal de ARCA | | WSAA_ERROR | Error SOAP de WSAA (ver soapFault para detalle) | | WSASS_ERROR | Error en la creación del certificado | | CERTIFICATE_ERROR | CSR rechazado, alias duplicado, etc. | | CRYPTO_ERROR | Error criptográfico (claves, firma, parseo) | | NETWORK_ERROR | Timeout o fallo de red | | SESSION_EXPIRED | Sesión del portal expirada | | UNSAFE_URL | URL no HTTPS o fuera de dominio ARCA |

SOAP faults conocidos

| Faultcode | Significado | Hint | | --- | --- | --- | | cms.cert.untrusted | Cert no emitido por ARCA | Verificar ambiente (testing vs production) | | coe.notAuthorized | Cert no autorizado para el servicio | Asociar en "Administrador de Relaciones" | | cms.sign.invalid | Firma CMS inválida | Verificar par cert/key | | cms.cert.expired | Cert expirado | Crear uno nuevo | | cms.cert.revoked | Cert revocado | Crear uno nuevo | | coe.alreadyAuthenticated | Ya hay ticket activo | Esperar expiración | | coe.ticketExpired | Ticket expirado | Re-autenticar |

Seguridad

  • HTTPS obligatorio — todas las conexiones validan protocolo y dominio (solo *.afip.gob.ar / *.afip.gov.ar)
  • Credenciales seguras — nunca se loguean, almacenan en disco, ni se incluyen en errores
  • Clave privada local — se genera en tu máquina y nunca sale de ella
  • Validación de entrada — CUIT (con dígito verificador), alias (alfanumérico), servicio (previene XML injection)
  • Timeouts — 120 segundos por defecto en todas las requests HTTP
  • Retry — 3 intentos con backoff en el login del portal (solo errores de red, no credenciales)
  • Sin dependencias de red — no usa proxies ni servicios de terceros

Ver SECURITY.md para más detalles.

Cómo funciona

Producción

  1. Genera clave RSA 2048 bits + CSR (PKCS#10) localmente con node-forge
  2. Login al portal ARCA (JSF forms con ViewState + captcha + JWT)
  3. Obtiene token para arfe_certificado via API del portal
  4. Navega a "Administración de Certificados Digitales"
  5. Sube alias + CSR como archivo (multipart/form-data)
  6. Clickea "Ver" en el certificado creado (ASP.NET __doPostBack)
  7. Descarga el certificado PEM
  8. Devuelve cert + key

Testing

Igual pero usa WSASS (wsass-homo.afip.gob.ar) con un formulario de un solo paso.

Requisitos

  • Node.js >= 18
  • Clave fiscal nivel 2 o superior
  • Tener el servicio de certificados habilitado en el portal de ARCA

Licencia

MIT