Apple iOS Signing and Provisioning — Operator Primer
Status: technical research document. Not legal or tax advice. The $99/yr Apple Developer Program fee is likely a deductible business expense for MooseQuest LLC — confirm with your CPA. Last updated: 2026-06-11. Verify Apple documentation freshness at
developer.apple.com.
TL;DR
Apple's signing system is a four-layer stack (identity → certificate → provisioning profile → entitlements) where every layer scopes to a team, and you currently have two teams active in your project. The personal team (4B94BVU57T) and the org team (CM62W3T483) are structurally independent; your cert 4VG85D6HX8 can authenticate you for builds on either, but bundle IDs registered under one team are invisible to the other. The app.raxx.ios.uitests conflict exists because that bundle ID was claimed under the personal team first. The fix is a two-minute Apple Developer portal action, not a code change.
1. The Hierarchy — What Everything Actually Is
Apple ID
Your @icloud.com or custom email login. It's the person. Every other concept in this system hangs off teams, and teams are associated with Apple IDs. One Apple ID can be a member of many teams, including your personal (free) team and one or more paid org teams.
Team
A team is the organizational unit Apple uses for developer access and billing. Two kinds exist:
- Personal team — created automatically when you first sign into Xcode with an Apple ID that hasn't paid for the Developer Program. Free. Labeled with your name, no organization name. Used for quick device installs during development. Has significant restrictions (see Section 5).
- Org team (paid) — created when you enroll an organization in the Apple Developer Program ($99/yr, requires DUNS for LLC/Corp enrollment). Has a real organization name (MooseQuest LLC), full App Store access, TestFlight, IAP, and no 7-day cert rotation.
The confusing part: both look identical in Xcode's team picker. The only reliable differentiators are the Team ID and whether a company name appears.
Team ID
A 10-character alphanumeric string (CM62W3T483 for MooseQuest LLC, 4B94BVU57T for your personal account). This string is the actual identifier Apple uses when:
- Building your app's code signature
- Validating your AASA file for Universal Links (
appID=TEAMID.bundle.identifier) - Authorizing which certificates belong to which team
The Team ID is permanent. It's embedded in every provisioning profile and every app your team ships.
Certificate
A cryptographic credential stored in your Mac's Keychain that proves identity to Apple's signing infrastructure. Two types matter for shipping an app:
Apple Development certificate
- Used for Debug builds going to physical devices during development
- Valid for 1 year (source: developer.apple.com/support/certificates/)
- One per developer per team — but since you're the only developer on MooseQuest LLC, you have one cert under the org team and the personal team generates its own
- Technically tied to the team it was created under, but the private key sits in your Keychain on your Mac. The cert 4VG85D6HX8 is an Apple Development cert — your personal Mac holds the private key, Apple holds the public half. Xcode can use it to sign for whatever team the cert was issued under.
Apple Distribution certificate - Used for Release builds going to TestFlight or the App Store - You cannot sideload to a device with a Distribution cert — it's for submission pipelines only - Also 1 year validity
The confusing naming: Apple used to call these "iOS Development" and "iOS Distribution." They renamed them. Old docs, Stack Overflow answers from 2018, and some Xcode UI strings still use the old names. They refer to the same concepts.
Bundle ID (also called: App ID, Bundle Identifier, Identifier)
A reverse-DNS string like app.raxx.ios. This is how Apple's ecosystem globally identifies your app — across the App Store, iCloud, push notifications, associated domains, and IAP.
Critical scoping rule: bundle IDs are registered per-team in the Apple Developer portal. When you register app.raxx.ios under MooseQuest LLC (CM62W3T483), it belongs to that team. If Xcode previously auto-registered app.raxx.ios.uitests under your personal team (4B94BVU57T), it is now claimed there, and your org team cannot claim the same string.
This is not a bug. It's Apple's anti-squatting mechanism. It just makes the personal-to-org migration unpleasant.
Provisioning Profile
The document that binds everything together. A provisioning profile is a signed plist file that contains:
- App ID — which bundle identifier this profile applies to
- Certificate(s) — which signing identities are allowed to produce builds under this profile
- Device UDIDs — which physical devices can run the resulting binary (Development profiles only; Distribution/App Store profiles don't restrict devices this way)
- Entitlements — which capabilities the app may use (push notifications, Associated Domains, StoreKit, etc.)
- Team — which org team issued this profile
- Expiry — 1 year from creation
When Xcode builds your app, it stuffs a copy of the profile inside the .ipa. iOS validates the profile on install: is this device's UDID listed? Is this cert in the profile? Is the profile's team the same one the app binary's code signature references? If any check fails, install is rejected.
Entitlements
A plist of capability declarations embedded in your app binary and matched against the provisioning profile. Examples: com.apple.developer.associated-domains (for Universal Links / AASA), com.apple.developer.in-app-payments (for StoreKit). If you add a capability in Xcode without a matching provisioning profile, the build signs fine locally but crashes or fails validation at runtime.
"Automatically Manage Signing"
An Xcode setting (per-target, in Signing & Capabilities). When enabled, Xcode contacts Apple's servers at build time, looks up your team, and creates or refreshes certificates and provisioning profiles on your behalf. It removes the need to manually create profiles in the developer portal.
What it does not do:
- It cannot resolve bundle ID conflicts across teams
- It cannot create App Store distribution profiles (it creates Development profiles; App Store/TestFlight uploads use a separate archive-and-export flow)
- It does not write changes to disk until you explicitly save the project (Cmd-S) or trigger a build (Cmd-B)
See Section 5 for the gotcha this creates.
2. The Three Flows
Flow A: Sideload to your iPhone via Xcode (Debug build)
This is what you do every day for development. The chain:
- Xcode builds a Debug binary signed with your Apple Development cert
- Your device's UDID must appear in the Development provisioning profile for the bundle ID
- Xcode installs directly over USB or wirelessly
- App runs immediately, debugger can attach
- No App Store Connect involved
Which team? Either team works. Org team is preferred for Raxx because the personal team has capability limitations and the 7-day cert rotation (see Section 5). If Xcode defaults to the personal team for test targets, the main app target still builds fine — it just means the test runner is signed under a different team than the main app. This is cosmetically confusing but doesn't block device installs.
Device registration: your device's UDID must be registered in the Apple Developer portal under the team. You have 3 devices registered under MooseQuest LLC. The org team's Development profile for app.raxx.ios lists those 3 UDIDs.
Flow B: Upload to TestFlight (Release build, org team only)
TestFlight is Apple's beta distribution platform. Despite being "just testing," Apple treats TestFlight uploads identically to App Store submissions at the signing level.
- In Xcode, select Generic iOS Device (not a physical device)
- Product → Archive — this creates a
.xcarchive - Distribute App → App Store Connect → Upload
- Xcode switches to your Apple Distribution cert for this step
- The profile used is an App Store provisioning profile (not Development)
- Upload goes to App Store Connect; the build appears under TestFlight within ~30 minutes after Apple's automated processing
Critical: you must have a Distribution cert under your org team (CM62W3T483). Distribution certs are not auto-created by "Automatically Manage Signing" during normal development builds. Xcode creates one the first time you do an Archive + Upload flow.
Who can receive TestFlight builds? Internal testers (members of your App Store Connect team — up to 100) can install immediately. External testers require a round of App Store review (a lighter review than full App Store review, but real human review). Source: developer.apple.com/testflight/.
Flow C: App Store submission
Identical to TestFlight upload at the signing level. Difference is in App Store Connect: you submit a specific build for review, fill in metadata (screenshots, description, privacy nutrition label, etc.), and Apple reviews it. Review time is typically 1–3 days for first submissions. Source: developer.apple.com/distribute/.
3. The Raxx-Specific Situation Right Now
Your teams in this project
| Team | ID | Type | Used for |
|---|---|---|---|
| MooseQuest LLC | CM62W3T483 |
Org, paid | Main app target (app.raxx.ios), App Store path |
| Kristerpher Henderson | 4B94BVU57T |
Personal, free | Currently signing test targets (unintentional) |
The cert 4VG85D6HX8
This is an Apple Development certificate. It lives in your Mac's Keychain. The private key was generated on your machine when you (or Xcode) created a Certificate Signing Request. Apple signed the public half and associated it with your developer identity. Because it's tied to your Apple ID rather than a specific org, it can authenticate builds for either team — the Organizational Unit field in the cert determines which team a given signing operation is attributed to. (Source: TN3161 at developer.apple.com/documentation/technotes/tn3161-inside-code-signing-certificates/.)
The AASA file
raxx.app/.well-known/apple-app-site-association currently lists both team IDs in the appIDs array, per PR #3472. Format:
{
"applinks": {
"details": [
{
"appIDs": [
"CM62W3T483.app.raxx.ios",
"4B94BVU57T.app.raxx.ios"
],
"components": [...]
}
]
}
}
Listing both is correct for the transitional period. Once you fully deprecate the personal team from this project, you can remove the 4B94BVU57T entry — but there's no urgency because listing extra team IDs does no harm.
Important caching note: iOS caches the AASA file at app install time and refreshes it in the background (iOS 14+). A fresh install is the only guaranteed way to pick up AASA changes immediately.
The app.raxx.ios.uitests conflict
When Xcode first created your UI test target, "Automatically Manage Signing" was active and defaulted to your personal team. It auto-registered app.raxx.ios.uitests as a bundle ID under 4B94BVU57T. Now your org team can't claim that string.
Fix (two options):
Option 1 — Bundle ID swap (no Apple contact needed):
1. In Xcode, set the UITests target team to your personal team (4B94BVU57T)
2. Change the UITests bundle identifier to a throwaway value (e.g., app.raxx.ios.uitests.tmp)
3. Switch the UITests target team to MooseQuest LLC (CM62W3T483)
4. Set the bundle identifier back to app.raxx.ios.uitests
5. Xcode registers it under the org team
This works because changing the bundle ID in step 2 releases the claim on app.raxx.ios.uitests from the personal team in Apple's portal. Several Apple Developer Forum threads confirm this pattern (source: developer.apple.com/forums/thread/107350).
Option 2 — Contact Apple Developer Support:
Ask them to delete app.raxx.ios.uitests from your personal team's identifiers. Takes ~2 hours via phone or chat. Source: developer.apple.com/forums/thread/130766.
Option 1 is faster. If it silently fails (Xcode sometimes doesn't release the portal-side registration), fall back to Option 2.
4. The Naming Trap Table
This is the source of 80% of signing confusion. Apple uses different names in different contexts to refer to the same concept, and uses the same word in different contexts to mean different things.
| Apple says... | In this context it means... | What makes it confusing |
|---|---|---|
| Team | Either a personal free team or a paid org team | Xcode's picker shows both with no visual distinction beyond the name |
| Team ID | The 10-char org identifier (CM62W3T483) |
Apple also has a "Membership ID" — same thing, different name in different portal pages |
| Apple ID | Your login email | Also informally called "your account," "your developer account," "your personal team" |
| Bundle ID | The app.raxx.ios string |
Also called "App ID" in older Apple docs and "Bundle Identifier" in Xcode's UI — three names for the same field |
| App ID | In current Apple docs: a bundle ID registered in the portal | In Xcode's old UI: the full TEAMID.bundle.identifier compound string — the format still used in AASA files |
| Certificate | The .cer file Apple issues |
Also called "signing identity" in Xcode, "code signing certificate" in older docs |
| Provisioning Profile | The multi-field binding document | Xcode sometimes calls it a "profile" and sometimes shows it as an inlined signing configuration — you can't always see it directly |
| Automatically Manage Signing | Xcode auto-creates certs + profiles | Does NOT mean "everything works automatically forever" — it fails silently when portal state is inconsistent |
| Distribution | Signing for App Store / TestFlight upload | Confusingly, a "Development" profile is also used for ad-hoc on-device installs — "distribution" in Apple's taxonomy specifically means App Store Connect pipeline |
5. Breaking Changes and Gotchas
Xcode UI changes don't write to disk until save or build
When you change the signing team, bundle ID, or entitlements in Xcode's Signing & Capabilities tab, those changes are held in memory. The .xcodeproj file on disk does not update until you hit Cmd-S (Save) or trigger Cmd-B (Build). If you quit Xcode or your Mac crashes between making the change and saving, the change is gone. This is responsible for an unusual number of "I fixed this yesterday and it came back" debugging sessions.
Test targets have independent signing configuration
Each target in your Xcode project (main app, UI tests, unit tests, extensions) has its own Signing & Capabilities configuration. Changing the team or bundle ID on your main target does NOT cascade to test targets. You must set each target individually. This is why the app.raxx.ios.uitests problem exists — it defaulted to a different team than the main target.
.xcconfig files treat // as a comment delimiter — URLs break
This is documented at mokacoding.com/blog/double-slash-xcconfig/ (cross-referenced against Apple's own format guide at help.apple.com/xcode/mac/current/en.lproj/dev745c5c974.html). If you ever store a URL like https://api.raxx.app in an .xcconfig key, Xcode silently truncates it at https:. The // starts a comment. Workarounds: store URLs without the scheme and reconstruct in code, or use Info.plist for full URL values.
Bundle IDs can be "claimed" under one team, blocking another team from registering them
Covered in Section 3. The personal team auto-registers bundle IDs the moment Xcode's automatic signing touches a target under that team. There is no warning, no confirmation dialog. You find out later when the org team can't register the same string. The fix is in Section 3.
Personal team hard limits
The personal (free) team has restrictions Apple does not prominently document together:
- Development certificates are valid for 7 days (not 1 year). Apps signed with them expire off devices after 7 days and must be re-signed via Xcode. (Source: mybyways.com/blog/new-limitations-imposed-on-free-apple-developer-account with primary reference to Apple's restrictions documentation.)
- Up to 3 simultaneously sideloaded apps per device under a personal team. This is a per-Apple-ID restriction. (Source: jailbreak community documentation of the restriction; Apple does not publish this number in a single official location.)
- No App Store Connect access
- No TestFlight
- No IAP
- No push notifications (production APNs)
None of these apply to your org team (CM62W3T483).
The same cert (4VG85D6HX8) can sign for both teams
Because Apple Development certs are tied to the developer's identity (your Apple ID + your Mac's private key) rather than strictly to a single team, Xcode can use the same cert to sign builds under either team as long as the cert is present in the Keychain and Apple's portal associates that cert identity with the team. This is why you saw 4VG85D6HX8 appear valid for both teams. (Source: TN3161 at developer.apple.com/documentation/technotes/tn3161-inside-code-signing-certificates/ — a code-signing identity is the combination of certificate + matching private key; the key is local to your machine.)
AASA is cached at install time
iOS fetches the AASA file when an app is first installed and caches it. Background refresh happens periodically on iOS 14+ via Apple's CDN, but there is no guaranteed refresh time. After updating raxx.app/.well-known/apple-app-site-association, a fresh uninstall + reinstall is the only way to confirm the new configuration is live on a device. Source: developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html.
6. Resources
Primary sources — check these before accepting any third-party explanation:
https://developer.apple.com/documentation/xcode/distributing-your-app-for-beta-testing-and-releases
Central index for TestFlight, App Store, and ad-hoc distribution flows.
https://developer.apple.com/documentation/technotes/tn3161-inside-code-signing-certificates/
Apple's technical note on certificate internals. The authoritative source on what a code-signing identity actually is.
https://developer.apple.com/documentation/Xcode/sharing-your-teams-signing-certificates
Explains how signing certs are synchronized across team members.
https://developer.apple.com/help/account/certificates/certificates-overview/
Portal-level certificate management guide.
https://developer.apple.com/help/account/provisioning-profiles/create-a-development-provisioning-profile/
Step-by-step provisioning profile creation.
https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html
Universal Links and AASA file spec. This is the "legacy" archive doc but it's still the most complete single reference.
https://developer.apple.com/help/app-store-connect/
App Store Connect help index — TestFlight, App Review, IAP configuration.
https://developer.apple.com/support/certificates/
Apple's certificate overview with type list and expiry guidance.
https://developer.apple.com/forums/thread/107350
Apple Developer Forums: bundle ID claimed by personal team — resolution strategies.
https://developer.apple.com/forums/thread/130766
Apple Developer Forums: removing bundle IDs from personal team (contact Apple Support path).
https://mokacoding.com/blog/double-slash-xcconfig/
The //-as-comment xcconfig problem with workarounds. Not a primary source but the clearest writeup; cross-check against Apple's format guide at:
https://help.apple.com/xcode/mac/current/en.lproj/dev745c5c974.html
WWDC sessions worth watching: - WWDC 2021 "Distribute apps in Xcode with cloud signing" (session 10204) - WWDC 2023 "Verify app dependencies with digital signatures" (session 10165)
Search at developer.apple.com/videos/ — the full WWDC catalog is free.
7. What Comes Next for Raxx
Ordered by urgency:
Immediate: resolve the UITests bundle ID conflict
Use Option 1 from Section 3 (bundle ID swap in Xcode) to move app.raxx.ios.uitests under the org team. This unblocks any CI pipeline that needs to build the test target under the org team's signing.
Short-term: get TestFlight working under MooseQuest LLC
Steps: 1. Archive the app: Product → Archive (requires Generic iOS Device selected, Release scheme) 2. Distribute App → App Store Connect → Upload 3. If you don't yet have an Apple Distribution cert under MooseQuest LLC, Xcode will offer to create one at this step 4. Build appears in App Store Connect under TestFlight → Builds within ~30 minutes of upload 5. Add yourself as an internal tester; install via TestFlight app
This is a completely separate flow from the daily sideload. You need to do it at least once to confirm Distribution signing is configured before you approach the App Store submission step.
Medium-term: deprecate the personal team from this project
Once the UITests conflict is resolved and TestFlight is working under the org team:
1. Set every target in the Xcode project to use CM62W3T483 (MooseQuest LLC)
2. Remove the 4B94BVU57T entry from the AASA file's appIDs array
3. Commit the AASA change; testers need a fresh install to pick it up
Before App Store submission: StoreKit 2 sandbox testing
Per project decision (project_ios_billing_iap): iOS billing goes through Apple IAP / StoreKit 2. Before App Store submission:
1. Create your IAP products in App Store Connect (the product IDs are permanent once set)
2. Create a sandbox tester account (separate from your personal Apple ID)
3. Test the full purchase flow in the Simulator and on a device using the sandbox environment
4. StoreKit 2 receipt validation happens server-side — Raptor will need to call Apple's /verifyReceipt or the newer transactionInfo endpoint
CPA flag: the 30%/15% Apple commission on IAP revenue is a pass-through cost, not pure margin. Ask your CPA how this is reported — it is typically a cost of goods sold treatment, not a gross revenue reduction, but the correct treatment depends on your accounting method.
Ongoing: cert expiry calendar
Both Apple Development and Apple Distribution certs expire after 1 year. Calendar events now:
- Development cert for 4VG85D6HX8: check expiry date in Keychain Access → set a 30-day-before reminder
- When a cert expires, provisioning profiles that reference it also become invalid — you'll see Xcode errors about expired profiles before you notice the cert itself
Why This System Is Actually Hard
Apple's signing system exists because iOS has no sideloading path for end users — every app that runs on iOS must be cryptographically traceable to an Apple-enrolled identity. The complexity is the security model. The problem is that Apple designed the system from the perspective of "a team of engineers at a company," not "one founder with a personal Apple ID that predates their LLC." When your personal Apple ID is also your org account's admin, the system doesn't clearly separate the two contexts, and Xcode — which was built assuming you always know which team you're targeting — silently applies team defaults that cause exactly the bundle ID conflict you hit tonight.
Apple's documentation acknowledges this in scattered forum posts but does not have a single "here's how to migrate from personal to org team" guide. The Forum threads at developer.apple.com/forums/thread/107350 and developer.apple.com/forums/thread/130766 are the closest thing to it.
Before acting on any guidance in this document regarding entity tax treatment or the deductibility of Apple Developer Program fees, consult a CPA licensed in Pennsylvania familiar with single-member LLC pass-through taxation.
Sources as of 2026-06-11 — Apple's developer documentation URLs and content change without notice. Verify before acting.