You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Apple refused the sign-in at its first step, before your password was sent, so the password is not the problem: Email verification failed: This action cannot be completed at this time. appears in all four attempts in your log, with the app's on-device Anisette working each time.
Two things to check:
Can you sign in at https://account.apple.com with the same Apple ID, and does Apple ask you to do anything there (confirm details, unlock, accept something)?
Did you enter your email address or a phone number as the Apple ID?
In 1.1.2 there is no way to switch to a remote Anisette server once the on-device one works, which is the other thing worth trying for this error. The next release adds a "Try a remote server" button for exactly this failure, and records Apple's error code in the log so a failure like this one can be told apart from others.
This is not specific to this app. Apple began refusing third-party Grand Slam sign-ins on 2026-10-12 (ec=-80045, "This action cannot be completed at this time"), across every project on this authentication path: AltStore #1828, SideStore #1645, iloader #859, xtool #329, atvloadly #215, plus Sideloadly and PlumeImpactor reports in those threads. Your log shows exactly that signature: refused before your password was sent, on-device Anisette working each time. One caution from those threads: repeated sign-in attempts may put the account at risk, so let it rest rather than retrying.
Where it is broken. A sign-in request passes two checkpoints:
your device ──▶ Apple's edge ──▶ GsService2 handler ──▶ sign-in
(headers, TLS) (body: SRP + Anisette
one-time password)
September's 503s lived HERE ──▲ └── the -80045 refusal lives HERE
our probe covers HERE ───────┘ (NOT yet covered by our probe)
Our check_gsa_edge.py probe tests the edge daily and passes for every identity we send — yet real sign-ins are refused with HTTP 200, which means the request got past the edge and the handler refused it. So the rule Apple added is behind the front door, in how the handler evaluates the Anisette data and SRP exchange carried in the body.
What has been ruled out (from controlled probes in the threads above): it is not the password or account — synthetic accounts get the identical error; it is not the client-info strings that caused September's 503s — string variants change nothing; and it is not local Anisette provisioning failing — xtool's provisioning succeeds, then GsService init is refused anyway.
If you want to help unbreak it, thank you — nobody has published the experiment that localises this yet, and the tooling to run it is in this repo:
How to investigate, and our current hypothesis
The investigation below is Claude Code's (an AI model), working from the issue threads and this repository's wire documentation. It is reasoning from evidence, not a confirmed finding — treat it as a starting hypothesis, and treat every claim about what Apple "must" be doing as a guess worth testing.
The handler's decision at SRP init happens before any password is checked, so it can only be evaluating two things: the structure of the SRP exchange itself, and the Anisette data carried alongside it — the one-time password (X-Apple-I-MD), machine ID (X-Apple-I-MD-M), and the identifiers binding them to a machine. Local ADI provisioning succeeds (xtool's finding), which says the ADI libraries will still mint a one-time password; it says nothing about whether the handler still accepts what it mints. The most likely shape of the change, in order:
The handler now validates the Anisette machine data against something it didn't before — provisioning recency, machine-identifier consistency between the OTP and the body, or a new required field in the init plist. This fits every observation: provisioning succeeds, junk-body edge probes pass (they carry no anisette data at all), and every client regardless of headers is refused identically.
The handler rejects an entire class of machine identities — e.g. identities whose provisioning came from an emulator-emulating path (the unicorn-based providers many of these tools use) rather than real ADI hardware. This would fit the "any account, any IP, any headers" shape too.
A required new field in the init body that only genuine Apple clients send. Least likely, but the cheapest to test.
What would settle it, and what nobody has published: a real SRP init body, sent without credentials (init runs before the password is checked, so this is still not a sign-in attempt and carries no account risk), with the Anisette contents varied one at a time — fresh vs. stale provisioning, serial present vs. absent, OTP from a different provider. Whichever variation changes the answer is where the rule lives.
To get started: scripts/probe_gsa_signin.py probes the edge with arbitrary header variants (--set Name=Value, --unset Name, --client-info "...") and no account involved. Its BODY docstring documents exactly where the handler-level extension goes — a --real-init mode building the genuine init body from the pinned FindMy.py's own SRP machinery, reporting the response plist's ec code, and varying the Anisette contents. That mode does not exist yet; building it is the first contribution worth making, and the script is structured so it reuses everything already there.
Once it exists: run the baseline, vary the Anisette contents one at a time, and compare ec codes. A variation that flips -80045 to something else is the answer.
And wherever you find the cause, please take it beyond this issue. Every project linked above is locked out identically and none of them can see this thread — post it to those trackers, xtool #329 first since its maintainer is actively investigating there. The whole ecosystem gets unblocked by one finding only if it travels.
For this app specifically: there is nothing to fix on our side until the rule is understood. The next release adds a remote-Anisette fallback and logs Apple's error code so failures like this are recognisable, but there is no evidence yet that a different Anisette source gets past this refusal, and we won't promise that it will.
As of this time, these are the latest findings across the other trackers. No project has published a cause or a fix: no fix branch, pull request or release in Impactor, isideload/iloader, xtool, SideStore, AltStore, anisette-v3-server or atvloadly.
Controlled probes on atvloadly, using a fake account and on-device Anisette, still get -80045 at SRP init after each of these changes: header case preserved, the four CPD flags sent as booleans, and Client-Time, TimeZone and Locale added. This makes hypothesis 3 above less likely.
Cross-posting per this thread's request (this is not the -80045 refusal itself, but the blocker right behind it — and it is specific to fetching Find My reports):
The GSA -80045 refusal is now solvable — report an Android identity consistent with the Android CoreADI Anisette machine ID, and treat hsc=409 in the GSA complete response as the 2FA prompt (Apple no longer sends au). With those two, login + trusted-device 2FA + mobileme all succeed.
But since 2026-10-12 the com.apple.mobileme service-data tokens now contains only mmeAuthToken — searchPartyToken is gone. The report fetch (gateway.icloud.com/acsnservice/fetch) then returns HTTP 401. The token set appears tied to the (platform-consistent) Anisette identity: an Android identity passes mobileme but yields only mmeAuthToken, while a Mac identity with our Android Anisette is refused (status 1). So searchPartyToken may now require a genuine macOS/iOS Anisette.
This affects every project that reads tokens.searchPartyToken (OpenTagViewer, macless-haystack, …). If anyone has obtained searchPartyToken after 2026-10-12, please share.
Attribution, stated plainly: the person posting this did not write or review a single
line of code. The investigation and the fix were done by Devin (Fable 5.1), an automated
contributor, running against this repository. Everything below is what it observed, in its
own experiments — nothing is quoted second-hand.
Root cause, localised to one check
The refusal is not "Apple blocks third-party clients" — it is a provenance consistency
check in the GsService2 handler:
The ADI libraries every project provisions with are Apple's Android binaries (from
the Apple Music APK). The machine id they mint (X-Apple-I-MD-M) carries that origin.
Since 2026-10-12 the handler compares it against the platform X-MMe-Client-Info
claims. Android-minted machine id + macOS/iPhone client-info → ec=-80045, before
any credential is touched. A wrong OTP still gets -80045; only a missing OTP gets -80010, so the provenance verdict precedes authentication entirely.
Same machine id + Android client-info → ec=0 with the full SRP challenge
(i, s, sp, c, B).
Provenance is bound at provisioning: a machine id provisioned under a Mac claim and
then presented with an Android one is answered hsc=434 (re-sync demand) — you must
re-provision, not just change the string.
Second, independent finding: gsd.apple.com now chains to Apple Root CA – G3, which is
in no shipped trust store. That is the -45003/502 every remote Anisette server hit — not
a policy refusal, a TLS handshake failure on Apple's own provisioning endpoints.
How it was found
Extended probe_gsa_signin.py with --real-init: a structurally real SRP init
(srp.User.start_authentication()A2k, ps: [s2k, s2k_fo], synthetic nonexistent Apple
ID, real provisioned cpd) — the body the handler reads, while still never being a
sign-in attempt. Then varied one cpd field at a time:
variant
answer
no X-Apple-I-MD-M
ec=-80009 "MID is invalid"
junk X-Apple-I-MD-M
ec=-29004 "environment mismatch"
valid Android-minted MD-M + macOS client-info
ec=-80045
same + junk serial / junk device-id / junk X-Apple-I-MD
still -80045
same + Android client-info
ec=0
Mac-provisioned MD-M + Android client-info
hsc=434
second, independently provisioned machine id
same -80045 → a class check, not an identity ban
xtool found the client-info side independently (xtool-org/xtool#337, shipped in 1.22.2).
What this adds: the field-level proof that X-Apple-I-MD-M provenance is the trigger, the hsc=434 re-provisioning requirement, and the G3 root cause of the remote-server errors.
The fix, verified end to end
On rubo77/OpenTagViewer@feature/gsa-real-init (two commits, MR-ready):
Hardware.ANDROID profile (Pixel 7 / Android;14;UQ1A.240205.002 / com.apple.akd/1.0),
stored Mac/iPhone identities are replaced and anisette/provisioning is wiped before ADISetProvisioningPath so ADI re-provisions under the Android claim. Costs affected
installs one re-login.
Apple Root CA – G3 added as a trust anchor for gsa/gsd only.
Verified, honestly stated:
✅ --real-init against live Apple: ec=0 with a freshly Android-provisioned machine id
✅ On-device, Pixel 8 Pro: libraries download, ADI provisioning completes
(ADIProvisioningEnd = 0), sign-in accepts password and 2FA code
⚠️ After successful auth, that test account hit the known com.apple.mobileme delegate
refusal (status=1, "account never used with an Apple device") — an account-level gate,
unrelated to this fix
❓ Untested: an Apple ID that has previously been activated on real Apple hardware
should pass the mobileme gate and reach actual fetching — that final step awaits a
qualifying account
Thanks — this localises -80045 precisely, and matches what we found independently (Android-consistent identity → ec=0).
One complementary data point that may refine the mobileme conclusion, because your own last two bullets are the crux:
Your status=1 was the account gate (account never activated on real Apple hardware). We have the other half: our test Apple ID is activated (trusted-device 2FA prompts arrive, idms_pet is issued), and with the Android identity mobileme returns status=0 — so it clears the gate — but the com.apple.mobilemeservice-data.tokens contains only mmeAuthToken, never searchPartyToken:
[gsa] o=complete Status={'hsc': 409, ..., 'au': 'trustedDeviceSecondaryAuth'} # fixed as in your Android profile
[gsa] o=complete Status={'hsc': 200, ...} # 2FA code accepted
[mobileme] idms_pet_len=523
[mobileme] state=LOGGED_IN service_keys=['protocolVersion','tokens'] tokens=['mmeAuthToken']
And the report fetch rejects that token: https://gateway.icloud.com/acsnservice/fetch with Basic <dsid>:<mmeAuthToken> → HTTP 401 (identical to a bogus token).
We also compared identities in one session:
mobileme X-MMe-Client-Info
anisette
result
Android
Android
status=0, tokens = mmeAuthToken only
Mac
Android
status=1
So passing the mobileme gate does not yield searchPartyToken — the issued token set appears tied to the (platform-consistent) identity, and an Android identity never gets searchPartyToken. This suggests your final ❓ ("an activated account should reach actual fetching") may still stop at the fetch: the Android re-provisioning fix gets ec=0 and clears mobileme, but the Find My report fetch needs a token we haven't seen issued to Android identities.
If you or Devin can run the activated account through the fetch step, the one thing that settles it is: does searchPartyToken appear in mobilemetokens (or does the fetch return 200)? That is exactly the question in malmeloo/FindMy.py#278 (malmeloo/FindMy.py#278), also posted to macless-haystack#248. Great work — this is the first field-level proof of the provenance check.
Status as of 2026-10-14, with thanks to @rubo77 and @hoorayman for the field-level work above.
Merged:#262 adds Apple Root CA - G3 as a trust anchor for gsa.apple.com and gsd.apple.com. gsd.apple.com, where ADI provisioning goes, now chains to that root, which Android does not ship. This is the trust-anchor part of @rubo77's branch only, credited to them. It does not fix -80045 by itself.
Sessions created before 2026-10-12 are not affected. A phone signed in on app 1.1.0 is still fetching recent locations today.
What this means for you:
If you are signed in and seeing locations, stay signed in. Do not sign out, clear the app's data or reinstall, because signing in again currently fails.
If you cannot sign in, there is no fix to install yet. Avoid retrying repeatedly; repeated attempts may put the account at risk.
Next steps:
We are not switching the app to an Android identity yet. It would make everyone sign in again and add a new device to their Apple account, and the result would be a sign-in that cannot fetch locations, which would break users whose sessions work today. @rubo77's Sign in as the Android device the ADI libraries actually are — fixes #248 #261 stays open for that reason, and is where we start if that changes.
Same attribution as before: the person posting wrote or reviewed no code; Devin (Fable 5.1) does the work.
One correction worth making to the record. Our status=1 account was activated on real Apple hardware — it is signed into an iPhone XR with iCloud and Find My enabled, in daily use. So status=1 is not strictly "account never activated"; whatever gate it encodes is narrower than that (device registration, account score, something about the delegate request itself — unknown). Reporting that because it changes what a reproducing account needs to look like, and because @hoorayman's activated-account result (status=0, mmeAuthToken only) shows the gate and the token set are two separate questions: their activated account passed mobileme, ours — also activated, Find My and all — did not. Worth understanding what distinguishes them before the token question is even reached.
Experiment instrumented and queued. rubo77/OpenTagViewer@feature/gsa-real-init now logs the names of the service tokens Apple issues, on every completed sign-in — Sign-in issued N service token(s): [...]. Values are never logged; names only (the diff is the last commit on that branch if anyone wants to check). An activated account goes through the full flow on a Pixel 8 Pro, on this build. We'll report back whether it clears mobileme at all, and if it does, whether searchPartyToken appears in tokens — and whether acsnservice/fetch accepts it or still answers 401.
TL;DR: The problem seems to be that even if you get in to the account by saying you are an Android phone (the SideStore fix), you are not always given the grants needed to fetch FindMy location reports. So the SideStore fix is part of the fix here, but here it requires more work to get it to return FindMy reports again consistently (as well as the whole iCloud account recovery route to work in general, which is untested right now I think).
To be clear I have not tested the work of the two users above myself yet as I am busy with some other projects, so I am assuming they are on it. Anybody else experimenting and testing this is of course helpful. Current status would be:
We can login as an Android phone by sending different headers than the app does now (The SideStore fix). This gives us a logged in account, but no FindMy network location fetch permissions.
Fetching location reports seems to depend on the grant above. If you don't get that one you can't actually fetch reports using base FindMy.py (not the OpenTagViewer FindMy.py fork)
This app built a custom iCloud "account recovery" flow that also depended on the login. This is what allows you to log in to your apple account in the app and never have to export the tags again - it syncs with your iCloud account in the app. This is untested since this breakage/Android login fix I think. It's a prerequisite for getting the list of tags and their keys to be able to fetch them using that list for (2)
Same attribution as before: the person posting wrote or reviewed no
code; Devin (SWE-2) does the work and runs the experiments.
Two accounts, four runs, one answer so far.
Account
activated
accountsd claim
android.music claim
dev account
never
status=1
status=1
second account
iPhone XR, iCloud + Find My, daily use
status=1
status=1
The experiment behind the right-hand column: the delegate request's X-MMe-Client-Info and User-Agent were flipped from com.apple.AOSKit/282 (com.apple.accountsd/113) / iCloudHelper -
two macOS daemons on an Android claim, the same class of inconsistency
GSA answers with -80045 - to com.apple.AuthKit/1 (com.apple.android.music/4.9.6), the one client Apple itself ships on
Android. Same phone, same machine id, minutes apart. status=1,
unchanged, on both accounts.
So whatever status=1 gates on at com.apple.mobileme, it is not the
client-info claim - the check GSA runs at SRP init is not repeated
there.
Which leaves the variable @hoorayman's status=0 differs in: the
machine id's provenance. Ours is minted by the Android ADI libraries
on-device. Was the anisette behind your mobileme status=0 generated
by a server, or by local Android ADI? If yours came from a
non-Android-provisioned identity, the gate would be sitting on the
machine id itself - which our next experiment tests directly by
forcing a server identity for the same accounts.
Same attribution as before: the person posting wrote or reviewed no
code; Devin (Fable 5.1) does the work and runs the experiments.
A mechanical datum for status=1 that changes what it might mean.
The mobileme delegate request authenticates as apple-id : <the com.apple.gs.idms.pet token> - as HTTP Basic auth and in the body's password field. We instrumented the exchange in a test build, which
logs field lengths and key names only, never values. Both runs below
are apple@r.z11.de (activated: iPhone XR, iCloud + Find My, daily
use) signed in through a server anisette identity:
Read together: Grand Slam completed (ec=0, au=None, no 2FA
demanded) and returned a session - but neither com.apple.gs.idms.pet
nor com.apple.gs.idms.hb was populated in it. The fork reads the pet
with .get("token", ""), so the delegate request went out
authenticating with an empty password, and the status-message is the
literal truth: authentication failed. For these runs status=1 needs
no account gate at all - the credential it would authenticate with was
never issued.
What this does NOT establish:
Whether our earlier runs under the local Android-ADI identity
lacked the pet the same way (also status=1, but the probe did not
exist then - plausibly the same mechanism, unverified).
Whether t carried the tokens under different names or was empty
entirely - the token-name probe landed in this build but the next
sign-in was refused upstream first (below).
Most interestingly: whether the pet is issued only on the challenge path. @hoorayman's successful run went hsc=409 / trustedDeviceSecondaryAuth -> code -> hsc=200 and logged idms_pet_len=523. Ours went hsc=200 au=None straight through and
got idms_pet_len=0. If the pet is only minted when the login
completed trusted-device auth, then an au=None login starves the
delegate of its credential and status=1 is a consequence of the path, not the account.
@hoorayman: on your status=0 run, was the pet present precisely
because your login went through trusted-device auth? If so our data
matches yours exactly rather than contradicting it.
Two side observations, both probably benign:
Apple pushed trusted-device verification codes to the iPhone on runs
where the flow itself never requested one (au=None) - an
informational push, not a prompt our UI failed to show.
A later sign-in attempt was refused at Grand Slam with HTTP 503 at
SRP init, before the password - plausibly the rate limiting @parawanderer warned about. We have stopped retrying the account.
Same attribution as before (Devin/SWE-2 does the work and runs the experiments).
Following on the idms_pet_len=0 finding, the next test on our side:
Force the challenge path. Re-provision the local ADI identity (a fresh, untrusted machine id) so the same account goes through hsc=409 / trustedDeviceSecondaryAuth -> code -> hsc=200, then read idms_pet at the delegate step.
If the pet appears (~523, like @hoorayman's), status=1 is a path consequence: an au=None login for this identity class is issued no pet, and the delegate cannot authenticate anything. The interesting part would then be why Apple treats the login as not requiring a challenge yet refuses to bind the credential - and whether real clients get an au demanding the challenge where ours got None.
If it stays empty, the refusal is bound to the machine identity itself, and no client-side claim fixes it.
The instrumented build also sniffs the decrypted spd now, so the same run shows which token names t actually carries - answering the "issued under a different name" question in the same shot.
(Waiting out the apparent 503 rate-limit first - no more hammering.)
@rubo77 — confirming directly, and it lines up exactly with your mechanism.
Yes. Our status=0 run is the challenge path, end to end:
[gsa] complete hsc=409, au=trustedDeviceSecondaryAuth # we inject au from hsc=409
[gsa] complete hsc=200 # trusted-device code accepted
[mobileme] idms_pet_len=523 # pet present
[mobileme] status=0, tokens=['mmeAuthToken']
And our earlier runs — before we handled hsc=409, so findmy skipped 2FA and went straight to the delegate on an au=None login — had idms_pet_len=0 and mobileme status=1. That is the same mechanism you describe: an empty pet → the delegate request authenticates with an empty password.
So your two runs and ours agree: for this (Android-ADI) identity class the pet is minted on the trusted-device challenge path, not on au=None — status=1 on the au=None path is a consequence of the path, not the account. (It also matches the idms_hb_len=0 you saw; same starvation.)
The caveat that keeps this issue open: even with the pet present (status=0), the com.apple.mobilemeservice-data.tokens still contained only mmeAuthToken — no searchPartyToken — and the fetch still answered 401.
And a data point for the platform-binding question, from @sacca97 below (FindMy.py#278): a Windows identity (provisioning + 2FA + loginDelegates all accepted) got mailToken + mmeAuthToken — a different set than Android's single mmeAuthToken, consistent with "the set follows the claimed platform" — but still no searchPartyToken, and every token 401s on both findmyservice/v2/fetch and acsnservice/fetch. Windows is therefore not a shortcut; this is narrowing to macOS/iOS only.
Solved — with a real Mac. Answering the open question from this thread and malmeloo/FindMy.py#278: a native macOS AOSKit anisette identity is issued the full token set including searchPartyToken, and the report fetch then returns real reports.
Result (reproduced end to end on a physical Mac, macOS 10.15.8 / x86_64)
[gsa] o=init Status={'hsc':200,'ec':0,...} # no -80045
[gsa] o=complete Status={'hsc':409,...} # trusted-device 2FA demanded
[gsa] o=complete Status={'hsc':200,...} # after the code
mobileme tokens issued:
['mmeFMFAppToken','keyTransparencyToken','mapsToken','searchPartyToken',
'mmeFMIPToken','cloudKitToken','mmeFMIPSiriToken','mmeFMIPAppToken',
'mmeAuthToken','mmeBTMMInfiniteToken']
*** searchPartyToken PRESENT ***
POST https://gateway.icloud.com/acsnservice/fetch (Basic dsid:searchPartyToken + native anisette) → HTTP 200 with payloads; decrypted → real coordinates, e.g. 2026-10-15 07:52:07 lat=37.863506 lon=112.506846.
How the native identity is obtained
The anisette python lib is always Android ADI (arch=arm64-v8a), even on macOS — that's why macOS alone changes nothing. You must use the Mac's own AOSKit.framework:
Note the keys are X-Apple-MD / X-Apple-MD-M (no X-Apple-I- prefix) — map them to X-Apple-I-MD / X-Apple-I-MD-M. Use the Mac client-info (<MacBookPro18,3> <Mac OS X;13.4.1;22F8> <com.apple.AOSKit/282 (com.apple.accountsd/113)>).
The token is NOT portable — the Mac must stay in the loop
fetch request
result
native Mac anisette + Mac searchPartyToken
HTTP 200
Android anisette + Mac searchPartyToken
HTTP 401
no anisette + Mac searchPartyToken
HTTP 401
So a searchPartyToken obtained with a Mac identity only works together with that Mac's native anisette — you cannot harvest the token once and fetch from a Linux/Windows box. Consequence: the Find My login + fetch run on the Mac (it can serve many accounts; the anisette is machine-level). A hosted Mac or a macOS VM is the production shape.
Practical gotchas
TLS: gsa.apple.com chains to the old Apple Root CA (O=Apple Inc./OU=Apple Certification Authority), which is not in certifi → python.org Python fails with self-signed certificate in certificate chain. Add that root (and Apple Root CA - G3 for gsd.apple.com, as @rubo77 found) to a bundle and point SSL_CERT_FILE at it. (curl works because it uses the macOS keychain; Python does not.)
2FA flow is as in the thread: hsc=409 → trusted-device code; the phone 2FA page (/auth) is 403 for these clients.
Net: a native macOS/iOS identity is the requirement. Android (and, per earlier reports, Windows) will not receive searchPartyToken. Patch scripts and the full log are in the linked repo; happy to share.
(Posted by a human, with an AI assistant doing the engineering.)
Thank you to both of you @rubo77 and @hoorayman for looking into this and @hoorayman for figuring this out! I think this would be a design change on the FindMy.py end as this would now require a Mac to be running somewhere and producing these anisette reports. Since most users wouldn't have a mac they can leave running/on permanently, an initial fix might look like seeing if some kind of QEMU VM Mac could be made to run and produce these reports instead? Though this obviously instantly makes the service much heavier than the ones everybody has been using in the anisette ecosystem before.
The question would also be whether we could try to understand if we can reproduce the Mac anisette behaviour in the library somehow to skip needing a Mac entirely (this would be the ideal for the entire FindMy ecosystem), or if there is some limitation by which this is now impossible.
So I guess this leaves two things:
The immediate fix might be to create a Mac-based anisette server wrapper (runs on any Mac) followed by some sort of QEMU Mac container that runs this. Running a MacOS in a container is already an existing tool (I know of sickcodes/Docker-OSX which I have used and it works) but it currently requires UI interaction to get it running, and it has a slow startup time.
The other question would be to investigate if the Mac's anisette protocol can be reproduced without the Mac (or plausibly an iPhone/iPad's anisette protocol reproduced without an iPhone/iPad, I suspect it'll be equivalent). Note that I don't know of any projects that have accomplished this before, as neighbouring projects like OpenBubbles/rustpush are based on running on a Mac, presumably because of the same limitation which they probably hit earlier for the iMessage token aspect (I have not checked for more projects myself).
Independent confirmation of @hoorayman's result (posted while I was writing this), on a newer setup, plus two things not covered above: a macOS 27.0.1 Mac we tried fails the same call, and the fetch does not have to run on the Mac. Only the anisette has to come from it. That is the "Mac-based anisette server wrapper" shape suggested above, and we are running it now.
Setup
An Apple Silicon MacBook Air on macOS 26.4, SIP enabled, signed into iCloud with the same Apple ID.
An ordinary ad-hoc-signed binary calls +[AOSUtilities retrieveOTPHeadersForDSID:@"-2"] (AOSKit) and gets X-Apple-MD / X-Apple-MD-M with no special entitlements. The same call on the one macOS 27.0.1 Mac we tried fails with AOSKit WARN: Info request failed: -45070 and returns no headers, even run from a plain Terminal. One machine only (different model and account), so this may be 27 tightening the entitlement check or something about that machine. Worth checking before upgrading a Mac that serves anisette.
We serve that anisette over HTTP (anisette-v1 JSON). The machine's own X-Mme-Device-Id, X-Apple-I-SRL-NO and X-Apple-I-MD-LU come from AKDevice. Then we run the usual GSA → loginDelegates flow, with every X-MMe-Client-Info set to that Mac's real serverFriendlyDescription (<MacBookAirX,Y> <macOS;26.4;…>).
Results
GSA ec=0. On the account where the Mac is a trusted device, no second factor was asked. A second account went through hsc=409 → SMS → hsc=200.
loginDelegates returns status=0 with the full token set: searchPartyToken, mmeFMIPToken, mmeFMFAppToken, cloudKitToken, … (both accounts).
acsnservice/fetch with that token plus the same Mac's anisette → 200 with fresh reports.
The same token plus Android (anisette-v3-server) anisette → 401.
What this suggests
The token set depends on the platform the anisette was minted on. This agrees with the Android-only-mmeAuthToken and Windows-mailToken results above.
The token is usable only with anisette from the machine that obtained it. Signing in once on a Mac and then fetching from Linux with Android anisette does not work.
A workable middle ground: one Mac (≤ macOS 26) serves anisette to headless fetchers elsewhere, for example over an SSH tunnel. That is what we run now. It is not macless, but the Mac only mints headers.
Not tested: whether a token from Mac A works with anisette from a different Mac B (machine-bound vs. merely "must be macOS").
Activity
Offer the remote server when Apple refuses before the password
parawanderer commentedon Oct 12, 2026
Apple refused the sign-in at its first step, before your password was sent, so the password is not the problem:
Email verification failed: This action cannot be completed at this time.appears in all four attempts in your log, with the app's on-device Anisette working each time.Two things to check:
In 1.1.2 there is no way to switch to a remote Anisette server once the on-device one works, which is the other thing worth trying for this error. The next release adds a "Try a remote server" button for exactly this failure, and records Apple's error code in the log so a failure like this one can be told apart from others.
parawanderer commentedon Oct 13, 2026
This is not specific to this app. Apple began refusing third-party Grand Slam sign-ins on 2026-10-12 (
ec=-80045, "This action cannot be completed at this time"), across every project on this authentication path: AltStore #1828, SideStore #1645, iloader #859, xtool #329, atvloadly #215, plus Sideloadly and PlumeImpactor reports in those threads. Your log shows exactly that signature: refused before your password was sent, on-device Anisette working each time. One caution from those threads: repeated sign-in attempts may put the account at risk, so let it rest rather than retrying.Where it is broken. A sign-in request passes two checkpoints:
Our
check_gsa_edge.pyprobe tests the edge daily and passes for every identity we send — yet real sign-ins are refused with HTTP 200, which means the request got past the edge and the handler refused it. So the rule Apple added is behind the front door, in how the handler evaluates the Anisette data and SRP exchange carried in the body.What has been ruled out (from controlled probes in the threads above): it is not the password or account — synthetic accounts get the identical error; it is not the client-info strings that caused September's 503s — string variants change nothing; and it is not local Anisette provisioning failing — xtool's provisioning succeeds, then GsService init is refused anyway.
If you want to help unbreak it, thank you — nobody has published the experiment that localises this yet, and the tooling to run it is in this repo:
How to investigate, and our current hypothesis
The investigation below is Claude Code's (an AI model), working from the issue threads and this repository's wire documentation. It is reasoning from evidence, not a confirmed finding — treat it as a starting hypothesis, and treat every claim about what Apple "must" be doing as a guess worth testing.
The handler's decision at SRP init happens before any password is checked, so it can only be evaluating two things: the structure of the SRP exchange itself, and the Anisette data carried alongside it — the one-time password (
X-Apple-I-MD), machine ID (X-Apple-I-MD-M), and the identifiers binding them to a machine. Local ADI provisioning succeeds (xtool's finding), which says the ADI libraries will still mint a one-time password; it says nothing about whether the handler still accepts what it mints. The most likely shape of the change, in order:unicorn-based providers many of these tools use) rather than real ADI hardware. This would fit the "any account, any IP, any headers" shape too.What would settle it, and what nobody has published: a real SRP init body, sent without credentials (init runs before the password is checked, so this is still not a sign-in attempt and carries no account risk), with the Anisette contents varied one at a time — fresh vs. stale provisioning, serial present vs. absent, OTP from a different provider. Whichever variation changes the answer is where the rule lives.
To get started:
scripts/probe_gsa_signin.pyprobes the edge with arbitrary header variants (--set Name=Value,--unset Name,--client-info "...") and no account involved. ItsBODYdocstring documents exactly where the handler-level extension goes — a--real-initmode building the genuine init body from the pinned FindMy.py's own SRP machinery, reporting the response plist'seccode, and varying the Anisette contents. That mode does not exist yet; building it is the first contribution worth making, and the script is structured so it reuses everything already there.Once it exists: run the baseline, vary the Anisette contents one at a time, and compare
eccodes. A variation that flips-80045to something else is the answer.And wherever you find the cause, please take it beyond this issue. Every project linked above is locked out identically and none of them can see this thread — post it to those trackers, xtool #329 first since its maintainer is actively investigating there. The whole ecosystem gets unblocked by one finding only if it travels.
For this app specifically: there is nothing to fix on our side until the rule is understood. The next release adds a remote-Anisette fallback and logs Apple's error code so failures like this are recognisable, but there is no evidence yet that a different Anisette source gets past this refusal, and we won't promise that it will.
Update, 2026-10-13 08:56 UTC
As of this time, these are the latest findings across the other trackers. No project has published a cause or a fix: no fix branch, pull request or release in Impactor, isideload/iloader, xtool, SideStore, AltStore, anisette-v3-server or atvloadly.
-80045at SRP init after each of these changes: header case preserved, the four CPD flags sent as booleans, and Client-Time, TimeZone and Locale added. This makes hypothesis 3 above less likely.anisetteID, while refreshing through a local AltServer reportedly works where a remote one fails. The working report does not say which OS it ran on.invalid Trust Key (-45003), andani.sidestore.ioreturns 502 (also seen on xtool). For now, switching to a remote server is unlikely to help.Add a Grand Slam edge probe that takes arbitrary header variants
hoorayman commentedon Oct 14, 2026
Cross-posting per this thread's request (this is not the
-80045refusal itself, but the blocker right behind it — and it is specific to fetching Find My reports):The GSA
-80045refusal is now solvable — report an Android identity consistent with the Android CoreADI Anisette machine ID, and treathsc=409in the GSAcompleteresponse as the 2FA prompt (Apple no longer sendsau). With those two, login + trusted-device 2FA +mobilemeall succeed.But since 2026-10-12 the
com.apple.mobilemeservice-datatokensnow contains onlymmeAuthToken—searchPartyTokenis gone. The report fetch (gateway.icloud.com/acsnservice/fetch) then returns HTTP 401. The token set appears tied to the (platform-consistent) Anisette identity: an Android identity passesmobilemebut yields onlymmeAuthToken, while a Mac identity with our Android Anisette is refused (status 1). SosearchPartyTokenmay now require a genuine macOS/iOS Anisette.Full evidence, raw logs and the 5 variants we tried: malmeloo/FindMy.py#278 — malmeloo/FindMy.py#278
This affects every project that reads
tokens.searchPartyToken(OpenTagViewer, macless-haystack, …). If anyone has obtainedsearchPartyTokenafter 2026-10-12, please share.rubo77 commentedon Oct 14, 2026
Attribution, stated plainly: the person posting this did not write or review a single
line of code. The investigation and the fix were done by Devin (Fable 5.1), an automated
contributor, running against this repository. Everything below is what it observed, in its
own experiments — nothing is quoted second-hand.
Root cause, localised to one check
The refusal is not "Apple blocks third-party clients" — it is a provenance consistency
check in the GsService2 handler:
the Apple Music APK). The machine id they mint (
X-Apple-I-MD-M) carries that origin.X-MMe-Client-Infoclaims. Android-minted machine id + macOS/iPhone client-info →
ec=-80045, beforeany credential is touched. A wrong OTP still gets
-80045; only a missing OTP gets-80010, so the provenance verdict precedes authentication entirely.ec=0with the full SRP challenge(
i, s, sp, c, B).then presented with an Android one is answered
hsc=434(re-sync demand) — you mustre-provision, not just change the string.
Second, independent finding:
gsd.apple.comnow chains to Apple Root CA – G3, which isin no shipped trust store. That is the
-45003/502 every remote Anisette server hit — nota policy refusal, a TLS handshake failure on Apple's own provisioning endpoints.
How it was found
Extended
probe_gsa_signin.pywith--real-init: a structurally real SRP init(
srp.User.start_authentication()A2k,ps: [s2k, s2k_fo], synthetic nonexistent AppleID, real provisioned
cpd) — the body the handler reads, while still never being asign-in attempt. Then varied one
cpdfield at a time:X-Apple-I-MD-Mec=-80009"MID is invalid"X-Apple-I-MD-Mec=-29004"environment mismatch"ec=-80045X-Apple-I-MD-80045ec=0hsc=434-80045→ a class check, not an identity banxtool found the client-info side independently (xtool-org/xtool#337, shipped in 1.22.2).
What this adds: the field-level proof that
X-Apple-I-MD-Mprovenance is the trigger, thehsc=434re-provisioning requirement, and the G3 root cause of the remote-server errors.The fix, verified end to end
On
rubo77/OpenTagViewer@feature/gsa-real-init(two commits, MR-ready):Hardware.ANDROIDprofile (Pixel 7 / Android;14;UQ1A.240205.002 / com.apple.akd/1.0),stored Mac/iPhone identities are replaced and
anisette/provisioningis wiped beforeADISetProvisioningPathso ADI re-provisions under the Android claim. Costs affectedinstalls one re-login.
gsa/gsdonly.Verified, honestly stated:
--real-initagainst live Apple:ec=0with a freshly Android-provisioned machine id(
ADIProvisioningEnd = 0), sign-in accepts password and 2FA codecom.apple.mobilemedelegaterefusal (
status=1, "account never used with an Apple device") — an account-level gate,unrelated to this fix
should pass the mobileme gate and reach actual fetching — that final step awaits a
qualifying account
hoorayman commentedon Oct 14, 2026
Thanks — this localises
-80045precisely, and matches what we found independently (Android-consistent identity →ec=0).One complementary data point that may refine the mobileme conclusion, because your own last two bullets are the crux:
Your
status=1was the account gate (account never activated on real Apple hardware). We have the other half: our test Apple ID is activated (trusted-device 2FA prompts arrive,idms_petis issued), and with the Android identitymobilemereturnsstatus=0— so it clears the gate — but thecom.apple.mobilemeservice-data.tokenscontains onlymmeAuthToken, neversearchPartyToken:And the report fetch rejects that token:
https://gateway.icloud.com/acsnservice/fetchwithBasic <dsid>:<mmeAuthToken>→ HTTP 401 (identical to a bogus token).We also compared identities in one session:
X-MMe-Client-Infostatus=0, tokens =mmeAuthTokenonlystatus=1So passing the mobileme gate does not yield
searchPartyToken— the issued token set appears tied to the (platform-consistent) identity, and an Android identity never getssearchPartyToken. This suggests your final ❓ ("an activated account should reach actual fetching") may still stop at the fetch: the Android re-provisioning fix getsec=0and clears mobileme, but the Find My report fetch needs a token we haven't seen issued to Android identities.If you or Devin can run the activated account through the fetch step, the one thing that settles it is: does
searchPartyTokenappear inmobilemetokens(or does the fetch return 200)? That is exactly the question in malmeloo/FindMy.py#278 (malmeloo/FindMy.py#278), also posted to macless-haystack#248. Great work — this is the first field-level proof of the provenance check.parawanderer commentedon Oct 14, 2026
Status as of 2026-10-14, with thanks to @rubo77 and @hoorayman for the field-level work above.
Merged: #262 adds Apple Root CA - G3 as a trust anchor for
gsa.apple.comandgsd.apple.com.gsd.apple.com, where ADI provisioning goes, now chains to that root, which Android does not ship. This is the trust-anchor part of @rubo77's branch only, credited to them. It does not fix-80045by itself.What we understand so far:
-80045is Apple refusing a machine id minted by the Android ADI libraries when the request claims to be a Mac or iPhone. Claiming an Android device over the same machine id getsec=0. Three groups found this independently: @rubo77's probe above, xtool (gsa: fix login using mismatched client-info xtool-org/xtool#337, shipped in 1.22.2 and confirmed working there), and the anisette-v3-server maintainer (Apple GrandSlam rejecting anisette-v3-server requests with error -80045 Dadoum/anisette-v3-server#61).mobileme, but receives onlymmeAuthTokenand nosearchPartyToken, and the location report fetch then returns 401. A SideStore user reports the same thing: sign-in works, iCloud does not.What this means for you:
Next steps:
searchPartyTokenat all. If you have obtained one after 2026-10-12, with any setup, please post the details here or on Since 2026-10-12: mobileme returns only mmeAuthToken (no searchPartyToken) — login OK, report fetch 401 malmeloo/FindMy.py#278.Trust Apple Root CA - G3 for gsa and gsd
Extend the Grand Slam probe to the sign-in handler, and find -80045 t…
Sign in as the Android device the ADI libraries actually are
Log which iCloud service tokens a sign-in was issued
rubo77 commentedon Oct 14, 2026
Same attribution as before: the person posting wrote or reviewed no code; Devin (Fable 5.1) does the work.
One correction worth making to the record. Our
status=1account was activated on real Apple hardware — it is signed into an iPhone XR with iCloud and Find My enabled, in daily use. Sostatus=1is not strictly "account never activated"; whatever gate it encodes is narrower than that (device registration, account score, something about the delegate request itself — unknown). Reporting that because it changes what a reproducing account needs to look like, and because @hoorayman's activated-account result (status=0,mmeAuthTokenonly) shows the gate and the token set are two separate questions: their activated account passedmobileme, ours — also activated, Find My and all — did not. Worth understanding what distinguishes them before the token question is even reached.Experiment instrumented and queued.
rubo77/OpenTagViewer@feature/gsa-real-initnow logs the names of the service tokens Apple issues, on every completed sign-in —Sign-in issued N service token(s): [...]. Values are never logged; names only (the diff is the last commit on that branch if anyone wants to check). An activated account goes through the full flow on a Pixel 8 Pro, on this build. We'll report back whether it clearsmobilemeat all, and if it does, whethersearchPartyTokenappears intokens— and whetheracsnservice/fetchaccepts it or still answers 401.sacca97 commentedon Oct 14, 2026
@parawanderer @rubo77 This might be a possible way to bypass error 80045: https://github.com/SideStore/SideSign/pull/5
parawanderer commentedon Oct 14, 2026
@sacca97 Check this summary from claude code.
TL;DR: The problem seems to be that even if you get in to the account by saying you are an Android phone (the SideStore fix), you are not always given the grants needed to fetch FindMy location reports. So the SideStore fix is part of the fix here, but here it requires more work to get it to return FindMy reports again consistently (as well as the whole iCloud account recovery route to work in general, which is untested right now I think).
To be clear I have not tested the work of the two users above myself yet as I am busy with some other projects, so I am assuming they are on it. Anybody else experimenting and testing this is of course helpful. Current status would be:
rubo77 commentedon Oct 14, 2026
Same attribution as before: the person posting wrote or reviewed no
code; Devin (SWE-2) does the work and runs the experiments.
Two accounts, four runs, one answer so far.
The experiment behind the right-hand column: the delegate request's
X-MMe-Client-InfoandUser-Agentwere flipped fromcom.apple.AOSKit/282 (com.apple.accountsd/113)/iCloudHelper-two macOS daemons on an Android claim, the same class of inconsistency
GSA answers with
-80045- tocom.apple.AuthKit/1 (com.apple.android.music/4.9.6), the one client Apple itself ships onAndroid. Same phone, same machine id, minutes apart.
status=1,unchanged, on both accounts.
So whatever
status=1gates on atcom.apple.mobileme, it is not theclient-info claim - the check GSA runs at SRP init is not repeated
there.
Which leaves the variable @hoorayman's
status=0differs in: themachine id's provenance. Ours is minted by the Android ADI libraries
on-device. Was the anisette behind your mobileme
status=0generatedby a server, or by local Android ADI? If yours came from a
non-Android-provisioned identity, the gate would be sitting on the
machine id itself - which our next experiment tests directly by
forcing a server identity for the same accounts.
sacca97 commentedon Oct 14, 2026
Windows get an extra token (malmeloo/FindMy.py#278 (comment)) but not the one we need.
Also web findmy (https://www.icloud.com/find) does not work either for airtags.
parawanderer commentedon Oct 14, 2026
@sacca97 Web FindMy never had AirTags (or FindMy "gadgets") FYI, hence the reason I came up with the app. Good to know about windows
rubo77 commentedon Oct 14, 2026
Same attribution as before: the person posting wrote or reviewed no
code; Devin (Fable 5.1) does the work and runs the experiments.
A mechanical datum for
status=1that changes what it might mean.The mobileme delegate request authenticates as
apple-id : <the com.apple.gs.idms.pet token>- as HTTP Basic auth and in the body'spasswordfield. We instrumented the exchange in a test build, whichlogs field lengths and key names only, never values. Both runs below
are
apple@r.z11.de(activated: iPhone XR, iCloud + Find My, dailyuse) signed in through a server anisette identity:
Read together: Grand Slam completed (
ec=0,au=None, no 2FAdemanded) and returned a session - but neither
com.apple.gs.idms.petnor
com.apple.gs.idms.hbwas populated in it. The fork reads the petwith
.get("token", ""), so the delegate request went outauthenticating with an empty password, and the status-message is the
literal truth: authentication failed. For these runs
status=1needsno account gate at all - the credential it would authenticate with was
never issued.
What this does NOT establish:
lacked the pet the same way (also
status=1, but the probe did notexist then - plausibly the same mechanism, unverified).
tcarried the tokens under different names or was emptyentirely - the token-name probe landed in this build but the next
sign-in was refused upstream first (below).
challenge path. @hoorayman's successful run went
hsc=409 / trustedDeviceSecondaryAuth-> code ->hsc=200and loggedidms_pet_len=523. Ours wenthsc=200 au=Nonestraight through andgot
idms_pet_len=0. If the pet is only minted when the logincompleted trusted-device auth, then an
au=Nonelogin starves thedelegate of its credential and
status=1is a consequence of thepath, not the account.
@hoorayman: on your
status=0run, was the pet present preciselybecause your login went through trusted-device auth? If so our data
matches yours exactly rather than contradicting it.
Two side observations, both probably benign:
where the flow itself never requested one (
au=None) - aninformational push, not a prompt our UI failed to show.
SRP init, before the password - plausibly the rate limiting
@parawanderer warned about. We have stopped retrying the account.
rubo77 commentedon Oct 14, 2026
Same attribution as before (Devin/SWE-2 does the work and runs the experiments).
Following on the
idms_pet_len=0finding, the next test on our side:Force the challenge path. Re-provision the local ADI identity (a fresh, untrusted machine id) so the same account goes through
hsc=409 / trustedDeviceSecondaryAuth-> code ->hsc=200, then readidms_petat the delegate step.status=1is a path consequence: anau=Nonelogin for this identity class is issued no pet, and the delegate cannot authenticate anything. The interesting part would then be why Apple treats the login as not requiring a challenge yet refuses to bind the credential - and whether real clients get anaudemanding the challenge where ours gotNone.The instrumented build also sniffs the decrypted
spdnow, so the same run shows which token namestactually carries - answering the "issued under a different name" question in the same shot.(Waiting out the apparent 503 rate-limit first - no more hammering.)
Instrument the mobileme exchange: credential lengths and issued token…
hoorayman commentedon Oct 15, 2026
@rubo77 — confirming directly, and it lines up exactly with your mechanism.
Yes. Our
status=0run is the challenge path, end to end:And our earlier runs — before we handled
hsc=409, so findmy skipped 2FA and went straight to the delegate on anau=Nonelogin — hadidms_pet_len=0and mobilemestatus=1. That is the same mechanism you describe: an empty pet → the delegate request authenticates with an empty password.So your two runs and ours agree: for this (Android-ADI) identity class the pet is minted on the trusted-device challenge path, not on
au=None—status=1on theau=Nonepath is a consequence of the path, not the account. (It also matches theidms_hb_len=0you saw; same starvation.)The caveat that keeps this issue open: even with the pet present (
status=0), thecom.apple.mobilemeservice-data.tokensstill contained onlymmeAuthToken— nosearchPartyToken— and the fetch still answered 401.And a data point for the platform-binding question, from @sacca97 below (FindMy.py#278): a Windows identity (provisioning + 2FA + loginDelegates all accepted) got
mailToken+mmeAuthToken— a different set than Android's singlemmeAuthToken, consistent with "the set follows the claimed platform" — but still nosearchPartyToken, and every token 401s on bothfindmyservice/v2/fetchandacsnservice/fetch. Windows is therefore not a shortcut; this is narrowing to macOS/iOS only.hoorayman commentedon Oct 15, 2026
Solved — with a real Mac. Answering the open question from this thread and malmeloo/FindMy.py#278: a native macOS AOSKit anisette identity is issued the full token set including
searchPartyToken, and the report fetch then returns real reports.Result (reproduced end to end on a physical Mac, macOS 10.15.8 / x86_64)
POST https://gateway.icloud.com/acsnservice/fetch(Basicdsid:searchPartyToken+ native anisette) → HTTP 200 with payloads; decrypted → real coordinates, e.g.2026-10-15 07:52:07 lat=37.863506 lon=112.506846.How the native identity is obtained
The
anisettepython lib is always Android ADI (arch=arm64-v8a), even on macOS — that's why macOS alone changes nothing. You must use the Mac's ownAOSKit.framework:Note the keys are
X-Apple-MD/X-Apple-MD-M(noX-Apple-I-prefix) — map them toX-Apple-I-MD/X-Apple-I-MD-M. Use the Mac client-info (<MacBookPro18,3> <Mac OS X;13.4.1;22F8> <com.apple.AOSKit/282 (com.apple.accountsd/113)>).The token is NOT portable — the Mac must stay in the loop
searchPartyTokensearchPartyTokensearchPartyTokenSo a
searchPartyTokenobtained with a Mac identity only works together with that Mac's native anisette — you cannot harvest the token once and fetch from a Linux/Windows box. Consequence: the Find My login + fetch run on the Mac (it can serve many accounts; the anisette is machine-level). A hosted Mac or a macOS VM is the production shape.Practical gotchas
gsa.apple.comchains to the old Apple Root CA (O=Apple Inc./OU=Apple Certification Authority), which is not in certifi → python.org Python fails withself-signed certificate in certificate chain. Add that root (and Apple Root CA - G3 forgsd.apple.com, as @rubo77 found) to a bundle and pointSSL_CERT_FILEat it. (curl works because it uses the macOS keychain; Python does not.)cryptography<47(newer releases dropped the 10.9 universal2 wheel).hsc=409→ trusted-device code; the phone 2FA page (/auth) is 403 for these clients.Net: a native macOS/iOS identity is the requirement. Android (and, per earlier reports, Windows) will not receive
searchPartyToken. Patch scripts and the full log are in the linked repo; happy to share.(Posted by a human, with an AI assistant doing the engineering.)
parawanderer commentedon Oct 15, 2026
Thank you to both of you @rubo77 and @hoorayman for looking into this and @hoorayman for figuring this out! I think this would be a design change on the FindMy.py end as this would now require a Mac to be running somewhere and producing these anisette reports. Since most users wouldn't have a mac they can leave running/on permanently, an initial fix might look like seeing if some kind of QEMU VM Mac could be made to run and produce these reports instead? Though this obviously instantly makes the service much heavier than the ones everybody has been using in the anisette ecosystem before.
The question would also be whether we could try to understand if we can reproduce the Mac anisette behaviour in the library somehow to skip needing a Mac entirely (this would be the ideal for the entire FindMy ecosystem), or if there is some limitation by which this is now impossible.
So I guess this leaves two things:
WDYT?
poterpan commentedon Oct 15, 2026
Independent confirmation of @hoorayman's result (posted while I was writing this), on a newer setup, plus two things not covered above: a macOS 27.0.1 Mac we tried fails the same call, and the fetch does not have to run on the Mac. Only the anisette has to come from it. That is the "Mac-based anisette server wrapper" shape suggested above, and we are running it now.
Setup
+[AOSUtilities retrieveOTPHeadersForDSID:@"-2"](AOSKit) and getsX-Apple-MD/X-Apple-MD-Mwith no special entitlements. The same call on the one macOS 27.0.1 Mac we tried fails withAOSKit WARN: Info request failed: -45070and returns no headers, even run from a plain Terminal. One machine only (different model and account), so this may be 27 tightening the entitlement check or something about that machine. Worth checking before upgrading a Mac that serves anisette.X-Mme-Device-Id,X-Apple-I-SRL-NOandX-Apple-I-MD-LUcome fromAKDevice. Then we run the usual GSA →loginDelegatesflow, with everyX-MMe-Client-Infoset to that Mac's realserverFriendlyDescription(<MacBookAirX,Y> <macOS;26.4;…>).Results
ec=0. On the account where the Mac is a trusted device, no second factor was asked. A second account went throughhsc=409→ SMS →hsc=200.loginDelegatesreturnsstatus=0with the full token set:searchPartyToken,mmeFMIPToken,mmeFMFAppToken,cloudKitToken, … (both accounts).acsnservice/fetchwith that token plus the same Mac's anisette → 200 with fresh reports.What this suggests
mmeAuthTokenand Windows-mailTokenresults above.Not tested: whether a token from Mac A works with anisette from a different Mac B (machine-bound vs. merely "must be macOS").
sacca97 commentedon Oct 16, 2026
@parawanderer sorted, please test independently: https://github.com/sacca97/os-findmy-e