How to Automatically Obtain a License for an App with IPATool: Complete Guide
IPATool provides two methods to automatically obtain a license for an app: the explicit purchase command or the download command with the --purchase flag, both utilizing the appstore.Purchase implementation to interact with Apple's private purchase endpoints.
IPATool is an open-source command-line interface for interacting with Apple's App Store, allowing users to search, purchase, and download iOS applications. When you need to automatically obtain a license for an app with IPATool, the tool handles Apple's authentication flows, token refresh, and purchase API communication through a structured workflow implemented in Go.
How the Purchase Workflow Works
The license acquisition process follows a six-step execution flow defined in the source code, handling everything from credential retrieval to error management.
Account Authentication and Token Management
The process begins in cmd/purchase.go by retrieving stored credentials through AccountInfo, which fetches the Apple ID and password token from the local keychain. If the subsequent request fails with appstore.ErrPasswordTokenExpired, the tool automatically re-authenticates using the Login method to obtain a fresh token before retrying the operation.
App Resolution
Before purchasing, IPATool must resolve the target application. The Lookup function (or an explicit App ID) queries Apple's servers to retrieve an appstore.App object containing the App Store item ID, as implemented in cmd/purchase.go lines 43-47.
The Purchase Request
The core purchase logic resides in pkg/appstore/appstore_purchase.go. The appstore.Purchase function builds a cryptographically signed PLIST request and POSTs it to Apple's private purchase endpoint. This implementation handles the low-level communication protocol required to acquire licenses from Apple's infrastructure.
Error Handling and Retry Logic
The purchase workflow handles several specific error cases:
ErrLicenseAlreadyExists– The app is already owned; treated as success.ErrPasswordTokenExpired– Triggers credential refresh and retry.ErrLicenseRequired– In download flows, triggers automatic purchase when the--purchaseflag is set.
Explicit License Acquisition via the Purchase Command
Use the standalone purchase command when you need to acquire a license without immediately downloading the application binary.
# Obtain a license for the app with bundle identifier com.example.myapp
ipatool purchase --bundle-identifier com.example.myapp
This command executes the following sequence:
- Calls
AppStore.Lookupto resolve the bundle ID to an App Store item. - Invokes
AppStore.Purchasewith the resolvedappstore.Appobject. - If the license already exists, returns success without error (
ErrLicenseAlreadyExists).
Automatic License Acquisition During Download
The download command supports automatic license acquisition through the --purchase flag, streamlining the workflow when you need both the license and the application package.
# Download the app and acquire a license if needed
ipatool download \
--bundle-identifier com.example.myapp \
--output myapp.ipa \
--purchase
When the --purchase flag is provided, the download flow implements retry logic in cmd/download.go (lines 76-84). If the initial download attempt returns appstore.ErrLicenseRequired, the tool automatically invokes Purchase before retrying the download:
if errors.Is(lastErr, appstore.ErrLicenseRequired) && acquireLicense {
err := dependencies.AppStore.Purchase(appstore.PurchaseInput{Account: acc, App: app})
if err != nil && !errors.Is(err, appstore.ErrLicenseAlreadyExists) {
return err
}
purchased = true
}
Programmatic Usage in Go
You can integrate IPATool's license acquisition directly into Go applications using the pkg/appstore package.
import (
"errors"
"github.com/majd/ipatool/v2/pkg/appstore"
)
func obtainLicense(client *appstore.Client, acc appstore.Account, bundleID string) error {
// Resolve the app first
lookup, err := client.Lookup(appstore.LookupInput{
Account: acc,
BundleID: bundleID,
})
if err != nil {
return err
}
// Attempt purchase; treat already-owned as success
err = client.Purchase(appstore.PurchaseInput{
Account: acc,
App: lookup.App,
})
if err != nil && !errors.Is(err, appstore.ErrLicenseAlreadyExists) {
return err
}
return nil
}
This implementation leverages the same underlying methods used by the CLI, providing programmatic access to Apple's purchase endpoints.
Key Implementation Files
| File | Purpose |
|---|---|
cmd/purchase.go |
CLI command implementation for explicit license purchase. |
cmd/download.go |
Download command with --purchase flag and retry logic. |
pkg/appstore/appstore_purchase.go |
Core purchase implementation building PLIST requests. |
pkg/appstore/appstore.go |
High-level interface exposing Purchase, Lookup, and Download methods. |
pkg/appstore/appstore_login.go |
Token refresh logic for expired credentials. |
Summary
- IPATool offers two pathways to automatically obtain a license for an app with IPATool: the dedicated
purchasecommand or the--purchaseflag withdownload. - Both methods use the
appstore.Purchaseimplementation inpkg/appstore/appstore_purchase.goto communicate with Apple's private APIs. - The tool handles authentication automatically, refreshing expired tokens via
LoginwhenErrPasswordTokenExpiredoccurs. - Error handling treats
ErrLicenseAlreadyExistsas success, allowing idempotent operations. - Programmatic access is available through the
github.com/majd/ipatool/v2/pkg/appstorepackage for Go developers.
Frequently Asked Questions
Can I purchase an app without downloading it using IPATool?
Yes. Use the explicit purchase command with the --bundle-identifier flag. This executes the purchase workflow in cmd/purchase.go without invoking the download logic, allowing you to acquire the license independently of retrieving the application binary.
What happens if I already own the app when using the purchase command?
IPATool returns success without error. The implementation specifically checks for ErrLicenseAlreadyExists in pkg/appstore/appstore_purchase.go (lines 60-87) and treats this condition as a successful operation, preventing duplicate purchases while confirming license ownership.
How does IPATool handle expired authentication tokens during purchase?
The tool implements automatic token refresh. When a purchase request fails with ErrPasswordTokenExpired, the code in cmd/purchase.go (lines 31-41) triggers the Login flow to obtain fresh credentials before retrying the purchase operation.
Is the --purchase flag required for downloading free apps?
No. Free apps do not require a license acquisition step. However, including the --purchase flag ensures the download succeeds even for paid apps by automatically triggering the purchase workflow when ErrLicenseRequired is encountered during the initial download attempt in cmd/download.go.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →