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.
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").
@jonnoberg-beep officially do to resolve it right now? Well, you could test the solution from #248 (comment) as a remote/external anisette server URL. Ideally it would be nice to create a derived library that can be run on android directly off of that implementation, instead of requiring a remote server. I suggest following this thread: malmeloo/FindMy.py#278 (comment)
@parawanderer in the native folder of my repo there is a (vibe-coded) rust port of the whole thing that "ideally" can replace all your python dependencies in the app. It includes the emulator bindings, and findmy.py + anisette.py logic necessary to login, fetch, etc.
I did test it in a mockup app on my phone and it works, I would not call it production ready tho.
any update on what an end user can do about this? is it possible to use the key generated by https://github.com/sacca97/os-findmy-e with opentagviewer somehow? currently this is a blocker for me using an airtag I have as the only apple device I have is an ipad and I can't exactly carry that around with me
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
11 remaining items
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
jonnoberg-beep commentedon Oct 19, 2026
@parawanderer so what can i do to resolve this problem?
parawanderer commentedon Oct 21, 2026
@jonnoberg-beep officially do to resolve it right now? Well, you could test the solution from #248 (comment) as a remote/external anisette server URL. Ideally it would be nice to create a derived library that can be run on android directly off of that implementation, instead of requiring a remote server. I suggest following this thread: malmeloo/FindMy.py#278 (comment)
sacca97 commentedon Oct 21, 2026
@parawanderer in the
nativefolder of my repo there is a (vibe-coded) rust port of the whole thing that "ideally" can replace all your python dependencies in the app. It includes the emulator bindings, and findmy.py + anisette.py logic necessary to login, fetch, etc.I did test it in a mockup app on my phone and it works, I would not call it production ready tho.
spidunno commentedon Oct 25, 2026
any update on what an end user can do about this? is it possible to use the key generated by https://github.com/sacca97/os-findmy-e with opentagviewer somehow? currently this is a blocker for me using an airtag I have as the only apple device I have is an ipad and I can't exactly carry that around with me
parawanderer commentedon Oct 26, 2026
@spidunno there are two options here: