A native macOS app for downloading and archiving IPA files of App Store apps licensed to your Apple Account.
Think of it as a SwiftUI counterpart to ipatool: sign in with your own
Apple Account, search the App Store, and keep a local copy of the apps you already own.
Note on naming — the repository is
IPArchive; the Xcode target, scheme and bundle identifier are stillIPAHelper/com.ixlab.IPAHelper. Renaming those would invalidate the Keychain entry of existing installs, so the internal names are intentionally left alone.
- Sign in with your Apple Account, including two-factor authentication
- Search the App Store for iPhone, iPad or Apple TV software
- Download the IPA of an app your account holds a license for
- Saves to
~/Downloads/<bundle id>_<app id>.ipa— e.g.com.example.app_1234567890.ipa - Keeps a rolling activity log (last 30 entries) so you can see exactly what happened
Please read this before opening an issue — these are deliberate boundaries, not bugs.
- It does not purchase apps. Paid apps are refused outright
(
AppStoreClient.purchasethrows for any app withprice > 0). You can only download apps your account already has a license for, either free apps or ones you previously bought. - It does not decrypt anything or bypass DRM. It uses your own credentials to ask Apple for a download the same way the App Store would.
- The downloaded IPA is not directly sideloadable.
IPAPatcher.patchis currently a stub: the IPA is saved exactly as Apple serves it, withoutiTunesMetadata.plistor theSC_Info/*.sinflicense files injected. That makes it suitable for archiving and analysis, not for installing onto a device. (Swift has no standard ZIP writer; the service boundary exists so a ZIP library can be wired in later.) - No download progress percentage. The underlying client only reports completion, so the UI shows an indeterminate spinner. Downloads can be cancelled at any time.
- macOS 14 (Sonoma) or later
- Swift 6.0 / Xcode 16 to build
- XcodeGen — optional, only if you want to regenerate the Xcode project
Via SwiftPM:
swift build
swift run IPAHelper
swift test # runs the IPAHelperCore unit testsVia Xcode:
xcodegen generate # optional — IPAHelper.xcodeproj is committed
open IPAHelper.xcodeprojThe product website lives in site/ and is built with Vue 3, TypeScript and Vite.
cd site
pnpm install
pnpm devRun pnpm build from site/ to type-check the project and create a production build. The macOS download URL
is currently a placeholder and is defined by DOWNLOAD_URL near the top of site/src/App.vue.
The project uses CODE_SIGN_STYLE: Automatic with no development team, so local builds are typically ad-hoc
signed and the signature changes on every rebuild. macOS ties Keychain item access to the signing identity,
so after rebuilding you will likely see a "IPAHelper wants to use your confidential information" prompt on the
next launch. Choosing Always Allow silences it until the next rebuild. This is expected for local
development, not a sign that anything is wrong.
Credential handling is the part of this project worth scrutinising, so here is exactly what is stored and where.
Your Apple Account password is never persisted. It is never written to the Keychain, never written to disk, and never enters the activity log. It is held in memory only, and cleared on sign-out.
| What | Where | Protection |
|---|---|---|
passwordToken, DSID, email, storefront |
macOS Keychain, service com.ixlab.IPAHelper |
kSecAttrAccessibleWhenUnlockedThisDeviceOnly — not synced to iCloud, not included in backups |
| Apple session cookies | ~/Library/Application Support/IPAHelper/cookies.plist |
file 0600, directory 0700 |
| Downloaded IPAs | ~/Downloads |
standard file permissions |
Other measures:
- Error messages never echo response bodies. Apple's authentication responses contain your
passwordTokenand DSID. If a response fails to decode, the error reports only the HTTP status, the response size, and theCodingKeypath — never the payload. This matters because errors are surfaced in the UI and the activity log, which users copy into bug reports. - No logging of any kind. There is no
print,NSLog, oros_loganywhere in the source. - Automatic cleanup of legacy data. Earlier versions stored the plaintext Apple Account password in the Keychain. On first launch, the stored record is re-encoded and written back, which drops that field. The migration is best-effort: if the Keychain write fails, your session is kept and the cleanup is retried on the next launch.
Stated plainly rather than buried:
- Session cookies are stored in cleartext on disk. File permissions (
0600) keep other user accounts out, but any process running as you can read them, and they include long-lived authentication tokens. Moving them into the Keychain is the obvious next step. - The device GUID is your real hardware MAC address (
DeviceGUIDProvider), which is what Apple's endpoints expect. It is a persistent hardware identifier and cannot be rotated. - The password stays in memory for the whole session. It is cleared on sign-out, but not immediately after a successful sign-in. Discarding it as soon as the token is obtained would narrow the window further.
To sign out and remove the stored credentials, use Sign Out in the app. To wipe the cookie file manually:
rm ~/Library/Application\ Support/IPAHelper/cookies.plistSources/
IPAHelper/ SwiftUI app — ContentView, IPAHelperModel, IPAHelperApp
IPAHelperCore/ Networking, models, Keychain and cookie storage
Tests/
IPAHelperCoreTests/ Unit tests for the core response decoding
site/ Vue product website
IPAHelperCore has no dependency on SwiftUI and is where all App Store communication lives.
The app layer holds no networking logic of its own.
Sign-in keeps failing. Use your Apple Account password, not an app-specific password — those are not supported by the endpoint this app talks to. If two-factor authentication is enabled, you will be asked for the 6-digit code after the first attempt; make sure you enter a fresh one.
"Rate limited by Apple". Apple throttles these endpoints. Wait a few minutes before retrying.
The download finished but the app says the IPA has no metadata. That is expected — see What it does not do above.
Issues and pull requests are welcome. Two things to keep in mind:
- Never paste raw responses into an issue. Apple's authentication payloads contain your
passwordToken, DSID and email. The app deliberately keeps them out of error messages; please don't reintroduce them by hand. - Run
swift buildandswift testbefore submitting.
This project is not affiliated with, endorsed by, or sponsored by Apple Inc. It is intended for archiving apps your own Apple Account is licensed to use, and for security research and analysis. You are responsible for complying with the App Store Terms of Service and the laws of your jurisdiction.
MIT © 2026 IntelliFuture