Pocas llamadas.
Cualquier plataforma.

Identity Layer se integra con una superficie mínima por diseño. MicroPython en un microcontrolador, Flutter en Android y Windows, o un PHP bridge colocado en sus puntos finales existentes. El mismo protocolo. Las mismas garantías criptográficas. Cuatro llamadas.

Raspberry Pi Pico 2W, PN532 NFC reader, SSD1306 OLED display, NTAG424 DNA card
Boot
Registering
Node exists
Verified
Challenge
Active
Cuatro llamadas operativas. WiFi, OLED y carga de configuración son infraestructura del dispositivo, no Identity Layer. La identidad primitiva es IdentityIoT, instalado a través de mip.
MicroPython
# Install via mip — no external dependencies
# import mip; mip.install("github:wide/identity-micropython")

from identity_iot import IdentityIoT

# 1. Init — configure node identity
identity = IdentityIoT(
    base_url  = cfg['base_url'],
    node_type = cfg['node_type'],
    tenant_id = cfg['tenant_id'],
    comm_key  = cfg['comm_key'].encode(),
    comm_iv   = cfg['comm_iv'].encode(),
)

# 2. Register — device-bound key, runs once
identity.ensure_registered()

# 3. Authenticate — Ed25519 challenge / verify / JWT
token = identity.authenticate()

# 4. Authenticated request — AES-256-GCM encrypted payload
response = identity.post_encrypted({'request': 'record_sensor_data', 'value': 42})
Componente Modelo Role
MCU Raspberry Pi Pico 2W (RP2350) TrustZone, WiFi, almacenamiento de claves device-bound
NFC reader PN532 Interfaz I2C, lee insignias NTAG424 DNA
Mostrar SSD1306 128x64 OLED Secuencia de inicio, estado de verificación
NFC badge NTAG424 DNA (NXP) AES-128 integrado, claves no exportables, dinámicas CMAC
Las implementaciones de referencia ESP32 y RP2040 para centros de datos y verticales de acceso físico están en progreso. El protocolo y el SDK son idénticos en todo el hardware compatible.

Los nodos Identity IoT no están limitados al acceso NFC. El mismo node autenticado puede transportar cualquier carga útil del sensor. Todas las lecturas se transmiten a través de AES-256-GCM POST cifrado después de que el node obtiene su JWT.

Tipo de sensorHardware típicoCampo de carga útil
TemperaturaDHT22, DS18B20, BME280temperatura (flotación, °C)
HumedadDHT22, BME280humedad (flotación,%)
PresiónBME280, BMP390presión (flotación, hPa)
movimiento PIRHC-SR501movimiento (booleano)
GPSNEO-6M, L76Xlat, lon, altitud (flotación)
Medición de energíaPZEM-004T, INA219voltaje, corriente, potencia (flotación)
NFC accesoPN532 + NTAG424 DNABadge_uid, concedido (bool)
JSON (descifrado)
{
  "node_uid"   : "273ec83a-84c8-4967-aafa-0780ab161cc1",
  "tenant_id"  : "0b3cfe4d-fdf7-46c2-bd41-b533da415dd9",
  "node_type"  : "sensor",
  "temperature": 24.3,
  "humidity"   : 58.1,
  "pressure"   : 1013.2,
  "updated_at" : "2026-06-09 11:42:07"
}

Badge leer. Reto emitido.
Ed25519 verificado.

Identity Tag es la capa de aplicación construida sobre Identity IoT. Cada lectura de badge desencadena un ciclo Ed25519 challenge/response completo contra el backend. No hay secretos almacenados en el reader. No hay identidad de texto claro en el badge. Multi-tenant por diseño.

Badge a GRANTED en cuatro pasos. El reader (Pico 2W + PN532) es un Identity IoT node autenticado. El badge lleva un fragmento de clave privada cifrado AES-CBC y un DEK dividido. El backend emite un desafío, recibe una firma Ed25519, la verifica y devuelve GRANTED o DENIED. Ningún secreto atraviesa el cable en texto sin cifrar. No existe ninguna base de datos de credenciales.
Flujo: badge leer para acceder a la decisión
# 1. Reader reads NTAG424 DNA NDEF payload
#    Fields: epk (encrypted private key), df2 (DEK fragment 2), mode (STD|HS)

# 2. DEK reconstruction
dek = df1_from_config XOR df2_from_badge

# 3. Decrypt badge private key
badge_privkey = AES_CBC_decrypt(dek, epk)

# 4. Request challenge from backend
challenge = POST identity_tag/it_request_challenge
#    { node_uid, badge_uid, tenant_id }

# 5. Sign challenge with badge key (Ed25519)
signature = ed25519_sign(badge_privkey, challenge_nonce)

# 6. Verify at backend
result = POST identity_tag/it_verify_badge
#    { challenge_id, signature_b64 }  ->  { granted: true }

# 7. Reader actuates relay (GRANTED) or displays DENIED
ModoDescripciónCaso de uso
STD Badge trabaja en cualquier terminal de la flota autorizada para ese tenant. Acceso a oficinas, puntos de entrada generales.
HS Badge vinculado criptográficamente a un terminal específico. La derivación DEK incorpora un hash de la clave pública del terminal. Badge no es válido en ningún otro reader. Salas de alta seguridad, racks de centros de datos, gabinetes de equipos.
Cada tenant tiene un espacio de nombres aislado: su propia flota node, registro badge, árbol de grupos y tabla de derechos. Un badge registrado a Tenant A no puede ser verificado por un node perteneciente a Tenant B. El aislamiento Tenant se aplica en el nivel de consulta de la base de datos, no solo a través de la lógica de la aplicación.
Punto finalMétodoRole
identity_tag/it_request_challengePOSTEmitir nonce para la verificación badge
identity_tag/it_verify_badgePOSTVerifique la firma Ed25519, devuelva GRANTED/DENIED
identity_tag/it_node_checkinPOSTNode latido y JWT actualización
identity_tag/it_register_badgePOST (manager)Escriba badge clave pública y derecho
identity_tag/it_list_nodesGET (manager)Node estado de la flota para tenant

