Tutorials / Shipping & infrastructure / Upload with an app-specific password
📝 Written ● Beginner Updated 2026-05-25

Upload to TestFlight or the App Store with an app-specific password

You don't need an App Store Connect API key to ship a build. LingCode's Archive & Distribute sheet can upload with just your Apple ID and an app-specific password — the lightest setup, and the closest thing to Xcode Organizer's one-click feel.

Why a password at all — didn't Organizer just work?

0

Xcode's Organizer feels credential-free because it quietly reuses the Apple ID account you signed into Xcode (Settings > Accounts). It holds that authenticated session internally. Any tool outside Xcode — including the xcrun altool uploader LingCode drives — cannot borrow that session. It needs a credential of its own, and Apple gives you exactly two:

  • An App Store Connect API key — a .p8 file plus a Key ID and Issuer ID. Rock-solid for automation, but you have to create it in the developer portal first. (Covered in Set up an App Store Connect API key.)
  • Your Apple ID + an app-specific password — a one-off password you generate in a minute, tied to your normal Apple ID. This is the path this tutorial takes.

Why can't you just type your real Apple ID password? Because your account has two-factor authentication, and a command-line uploader can't answer a 2FA prompt. An app-specific password is Apple's answer: a scoped, revocable password that bypasses the 2FA challenge for one tool. It is not a security downgrade — you can revoke it anytime, and it can't be used to sign into your account in a browser.

Which should you pick? If you just want to ship from your own Mac, use the app-specific password — less setup. If you're wiring up CI or a shared machine, use the API key — no human Apple ID attached.

Step 1 — Generate an app-specific password

1

This takes about a minute and you only do it once:

  • Go to account.apple.com and sign in with the same Apple ID as your Apple Developer account.
  • Open the Sign-In and Security section and choose App-Specific Passwords.
  • Click Generate an app-specific password (the +), label it something you'll recognize like LingCode upload, and confirm.
  • Copy the password it shows — it looks like xxxx-xxxx-xxxx-xxxx. You only see it once. Copy it now.
Two-factor authentication must be on. The "App-Specific Passwords" option only appears for Apple IDs with 2FA enabled. Every Apple Developer account already has it, so if you don't see the option, you're signed into the wrong Apple ID. Apple's reference: support.apple.com/102654.

Step 2 — Archive once

2

In LingCode, open the File menu > Archive & Export…. The sheet that opens is titled Archive & Distribute and it mirrors Xcode's Organizer model: three steps, top to bottom.

Click 1 · Archive. This runs a Release build and produces a .xcarchive — the durable, self-contained build product. It's the slow step (a full optimized compile), so you do it once. If a fresh archive already exists from a previous run, LingCode detects it on open and the button reads Re-archive — you can skip straight to exporting.

The whole point of archiving separately: one archive can be exported and distributed many times. Export an Ad Hoc build for a tester this morning and upload the same archive to TestFlight this afternoon — no second compile. You only re-archive when the code actually changes.

Step 3 — Export with the App Store method

3

Under 2 · Export, set the method to App Store and click Export. This takes the archive and produces the actual uploadable artifact — a signed .ipa for iOS or .pkg for macOS — packaged for App Store Connect.

Only the App Store method produces something TestFlight will accept. Development and Ad Hoc exports are for direct device installs; App Store Connect rejects them. That's why the upload step below only lights up after an App Store export.

"Archive vs Export" in one line: archive builds the app; export signs and packages it for a specific destination. You need both before anything can be uploaded — archiving alone leaves you a .xcarchive that nothing can install.

Step 4 — Upload

4

Once the App Store export finishes, the 3 · Upload to App Store Connect panel becomes active. Leave the authentication picker on Apple ID (the default), then:

  • Enter your Apple ID email — the same account from Step 1.
  • Paste the app-specific password you generated. LingCode stores it in your Keychain, so you only paste it once.
  • Click Upload to App Store Connect.

LingCode runs xcrun altool --upload-app on the artifact you just exported — no second archive, no re-export. When it succeeds, the build appears in App Store Connect under TestFlight after Apple finishes processing it, which usually takes 5–30 minutes.

Where did it go? A successful upload doesn't email you immediately. Open App Store Connect > your app > TestFlight and wait for the build to move from "Processing" to ready.

When the upload fails

5

LingCode reads altool's output and surfaces a specific reason. The ones you'll actually hit:

  • "Redundant Binary Upload" / ITMS-90189 — this build number is already on App Store Connect for this version. Bump the build number and re-archive. (Re-archiving is required here because the build number is baked into the binary.)
  • Authentication failed — the app-specific password was mistyped or revoked, or you used your real Apple ID password by mistake. Generate a fresh app-specific password (Step 1) and paste it again.
  • "No matching profiles found" / signing errors — the app record doesn't exist yet, or there's no distribution profile for the bundle ID. Create the app record in App Store Connect first; see First-time iOS App Store submission.
  • Missing Info.plist value / ITMS-90713 — Apple names the exact key (e.g. a usage-description string). Add it to your target's Info.plist and re-export.

The full xcodebuild and altool log is written to build/export.log next to your project, and the sheet's Reveal Log button jumps straight to it — useful when the one-line reason isn't enough.

Prefer the API key instead?

6

Everything above works identically if you switch the authentication picker to API key (.p8) — you'll enter a Key ID, Issuer ID, Team ID, and choose your AuthKey_*.p8 file instead of an Apple ID. Use this when you don't want a personal Apple ID involved (CI, a shared build machine) or you're already managing keys for the LingCode agent. The one-time key creation is covered in Set up an App Store Connect API key.

Get LingCode →

What's next