ITMS-90034 : corriger « Missing or invalid signature »
Par Mehdi Azizi
Publié le , 8 min
ITMS-90034 : ton build n'est pas signé avec un certificat de distribution valide. Lis sa signature avec codesign, puis refais un build store avec EAS.
ITMS-90034 arrive quand tu envoies ton build à App Store Connect. Il dit que ton app, ou l'un de ses composants, n'est pas signée avec un certificat de soumission Apple, c'est-à-dire un certificat de distribution valide. La correction : trouver quel bundle est mal signé et pourquoi, puis refaire un build signé pour l'App Store.
Ce guide reste centré sur l'erreur. Si les mots certificat et profil te sont flous, lis d'abord certificat développeur iOS et provisioning profile. Ici, tu trouveras le message à lire, un arbre de décision, les commandes qui inspectent ton IPA et la correction avec les identifiants gérés par EAS. Pour la partie EAS, j'ai lu le code d'EAS CLI 24.10.0 qui choisit le certificat.
Que veut dire l'erreur ITMS-90034 ?
Voici sa forme classique, avec des noms d'exemple :
ITMS-90034: Missing or invalid signature. The bundle 'com.exemple.monapp' at bundle path 'Payload/MonApp.app' is not signed using an Apple submission certificate.
En 2026, sur le forum d'Apple, elle apparaît aussi sous la forme « Validation failed (409) Missing or invalid signature », suivie du même texte et de « (ID : 90034) ».
Le « certificat de soumission », c'est le certificat de distribution. L'aide d'Apple sur les certificats l'écrit : les certificats de développement servent à lancer ton app sur tes appareils, ceux de distribution à la distribuer ou à l'envoyer à App Store Connect.
Lis le chemin cité : il désigne le bundle fautif. Payload/MonApp.app vise l'app elle‑même. Un chemin qui finit par .appex vise une extension, comme un widget. Un chemin en .framework vise une bibliothèque embarquée.
Ce n'est pas le refus d'un reviewer. La validation tombe à l'envoi ou pendant le traitement du build, avant TestFlight : ce build n'atteindra jamais tes testeurs.
L'arbre de décision : du message à la correction
Chaque ligne correspond à un indice que tu lis dans le message, dans les commandes de la section suivante ou dans les journaux d'EAS. Prends-les dans l'ordre : la première qui correspond donne ta piste.
| Ce que tu observes | Cause probable | Correction |
|---|---|---|
Chemin en .appex | Extension mal signée | Déclarer l'extension |
Signature=adhoc | Build non signé | Build profil store |
Apple Development | Build de développement | Build profil store |
ProvisionedDevices lu | Build interne (ad hoc) | Build profil store |
sealed resource | IPA modifiée après coup | Refaire le build |
| EAS : « no longer valid » | Certificat révoqué | Nouveau certificat |
| Tout est valide | Incident côté Apple | Renvoyer, puis signaler |
Inspecter ton IPA en quatre commandes
Télécharge l'IPA depuis la page du build sur expo.dev, puis ouvre un terminal sur ton Mac.
1. Qui a signé l'app ?
unzip -q MonApp.ipa -d ipa
codesign -dv --verbose=4 ipa/Payload/*.app 2>&1 | grep -E "^(Identifier|Authority|Signature|TeamIdentifier)="
codesign écrit sur la sortie d'erreur, d'où le 2>&1. Selon la note technique TN3161 d'Apple, chaque ligne Authority est un maillon de la chaîne de confiance. La première doit commencer par Apple Distribution: ou iPhone Distribution:, suivie du nom de ton équipe. Le second libellé est celui de l'ancien type iOS Distribution : d'après son code, EAS CLI 24.10.0 crée encore des certificats de ce type. Si tu lis Apple Development:, c'est un build de développement. Si tu lis Signature=adhoc sans aucune ligne Authority, le binaire n'est signé par aucun certificat.
2. L'app a-t-elle été modifiée après la signature ?
codesign --verify --deep --strict -vv ipa/Payload/*.app
Tu veux lire valid on disk, puis satisfies its Designated Requirement. TN3161 précise ce que ce contrôle garantit : tous les fichiers attendus sont là, aucun n'a été ajouté, aucun n'a été modifié. Sur un bundle de test que j'ai signé puis retouché, la commande répond a sealed resource is missing or invalid, puis file modified: suivi du fichier changé. L'option --deep sert ici à vérifier, jamais à signer : sur le forum d'Apple, un ingénieur de l'équipe support le déconseille pour signer.
3. Quel profil est embarqué ?
security cms -D -i ipa/Payload/*.app/embedded.mobileprovision -o profil.plist
plutil -extract ProvisionedDevices xml1 -o - profil.plist
plutil -extract ExpirationDate raw profil.plist
Ce sont les commandes de la note TN3125 sur les profils. Un profil App Store ne contient aucune liste d'appareils : la deuxième ligne doit répondre Could not extract value. Si elle affiche des identifiants d'appareils, c'est un profil ad hoc, celui d'un build interne. La troisième donne la date d'expiration du profil.
4. Les extensions et les frameworks sont-ils signés pareil ?
find ipa/Payload/*.app \( -name "*.appex" -o -name "*.framework" \) \
-exec sh -c 'echo "$1"; codesign -dvv "$1" 2>&1 | grep -m1 "^Authority="' _ {} \;
Chaque composant doit afficher la même ligne Authority que l'app. Si l'un d'eux s'en écarte, c'est lui que cite le message.
Si tu veux vérifier avant l'envoi, TN3161 recommande altool, le même contrôle que le bouton Validate App de Xcode. Il demande une clé API App Store Connect, dont le fichier AuthKey_<ID_CLE>.p8 se range dans ~/.appstoreconnect/private_keys :
xcrun altool --validate-app -f MonApp.ipa -t ios --api-key <ID_CLE> --api-issuer <ID_EMETTEUR>
Corriger avec EAS, cause par cause
Un build interne ou de développement envoyé à Apple
D'après la documentation d'Expo sur eas.json, les builds en "distribution": "internal" ne sont pas signés pour les stores : ils utilisent un profil ad hoc. Seul un profil en distribution store, la valeur par défaut, produit un build envoyable. Le plus sûr est d'envoyer le build que tu viens de construire, sans le choisir à la main :
eas build --platform ios --profile production --auto-submit
Si tu passes par eas submit --path, vérifie que le fichier est bien ton dernier build store. Sur le forum d'Apple, une équipe a découvert que son outil d'envoi renvoyait à chaque fois un ancien IPA, versionné dans git.
Une extension oubliée
Chaque extension est un bundle à part, avec son identifiant et son propre profil. Dans un projet Expo à génération native, la page d'Expo sur les extensions iOS demande de les déclarer dans extra.eas.build.experimental.ios.appExtensions. EAS CLI les connaît alors avant le build, et crée ou valide leurs identifiants. La plupart des bibliothèques qui ajoutent une extension écrivent cette déclaration pour toi, via leur plugin.
Solys, mon réveil à mini-jeux, embarque quatre extensions : un widget et trois extensions de Temps d'écran. Les quatre sont déclarées dans sa configuration, et EAS a un profil pour chacune. Une extension ajoutée à la main dans Xcode, sans cette déclaration, est le candidat idéal pour un chemin en .appex dans le message.
Un certificat révoqué ou expiré
La page d'Apple sur les certificats est claire : tu ne peux plus envoyer de build signé avec un certificat expiré ou révoqué. Un build déjà envoyé mais pas encore soumis peut même passer en Invalid Binary si son certificat a été révoqué.
Le code d'EAS CLI 24.10.0 montre quand ce cas passe inaperçu :
- Build interactif, connecté à Apple : EAS compare son certificat avec ceux encore valides chez Apple. S'il n'y est plus, il affiche « Current distribution certificate is no longer valid in Apple Dev Portal » et te propose d'en choisir ou d'en créer un.
- Build interactif, sans connexion : EAS ne vérifie que les dates et prévient qu'il saute la validation chez Apple.
- Build non interactif, en intégration continue : EAS affiche « Distribution Certificate is not validated for non-interactive builds » et signe quand même.
En intégration continue, EAS ne revérifie pas le certificat lui‑même : une révocation peut ne se voir qu'à l'envoi. La correction : lance un build interactif connecté à ton compte Apple, ou passe par eas credentials --platform ios, menu Build Credentials, puis « Distribution Certificate : Add a new one to your account ». Les profils qui contenaient l'ancien certificat deviennent invalides : EAS les contrôle au build suivant et les refait. Les limites d'Apple sur le nombre de certificats sont détaillées dans le guide sur le certificat développeur iOS.
Un binaire modifié après la signature
La signature scelle le code, les ressources et les métadonnées par des empreintes, comme l'explique la note TN3126 d'Apple. Décompresser l'IPA pour changer un fichier, puis la recompresser, casse ce sceau. Fais la modification dans ta configuration, puis refais un build. Ne retouche jamais l'IPA produite par EAS.
Même logique pour du code rangé au mauvais endroit, par exemple dans une archive .zip : l'App Store ne peut pas le re-signer. Apple décrit les emplacements autorisés dans sa page sur le contenu d'un bundle.
Des identifiants locaux
Si ton profil EAS utilise "credentialsSource": "local", ton fichier credentials.json pointe vers un certificat .p12 et un profil .mobileprovision. Vérifie le profil avec les commandes de l'étape 3 : il doit être de type App Store et contenir ton certificat de distribution actuel. Et garde ces fichiers hors du dépôt, comme les clés API d'une app Expo.
Quand tout est valide
Il reste un cas frustrant. Sur le forum d'Apple, des développeurs voient l'erreur disparaître en renvoyant le même build, sans rien changer. En août et septembre 2026, deux fils décrivent l'inverse : certificat et profil neufs, signature vérifiée, échec persistant. Dans l'un d'eux, un ingénieur d'Apple conseille un rapport de bug avec l'IPA, l'analyse de signature et les journaux de Transporter, puis un contact avec App Store Connect.
Renvoie donc une fois avec un nouveau numéro de build. Si l'erreur revient alors que tes quatre commandes sont propres, signale-la à Apple avec ces éléments. Ne révoque pas ton certificat par réflexe : ça ne résout rien de plus et ça invalide tes profils.
Envoyer ton build sans mauvaise surprise
Une signature se vérifie en deux minutes avant l'envoi. Les autres contrôles automatiques demandent la même rigueur, comme ITMS-90725 pour la version de Xcode ou ITMS-90683 pour les phrases d'autorisation. Le parcours complet du build à l'envoi, sans Mac, est dans publier une app iOS sans Mac.
Les refus d'un reviewer demandent plus de recul : la démarche est sur la page application refusée par Apple, et les motifs les plus fréquents sont dans pourquoi Apple refuse une app.
Pour vérifier ton dossier avant l'envoi, le Kit Review Apple réunit ma checklist et des skills Claude Code qui relisent ton projet. Si ton envoi bloque et que tu veux un regard humain, réserve une heure avec moi : on reprend ton projet en visio, sur ton écran. Et si tu prépares ta première sortie, fais ton diagnostic gratuit : il remet les étapes dans l'ordre et t'envoie ma checklist anti-refus Apple.
Questions fréquentes
ITMS-90034 est-il un refus d'App Review ?
Non. C'est une validation automatique faite à l'envoi du build, avant TestFlight et avant toute revue. Personne n'a ouvert ton app : Apple a seulement constaté que sa signature ne vient pas d'un certificat de distribution valide.
Faut-il révoquer mon certificat de distribution pour corriger ITMS-90034 ?
Seulement s'il est compromis ou déjà invalide. Révoquer un certificat qui fonctionne invalide tes profils sans corriger la cause. Commence par lire la signature de ton IPA avec codesign, puis corrige ce que l'arbre de décision désigne.
Peut-on corriger ITMS-90034 avec une mise à jour à distance ?
Non. La signature fait partie du binaire, et le build refusé ne sera jamais utilisable. Il faut produire un nouveau binaire correctement signé et le renvoyer.
Pourquoi l'erreur cite-t-elle mon widget et pas mon app ?
Parce que le widget est un bundle à part, signé avec son propre profil. S'il n'est pas déclaré à EAS ou qu'il a été signé autrement, il fait échouer tout l'envoi. Déclare l'extension dans ta configuration et refais un build.
Que faire si codesign dit que tout est valide ?
Vérifie aussi le profil embarqué et chaque extension. Si tout est propre, renvoie une fois avec un nouveau numéro de build. Si l'erreur persiste, envoie un rapport à Apple avec l'IPA, la sortie de codesign et les journaux d'envoi.

