Peu d'appels.
N’importe quelle plateforme.

Identity Layer s'intègre avec une surface minimale de par sa conception. MicroPython sur un microcontrôleur, Flutter sur Android et Windows, ou un PHP bridge déposé dans vos points de terminaison existants. Le même protocole. Les mêmes garanties cryptographiques. Quatre appels.

Raspberry Pi Pico 2W, PN532 NFC reader, SSD1306 OLED display, NTAG424 DNA card
Boot
Registering
Node exists
Verified
Challenge
Active
Quatre appels opérationnels. Le WiFi, OLED et le chargement de la configuration sont une infrastructure de périphérique, pas Identity Layer. La primitive d'identité est IdentityIoT, installé via 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})
Composant Modèle Rôle
MCU Raspberry Pi Pico 2W (RP2350) TrustZone, WiFi, stockage des clés device-bound
NFC reader PN532 Interface I2C, lit les badges NTAG424 DNA
Afficher SSD1306 128x64 OLED Séquence de démarrage, état de vérification
NFC badge NTAG424 DNA (NXP) AES-128 intégré, clés non exportables, dynamique CMAC
Les déploiements de référence ESP32 et RP2040 pour les centres de données et les secteurs verticaux d'accès physique sont en cours. Le protocole et le SDK sont identiques sur tout le matériel pris en charge.

Les nœuds Identity IoT ne sont pas limités à l’accès NFC. Le même node authentifié peut transporter n’importe quelle charge utile de capteur. Toutes les lectures sont transmises via AES-256-GCM crypté POST après que le node ait obtenu son JWT.

Type de capteurMatériel typiqueChamp de charge utile
TempératureDHT22, DS18B20, BME280température (flotteur, °C)
HumiditéDHT22, BME280humidité (flotteur, %)
PressionBME280, BMP390pression (flotteur, hPa)
Mouvement PIRHC-SR501mouvement (booléen)
GPSNÉO-6M, L76Xlat, lon, altitude (flotteur)
Comptage d'énergiePZEM-004T, INA219tension, courant, puissance (float)
Accès NFCPN532 + NTAG424 DNAbadge_uid, accordé (bool)
JSON (déchiffré)
{
  "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 lu. Défi lancé.
Ed25519 vérifié.

Identity Tag est la couche d'application construite au-dessus de Identity IoT. Chaque lecture badge déclenche un cycle complet Ed25519 challenge/response contre le backend. Aucun secret stocké sur le reader. Aucune identité en clair sur le badge. Multi-tenant par conception.

Badge à GRANTED en quatre étapes. Le reader (Pico 2W + PN532) est un Identity IoT node authentifié. Le badge contient un fragment de clé privée chiffré AES-CBC et un DEK fractionné. Le backend lance un défi, reçoit une signature Ed25519, la vérifie et renvoie GRANTED ou DENIED. Aucun secret ne traverse le fil en clair. Aucune base de données d'informations d'identification n'existe.
Flux : badge lire pour accéder à la décision
# 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
ModeDescriptionCas d'utilisation
STD Badge fonctionne sur n'importe quel terminal de la flotte autorisée pour ce tenant. Accès au bureau, points d'entrée généraux.
HS Badge lié cryptographiquement à un terminal spécifique. La dérivation DEK intègre un hash de la clé publique du terminal. Badge n'est pas valide sur tout autre reader. Salles de haute sécurité, racks de datacenter, armoires d'équipement.
Chaque tenant possède un espace de noms isolé : sa propre flotte node, son registre badge, son arborescence de groupe et sa table d'autorisation. Un badge enregistré auprès de Tenant A ne peut pas être vérifié par un node appartenant à Tenant B. L'isolement Tenant est appliqué au niveau des requêtes de base de données, et non via la seule logique d'application.
Point de terminaisonMéthodeRôle
identity_tag/it_request_challengePOSTÉmettre un avis occasionnel pour la vérification badge
identity_tag/it_verify_badgePOSTVérifiez la signature Ed25519, renvoyez GRANTED/DENIED
identity_tag/it_node_checkinPOSTNode battement de coeur et JWT rafraîchissement
identity_tag/it_register_badgePOST (manager)Écrivez la clé publique et les droits badge
identity_tag/it_list_nodesGET (manager)Statut de la flotte Node pour tenant

L'application de provisionnement et de gestion fonctionne sur Android. Il utilise le NFC de l'appareil pour écrire les charges utiles badge et se connecte au backend via des canaux Identity Layer authentifiés.

Dart / Flutter : badge écrire
// 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);

Identité liée à l'appareil.
Quatre appels.

Forfaits locaux. Pas de service d'identité externe. La clé privée ne quitte jamais l'appareil. Stockage sécurisé via flutter_secure_storage et TEE / Secure Enclave lorsque disponible. Le chiffrement de la charge utile s'effectue de bout en bout via ITEMSEncrypter.

identity_package identity_std identity_hs items_crypto items_search items_document_body
Tous les forfaits sont locaux. Aucune dépendance pub.dev sur la couche d'identité. Le SDK est distribué dans le cadre du package de licence.
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
Plate-formeStatutStockage sécurisé
AndroïdeProduction, Google Play autoriséMagasin de clés Android / TEE
FenêtresProduction, Microsoft Store autoriséGestionnaire d'informations d'identification Windows
LinuxProductionlibsecret
iOS/MacOSSur la feuille de routeSecure Enclave

5 Ko.
Votre stack, inchangé.

Le PHP bridge est une exigence unique qui se trouve devant vos points de terminaison existants. Vos itinéraires, votre base de données, votre logique métier. Intouché.. Identity Layer gère l'authentification et le cryptage de la charge utile. Supprimez-le de la même manière que vous l'avez ajouté.

Inscription, abandon. Un require_once et deux appels de fonction. Vos points de terminaison commencent à recevoir des charges utiles vérifiées et déchiffrées. Aucune migration de schéma. Aucune modification de la table utilisateur. Pas de stockage de session. La pile complète côté serveur est 225 Ko.
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);
Les journaux d’audit existent mais sont cryptographiquement inaccessibles. L’accès nécessite une ordonnance judiciaire validée. Le mj_mandate_log point final enregistre le mandat et ouvre une fenêtre d’export de 72 heures. Les journaux sont détruits après la collecte. L'autorité requérante assume la responsabilité juridique.
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
);
ComposantTechnologieRemarques
Durée d'exécutionPHP 8.xVanille, aucun cadre requis
Base de donnéesMySQL / MariaDBSchéma standard, pas de colonnes d'informations d'identification
Cache / éphémèreRedisJetons de défi, files d'attente de messages (TTL < 1 min)
Taille du pont5 KoFichier PHP unique, déposez-le dans n'importe quelle pile LAMP
Taille de la pile complète225 KoIdentité STD + HS + Clés + Canal sécurisé + IoT + Étiquettes + Tag
DéploiementConteneur / sur site / air-gappedPas de connectivité cloud obligatoire