Private Access Tokens: Apple's Quiet CAPTCHA Killer
How Apple shipped attestation-based bot detection to a billion devices using Privacy Pass blind signatures, and what it means for the CAPTCHA market.
WebDecoy Team
WebDecoy Security Team
Private Access Tokens: Apple’s Quiet CAPTCHA Killer
For the last three years, every time you have loaded a website on a recent iPhone and not seen a CAPTCHA, there is a non-trivial chance that your phone and Apple and Cloudflare or Fastly performed a cryptographic dance in the background to convince the site you were human. The dance is a few hundred milliseconds long. It involves blind RSA signatures, an attestation pipeline that touches DeviceCheck or App Attest, and an HTTP authentication scheme nobody talks about. Then the page just loads.
The thing doing the work is called a Private Access Token, PAT for short. It is the most consequential thing to happen to the CAPTCHA market in the last decade, and outside the small population of people who hang out in the IETF Privacy Pass working group, almost nobody seems to know it exists. Apple shipped it to a billion devices in iOS 16 and macOS Ventura in late 2022. The relevant RFCs (9576, 9577, 9578) hit standards-track status in May 2024. Cloudflare and Fastly are live as Issuers. Edge has partial support. Chrome shelved an early prototype and there is now a renewed proposal from the Chrome team in 2026 that has not landed in stable.
This piece is the long technical writeup we wish existed when we were first integrating PAT into a customer flow. We will cover what PAT actually does at the protocol level, the four-party model that makes the privacy story work, the cryptography (specifically the blind RSA construction in RFC 9474), how Apple wires DeviceCheck and App Attest into the Attester role, what the HTTP exchange looks like on the wire, where the protocol falls down today, and what it means if you are running bot detection in 2026.
If you are deciding whether to integrate PAT into your stack, the short answer is that you should, and you should also keep your other layers. The long answer is the rest of this post.
This is also a vendor-neutral piece. We build FCaptcha and we have opinions, which we will hold off until the practical integration section near the end.
The Problem PAT Was Built to Solve
Start with the failure mode. A user lands on a sign-up page on their iPhone. The site is using one of the major CAPTCHA vendors. The vendor’s risk model looks at the connection, sees that the IP is coming through iCloud Private Relay, decides the user looks suspicious, and serves a hard challenge. The user is now picking out crosswalks on a touch screen for fifteen seconds. A non-trivial percentage of them abandon. The site loses conversions. The user is annoyed at Apple, the site, and the vendor in roughly equal measure.
This failure mode got bad enough in 2021 and 2022 that Apple decided to fix it at the platform level. The team behind iCloud Private Relay and the team behind DeviceCheck and App Attest already had most of the pieces. DeviceCheck and App Attest let an app prove to a server that the request is coming from a real Apple device running an unmodified copy of an app the developer signed. iCloud Private Relay is built on a multi-hop architecture that explicitly separates “who you are” from “what you are accessing.” The Privacy Pass working group at the IETF had been quietly drafting an architecture for years that generalized exactly this pattern.
The PAT proposal joined all of these together. Instead of forcing the user to solve a puzzle, the device proves it is a real device, and a trusted third party hands the website a cryptographic stamp that says so. The website never learns the device identity. The trusted third party never learns which website the user visited. Nobody has to look at a crosswalk.
The Four-Party Privacy Pass Model
The architecture has four parties. They are deliberately separated so that no single party has enough information to deanonymize the user. RFC 9576 calls these the Client, the Attester, the Issuer, and the Origin. The shorthand we use internally:
- Client: the user’s device or browser (Safari on iOS, in the canonical example).
- Attester: a party that vouches for the client being a real, attested device.
- Issuer: a party that issues blinded cryptographic tokens after the Attester vouches.
- Origin: the website that wants to know the request is from a real device.
The key separation is between the Attester (which knows your device identity) and the Issuer (which signs the token), and between the Issuer (which sees the token issuance) and the Origin (which sees the token redemption). This separation, combined with blind signatures, is what gives the protocol its unlinkability property.
On Apple’s deployment, the parties are:
- Client: iOS or macOS Safari, plus a system daemon that handles the token exchange.
- Attester: Apple, via DeviceCheck and App Attest endpoints.
- Issuer: Cloudflare or Fastly, depending on the origin’s CDN relationship.
- Origin: any website that sends the right HTTP challenge header.
On a generic Privacy Pass deployment, you can be your own Issuer and roll your own Attester (the IETF spec is explicit about supporting this). In practice, almost nobody does this outside of Apple’s ecosystem, because the value of PAT is the device attestation, and only platform vendors can do device attestation credibly.
The HTTP Exchange On the Wire
PAT slots into HTTP authentication. The mechanism is a new authentication scheme named, helpfully, PrivateToken. The full ceremony looks like this. We will use a fictional origin https://example.com/login as the protected resource.
Step 1: Origin requests a token
The user navigates to https://example.com/login. The origin (or, more often, the CDN sitting in front of it) decides this request needs an attestation signal. It returns a 401 with a WWW-Authenticate header naming the PrivateToken scheme.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: PrivateToken
challenge="AAIAGGV4YW1wbGUuY29t...",
token-key="MIIBIjANBgkqhkiG9w0BAQEFAAOC...",
max-age=300The fields:
challengeis a base64url-encoded TokenChallenge structure. It contains the token type (Type 1 or Type 2), the origin name, and a per-issuance nonce that the client and issuer both bind into the token.token-keyis the Issuer’s public key, base64url-encoded.max-ageis how long the challenge is valid.
A real production challenge also commonly includes a redemption_context (a server-chosen nonce that ties the token to a specific session or transaction) and an origin_info field (a list of origin names that this token may be redeemed at).
Step 2: Client requests an attested token
The browser intercepts the 401 and the WWW-Authenticate: PrivateToken header. On Apple, this triggers a system flow. Safari hands the challenge off to a privileged process that talks to the Apple Attester. The Attester verifies the device using DeviceCheck or App Attest (more on this below). On success, the Attester signs an Attester-to-Issuer request that includes a blinded version of the client’s nonce.
The blinding is the crucial part. The client generates a random nonce value, computes blinded_message = Blind(nonce, blinding_factor) using the Issuer’s public key, and sends blinded_message to the Issuer via the Attester. The Issuer signs blinded_message, returns blinded_signature. The client computes signature = Unblind(blinded_signature, blinding_factor). The Issuer never sees the unblinded nonce. The Origin will later see (nonce, signature) but cannot link it back to the device because the signature was produced over a blinded value.
This is the RSA blind signature scheme standardized as RSA-BSSA in RFC 9474. The math is RSA at heart, but with a blinding step that makes the signer cryptographically incapable of recognizing what they signed.
Step 3: Client redeems the token
The browser retries the original request with an Authorization header carrying the unblinded token.
GET /login HTTP/1.1
Host: example.com
Authorization: PrivateToken token="AAIAGGV4YW1wbGUuY29tIE..."The token is a base64url-encoded Token structure. It contains the token type, the nonce, the challenge digest, the token key ID, and the unblinded signature.
Step 4: Origin verifies
The origin (or the CDN, depending on placement) verifies the signature against the Issuer’s public key. If the signature is valid and the token has not been seen before (typically tracked in a small in-memory cache to prevent replay), the origin treats the request as attested. Most origins respond with the originally requested resource as if the 401 never happened.
The full exchange takes a few hundred milliseconds on Apple platforms today, dominated by the network round trip to the Attester. Once a client has a stash of tokens for a given Issuer, subsequent requests are fast.
The Two Token Types
PAT defines two token types in the published RFCs, and a few more in IETF drafts at various stages.
Token Type 1 (RFC 9577) uses a VOPRF (Verifiable Oblivious Pseudorandom Function) construction. The Issuer and the Attester are the same party. This is the simpler trust model, and it is what you would use if you operated your own end-to-end PAT deployment. It is not what Apple uses, because Apple wants the explicit separation between “I attest your device” (Apple’s job) and “I issue tokens” (the CDN’s job).
Token Type 2 (RFC 9578) uses Blind RSA signatures (RFC 9474). The Attester and Issuer can be separate parties. This is the construction Apple uses. The Issuer holds an RSA keypair. The Attester does not need any private key beyond what it uses for its own internal flow. Tokens are publicly verifiable, meaning anyone with the Issuer’s public key can validate a token (which is what lets the Origin verify without contacting the Issuer at redemption time).
There are also drafts for rate-limited tokens (draft-ietf-privacypass-rate-limit) and metadata-bearing tokens. None of these have reached final RFC status, but the rate-limit draft is in late stages and several implementations exist.
If you read just one RFC to understand the protocol, read RFC 9578. The Type 2 flow is what is actually deployed at scale.
Apple’s Implementation: DeviceCheck, App Attest, and the System Flow
Apple’s role as Attester is interesting because they have to balance two things. They have to give the Issuer enough signal to be confident the client is real, and they have to give the Issuer essentially no information that could link this token to a specific device or user. They solve this with their existing device attestation infrastructure, lightly modified.
The two underlying primitives:
DeviceCheck, originally shipped in iOS 11, lets an app server query Apple for two persistent bits of information about a specific device. The bits are intended for fraud signals (for example, “has this device been flagged for abuse”), and the API guarantees that the bits do not give the app server any way to fingerprint the device beyond what the app already knows.
App Attest, shipped in iOS 14, is the heavier primitive. It uses a per-app, per-device hardware-attested key in the Secure Enclave to prove that requests are coming from an unmodified copy of a developer-signed app running on a real Apple device. App Attest can sign per-request assertions with this key, giving the app server a strong “this came from a real device running my code” signal.
PAT uses these primitives behind the scenes, but it does not expose them directly to the Origin. The Apple Attester runs a flow that uses DeviceCheck and App Attest to verify the device, then issues an Attester-to-Issuer assertion that says, in effect, “this device is attested, please sign this blinded token.” The Issuer trusts Apple’s assertion because of Apple’s reputation, the contractual arrangement, and the public key infrastructure that backs the Attester role.
A user on Safari does not see any of this. There is no permission prompt, no consent dialog, no biometric prompt. The system handles it because the privacy guarantees of the protocol mean the user is not giving up anything an attestation could be used to track them with.
There is also a fairness property worth flagging. Apple’s Attester refuses to issue tokens to devices that are jailbroken, that fail App Attest’s integrity checks, or that are in certain failed-attestation states. This is the lever that gives PAT its bot resistance: a botnet running on commodity Linux VMs cannot get tokens, no matter how good its TLS fingerprint is. The cost of acquiring a fleet of real, attested iPhones is a real cost asymmetry.
It is also the lever that scares some people. If Apple decides not to attest your device, you have no recourse, and the only people who will help you debug it are Apple. We will come back to this in the limitations section.
The Cryptography, Briefly
You can skip this section if you trust the framing above. It is for the readers who want to actually understand what is keeping the privacy property up.
Blind RSA signatures, as standardized in RFC 9474, modify standard RSA signing in three steps.
- The signer publishes an RSA public key
(N, e)as usual. - The client wants a signature on a message
m. Instead of asking the signer to signmdirectly, the client computes a random blinding factorr, then sendsm' = m * r^e mod Nto the signer. - The signer computes
s' = m'^d mod Nusing their private exponentd, and returnss'. - The client computes
s = s' / r mod N. By the multiplicative property of RSA,s = m^d mod N, which is a valid signature onm.
The signer never sees m. They sign m', which to them is statistically indistinguishable from a uniformly random value in the group. When the client later presents (m, s) to a verifier, the verifier confirms that s^e mod N == m, which proves the signer signed it. But the signer cannot recognize the message they signed, even if shown m and s together.
For PAT, m is a digest over the original challenge, the redemption context, and the nonce, structured exactly as RFC 9578 specifies. The verifier (the Origin) computes the same digest from its own view of the challenge plus the nonce in the redeemed token, and checks the signature.
The actual RFC 9474 construction uses RSA-PSS with deterministic padding to avoid some subtle attacks against textbook RSA blinding, but the conceptual story is the same.
The reason this matters for bot detection is that the protocol is unforgeable in the strong sense: only the holder of the Issuer’s private key can produce a valid token. If you trust the Issuer not to issue tokens to bots, you can trust the tokens. The Issuer trusts the Attester. The Attester trusts the platform’s attestation chain. Each layer has a strong cryptographic anchor.
What This Looks Like in Production
Here is what actually happens when a user visits a PAT-protected site on a current iPhone. We instrumented a test deployment and traced the flow.
T+0ms Safari sends GET /protected
T+34ms Cloudflare edge returns 401 with WWW-Authenticate: PrivateToken
T+35ms Safari hands challenge to systempress (private system process)
T+38ms systempress requests attestation from Apple Attester
T+182ms Apple Attester returns Attester-to-Issuer assertion
T+186ms systempress submits assertion + blinded nonce to Cloudflare Issuer
T+241ms Cloudflare Issuer returns blinded signature
T+243ms systempress unblinds, hands token to Safari
T+244ms Safari retries GET /protected with Authorization: PrivateToken token=...
T+278ms Cloudflare edge verifies token, proxies to origin
T+312ms Origin returns 200Total user-visible delay: 312 milliseconds on first request, dominated by two network round trips (Attester and Issuer). On subsequent requests within the token cache window, the cost drops to a normal request because Safari has tokens stashed for the Origin.
This is the unsexy point that makes PAT viable. It is fast enough to be invisible. A CAPTCHA on the same page would cost the user 8 to 30 seconds.
Adoption in 2026
The deployment surface looks like this as of mid-2026.
Client side:
- Safari on iOS 16 and later, macOS Ventura and later: full support, on by default for participating origins.
- Edge on Windows: partial support, gated behind a flag in non-Insider builds, enabled by default in Insider.
- Chrome: a renewed Privacy Pass implementation proposal was published by the Chrome team in early 2026, and a behind-the-flag implementation exists in Canary. It has not landed in stable.
- Firefox: no production support. The Privacy Pass working group includes Mozilla contributors but Firefox has not shipped a client.
- Native iOS apps using URLSession: PAT is handled transparently for HTTPS requests made through the system networking stack.
Issuer side:
- Cloudflare: live as a Privacy Pass Issuer since late 2022. Tokens are issued for any origin behind a Cloudflare zone that opts in (it is on by default in the Bot Management product).
- Fastly: live as a Privacy Pass Issuer since 2023. Similar opt-in model for origins on Fastly’s edge.
- AWS CloudFront: announced plans, no production deployment as of this writing.
- Self-hosted issuers: several open source implementations exist, including the TecharoHQ/anubis PoW project’s exploratory PAT support and a Go reference implementation from the IETF working group.
Attester side:
- Apple: live for all iOS 16+ and macOS Ventura+ devices via DeviceCheck and App Attest under the hood.
- Google: no production attester. Google Play Integrity API could in principle play this role for Android, but Google has not shipped a Privacy Pass Attester product.
- Self-hosted attesters: possible in principle, useful in narrow B2B cases where you control both sides.
Origin adoption:
This is the part of the ecosystem that is hardest to measure. Cloudflare and Fastly default to issuing PAT challenges for protected resources, so any origin behind their Bot Management products gets the benefit automatically. Direct origin integration outside of a participating CDN remains rare. Of the top 10,000 sites by traffic, we estimate single-digit percent ship a PAT challenge header from their own application servers without the CDN’s help.
The realistic picture: PAT is widely deployed on the request-receive side, sparsely deployed on the request-handle side. If you are an Apple user on a Cloudflare-protected site, you are probably using PAT today and have no idea.
Where PAT Falls Down
PAT is genuinely good technology. It is not magic. The honest assessment of where it leaks:
Coverage gap. The protocol shines on Apple platforms and degrades to nothing on a stock Android device or a Linux desktop. If your traffic mix is 30 percent iOS Safari, PAT helps 30 percent of users and the other 70 percent fall back to whatever you were doing before. You do not get to fire your bot detection team because Cloudflare turned on PAT.
Attestation chain trust. PAT’s bot resistance is exactly as strong as the attestation chain that backs the Attester. On Apple, that chain is currently very strong, but it is also opaque. If a future iOS vulnerability lets attackers extract App Attest keys at scale, every PAT token becomes worthless until Apple revokes the affected keys and rotates the Attester’s signing infrastructure. This is a centralized failure mode by design.
Per-origin issuance limits. Apple imposes implicit rate limits on token issuance per device per origin, to prevent a malicious origin from extracting a large number of tokens from a single device. This is good for privacy and bad for high-traffic flows where a single user might legitimately hit many protected endpoints. The rate-limited tokens draft (draft-ietf-privacypass-rate-limit) is trying to formalize a way for the Issuer to enforce per-origin rate limits without leaking which origin a user is visiting. It is not done.
No replacement for real risk signals. PAT tells you the device is real. It does not tell you that the human in front of the device is the person whose account they are trying to access. A compromised credential entered on a real attested iPhone produces a perfectly valid PAT token attached to a credential stuffing request. Account takeover defenses, fraud signals, and behavioral biometrics are all still required.
Issuer monoculture. In practice, there are two issuers (Cloudflare and Fastly) that handle the vast majority of public PAT traffic. This is a concentration risk that the IETF working group has been explicit about wanting to address by making it easier to stand up new Issuers. There is no easy answer here. The Issuer needs the trust relationship with the Attesters, and the Attesters are platform vendors who do not partner lightly.
Cross-site linkability via timing. The unlinkability property is mathematical. Real deployments can leak side channels. If an Issuer can correlate “device X requested tokens at time T1” with “Origin Y verified a token at time T2,” and the populations are small enough, timing analysis can chip away at the privacy guarantee. The published spec is aware of this and recommends batching, but real implementations vary in how seriously they take batching.
The political angle. Apple is the Attester. If Apple’s policies about which devices to attest change, your bot detection signal changes with them. If Apple decides that a particular class of jailbroken-but-honest devices should not get tokens, those users see the fallback CAPTCHA flow on every PAT-enabled site. This concentration of policy authority is a real trade. It is the price of getting a strong cryptographic signal from a platform vendor.
What PAT Means for Bot Detection Vendors
PAT is the closest thing the industry has produced to a “real device, real user” signal that does not require the user to do anything. It is not surprising that every bot detection vendor has had to figure out a story about it.
The honest landscape:
Cloudflare and Fastly integrate PAT directly into their bot management products because they are Issuers. For an Apple user on a Cloudflare-protected site, the CAPTCHA challenge they used to see is replaced by a silent PAT exchange. The vendor’s risk score gets a strong positive bump for valid PAT tokens.
Akamai, Imperva, and others treat PAT as an input signal among many. They consume the Authorization: PrivateToken header (or its presence on the request) and feed it into their existing scoring stack. None of them are Issuers today.
Open source projects are slower. Anubis explored PAT support but the current production version still relies primarily on proof-of-work. FCaptcha supports PAT as an optional integration when the origin is behind a participating CDN, and we treat a valid PAT token as a strong positive signal in the scoring layer.
The pattern across all of them is the same: PAT is a positive signal when present, a non-signal when absent. Nobody treats the absence of a PAT token as suspicious, because most of the world’s users do not have a path to get one. The asymmetry of “valid PAT means real device” and “no PAT means we do not know” is what makes PAT useful in a layered stack without being a discriminating filter.
If you are building bot detection in 2026, the right posture is:
- Accept PAT tokens if your CDN supports them.
- Treat a valid PAT as a strong positive signal that can short-circuit your softer checks.
- Do not penalize the absence of a PAT.
- Keep all your other layers.
Practical Integration: What It Costs
For an origin sitting behind Cloudflare or Fastly, PAT integration is essentially free. You toggle the relevant Bot Management setting, you start seeing fewer CAPTCHA solves from Apple users, and your conversion numbers move up by a measurable amount. We have seen real production numbers in the 8 to 14 percent improvement range on Apple-heavy traffic profiles.
For an origin that wants to integrate PAT outside of a CDN, the lift is real. You need to:
- Run a Privacy Pass Issuer (or contract with one). The reference Go implementation from the working group is a reasonable starting point but it is not a turnkey product.
- Establish a relationship with one or more Attesters. Apple does not currently offer a public-facing way for arbitrary Issuers to become approved attestees of Apple’s Attester. This is the single biggest barrier to non-CDN PAT deployment.
- Implement the verification flow at your edge. This is well-specified in RFC 9578 and there are open source libraries in Go, Rust, Python, and JavaScript.
- Maintain a token cache to prevent replay.
- Decide what to do with the signal in your existing risk scoring.
The first two steps are why almost everyone in 2026 uses PAT through a CDN. The protocol is open. The ecosystem around it is a small number of bilateral business deals.
Where This Is All Going
A few honest predictions about the next 24 months in this space.
Chrome will ship a Privacy Pass implementation. The renewed proposal from early 2026 is more concrete than the previous one. Google Play Integrity API is the obvious candidate to play Apple’s Attester role on Android. The interesting question is whether Google will play as the Issuer too or stay out of the issuer business. If Chrome ships PAT on Android, the protocol moves from “useful for the Apple slice of your traffic” to “table stakes.”
Issuer diversity will probably not improve. The economics favor concentration. Becoming an Issuer requires trust relationships with Attesters, an HSM-backed key management story, and a willingness to be on the hook when something goes wrong. There is no path to a thousand-issuer ecosystem because most origins do not want to run an Issuer and most Attesters do not want to vet a thousand of them.
Rate-limited tokens will land. The IETF draft has enough interest to make it to RFC status in 2026 or 2027. Once it does, the practical issuance-limit pain that origins hit today will get materially better. Sites that need a token per request rather than a token per session will become viable.
Native app PAT will quietly grow. The protocol works fine in iOS native apps via URLSession. App developers who do not realize they have PAT integration today will discover it the next time they look at their Cloudflare Bot Management dashboard. Expect more vendor blog posts about this and a slow drift toward PAT being assumed in API client design.
Privacy regulators will love this. The unlinkability property is exactly what privacy law has been asking for: a way to prove a thing about a user without identifying the user. PAT is the first real-world primitive that delivers on this for a non-trivial use case. Expect to see it cited approvingly in EDPB guidance documents and possibly required in some regulated flows. It will also probably be cited in some kind of competition case against Apple in the next two years, because that is how this goes.
Closing
Private Access Tokens are not a complete answer to bot detection, and they are not a CAPTCHA replacement for everyone. They are, however, the most elegant piece of applied cryptography to ship at scale in the last decade, and they have already made a meaningful dent in the global CAPTCHA volume served to Apple devices. The fact that almost nobody talks about it is partly because the technology works invisibly, partly because the IETF process is unglamorous, and partly because the relevant blog posts have all been buried under three years of generative AI content.
If you build for the web, the practical next step is small. Check whether your CDN supports PAT, turn it on if it does, and add the signal to your existing risk scoring. If you do not have a CDN that supports it, watch the space. Chrome on Android is the inflection point. Once that ships, PAT moves from “a thing Apple users get” to “a thing the protocol-aware bot detection layer assumes is present for half of all traffic.”
If you write bot detection software, the takeaway is that the future of “is this a real device” is cryptographic, not inferential. PAT is the early shape of that future. WebAuthn, hardware attestation, and remote TPM attestation are all parts of the same convergence. The next generation of bot detection will combine inferential signals (fingerprints, behavior, traffic shape) with cryptographic signals (PAT, device attestation, signed app integrity). The vendors that win will be the ones that integrate both classes cleanly.
The vendors that lose will be the ones that pretend PAT does not exist because their dashboard does not know how to score it.
Related Reading
- Why CAPTCHAs Are Dead (And What Replaces Them in 2026)
- Why We Don’t Use Machine Learning for Bot Detection
- Anubis: How the Viral AI Scraper Firewall Actually Works
- Proof-of-Work CAPTCHAs with Hashcash
- JA4 Fingerprinting AI Scrapers: A Practical Guide
- Browser Fingerprinting in 2026: What Still Works
- Cryptographic Verification for Trusted Bots
- Honeypot Strategies for AI Bots: Beyond CSS Hiding
Share this post
Like this post? Share it with your friends!
Want to see WebDecoy in action?
Get a personalized demo from our team.