La aplicación de aprovisionamiento y gestión se ejecuta en Android. Utiliza el NFC del dispositivo para escribir cargas útiles badge. y se conecta al backend a través de canales Identity Layer autenticados.

Dart / Flutter: badge escribir
// identity_tag package - badge provisioning
final writer = IdentityTagWriter(api: tagApi);

// Generate badge keypair and encrypt private key with split DEK
final payload = await writer.prepareBadgePayload(
  tenantId  : tenant.id,
  mode      : BadgeMode.STD,   // or BadgeMode.HS
  nodeUid   : null,              // required for HS mode
);

// Write NDEF to NTAG424 DNA via flutter_nfc_kit
await writer.writeToTag(payload);

Identidad vinculada al dispositivo.
Cuatro llamadas.

Paquetes locales. Sin servicio de identidad externo. La clave privada nunca sale del dispositivo. Almacenamiento seguro mediante flutter_secure_storage y TEE / Secure Enclave cuando esté disponible. El cifrado de carga útil es de extremo a extremo a través de ITEMSEncrypter.

identity_package identity_std identity_hs items_crypto items_search items_document_body
Todos los paquetes son locales. No hay dependencias de pub.dev en la capa de identidad. El SDK se distribuye como parte del paquete de licencia.
Dart / Flutter
// 1. Init — JWT identity, silent on subsequent boots
final auth = IdentityAuthServiceStd(ITEMSGlobals.authURI);
await auth.ensureJwt(
  preferredLocale: locale.languageCode,
  utcOffsetMin:    DateTime.now().timeZoneOffset.inMinutes,
);

// 2. Handshake — silent if identity already present on device
final result = await api.mjHandshake(
  identityHash: identityHash,
  publicKey:    publicKey,
);

// 3. Store JWT — session active, no password, no credential database
await _storage.write(key: 'token', value: result['token']);

// 4. Every request — AES-256-GCM payload, end-to-end encrypted
final response = await api.postEncrypted({'request': 'your_request'});
YAML
dependencies:

  # Identity Layer — local packages, no external registry
  identity_package:
    path: packages/identity_package
  identity_std:
    path: packages/identity_std
  identity_hs:
    path: packages/identity_hs
  items_crypto:
    path: packages/items_crypto
PlataformaEstadoAlmacenamiento seguro
AndroideProducción, Google Play autorizadaAlmacén de claves de Android / TEE
ventanasProducción, Microsoft Store autorizadaAdministrador de credenciales de Windows
linuxProducciónlibresecreto
iOS/macOSEn la hoja de rutaSecure Enclave

5 KB.
Tu pila, sin cambios.

El PHP bridge es un requisito único que se encuentra frente a sus puntos finales existentes. Tus rutas, tu base de datos, tu lógica de negocio. Intacto.. Identity Layer maneja la autenticación y el cifrado de la carga útil. Elimínelo de la misma manera que lo agregó.

Entrada, salida. Uno require_once y dos llamadas a funciones. Sus puntos finales comienzan a recibir cargas útiles verificadas y descifradas. Sin migración de esquema. No hay cambios en la tabla de usuarios. Sin almacenamiento de sesión. La pila completa del lado del servidor es 225KB.
PHP
// 1. Include the Identity Layer bridge — 5 KB
require_once 'identity/_mj_auth.php';

// 2. Authenticate — JWT verified, identity_hash extracted
//    identity_hash is a 64-char SHA-256 hex — never a user ID
[$identityHash, $tenantId, $claims, $role] =
    mj_authenticate_identity($encoder);

// 3. Every response — AES-256-GCM encrypted, end-to-end
sendEncryptedResponse($encoder, [
    'status' => 'ok',
    'data'   => $yourData,
], ['ts' => time()], 200);
Los registros de auditoría existen pero son inaccesibles criptográficamente. El acceso requiere una orden judicial validada. El mj_mandate_log punto final registra el mandato y abre una ventana de exportación de 72 horas. Los registros se destruyen después de su recolección. La autoridad requirente asume la responsabilidad legal.
PHP: mj_mandate_log
// Requires role = admin — never operator
[$userId, $tenantId, $claims, $role] = mj_authenticate($encoder);
mj_require_role($encoder, $claims, 'admin');

// Register mandate — opens 72h export window
// target_identity_hash: 64-char SHA-256, never plaintext identity
// Ciphertext is never stored — metadata only
$connector->executeDatabaseParameterQuery(
    "INSERT INTO audit_log (mandate_number, issuing_country,
     issuing_court, target_identity_hash, export_status)
     VALUES (?, ?, ?, ?, 'PENDING')",
    [$mandateNumber, $issuingCountry, $issuingCourt, $targetHash],
    $db
);
ComponenteTecnologíaNotas
Tiempo de ejecuciónPHP 8.xVainilla, no requiere marco.
Base de datosMySQL / MaríaDBEsquema estándar, sin columnas de credenciales
Caché / efímeroRedisTokens de desafío, colas de mensajes (TTL < 1 min)
Tamaño del puente5 KBArchivo único PHP, colocarlo en cualquier pila LAMP
Tamaño de pila completo225KBIdentidad STD + HS + Claves + Canal Seguro + IoT + Etiquetas + Tag
DespliegueContenedor/local/air-gappedSin conectividad a la nube obligatoria