Microsoft Edge Origin Trials Developer Console

Trust Tokens API

This is a new API for propagating a notion of user authenticity across sites, without using cross-site persistent identifiers like third party cookies.

Available from Microsoft Edge Edge 102 to Edge 106

End Date 10/27/2022


he two keys was used to retrieve the value of the private metadata.

Extension: iframe Activation

Some resources requests are performed via iframes or other non-Fetch-based methods. One extension to support such use cases would be the addition of a trustToken attribute to iframes that includes the parameters specified in the Fetch API. This would allow an RR to be sent with an iframe by setting an attribute of trustToken="{type:'send-redemption-record',issuer:<issuer>,refreshPolicy:'refresh'}".

Privacy Considerations

Cryptographic Property: Unlinkability

In Privacy Pass, tokens have an unlinkability property: token issuance cannot be linked to token redemption.

The privacy of this API relies on that fact: the issuer is unable to correlate its issuances on one site with redemptions on another site. If the issuer gives out N tokens each to M users, and later receives up to N*M requests for redemption on various sites, the issuer can't correlate those redemption requests to any user identity (unless M = 1). It learns only aggregate information about which sites users visit.

However, there are a couple of finer points that need to be considered to ensure the underlying protocol remains private.

Key Consistency

If the server uses different values for their private keys for different clients, they can de-anonymize clients at redemption time and break the unlinkability property. To mitigate this, the Privacy Pass protocol should ensure that issuers publish a public key commitment list, verifies it is small (e.g. max 3 keys), and verifies consistency between issuance and redemption.

Potential Attack: Side Channel Fingerprinting

If the issuer is able to use network-level fingerprinting or other side-channels to associate a browser at redemption time with the same browser at token issuance time, privacy is lost. Importantly, the API itself has not revealed any new information, since sites could use the same technique by issuing GET requests to the issuer in the two separate contexts anyway.

Cross-site Information Transfer

Trust tokens transfer information about one first-party cookie to another, and we have cryptographic guarantees that each token only contains a small amount of information. Still, if we allow many token redemptions on a single page, the first-party cookie for user U on domain A can be encoded in the trust token information channel and decoded on domain B, allowing domain B to learn the user's domain A cookie until either 1p cookie is cleared. Separate from the concern of channels allowing arbitrary communication between domains, some identification attacks---for instance, a malicious redeemer attempting to learn the exact set of issuers that have granted tokens to a particular user, which could be identifying---have similar mitigations.

Mitigation: Dynamic Issuance / Redemption Limits

To mitigate this attack, we place limits on both issuance and redemption. At issuance, we require user activation with the issuing site. At redemption, we can slow down the rate of redemption by returning cached Redemption Records when an issuer attempts too many refreshes (see also the token exhaustion problem). These mitigations should make the attack take a longer time and require many user visits to recover a full user ID.

Mitigation: Allowed/Blocked Issuer Lists

To prevent abuse of the API, browsers could maintain a list of allowed or disallowed issuers. Inclusion in the list should be easy, but should mean agreeing to certain policies about what an issuer is allowed to do. An analog to this is the baseline requirements in the CA ecosystem.

Mitigation: Per-Site Issuer Limits

The rate of identity leakage from one site to another increases with the number of tokens redeemed on a page. To avoid abuse, there should be strict limits on the number of token issuers contacted per top-level origin (e.g. 2); this limit should apply for both issuance and redemption; and the issuers used on an origin should be persisted in browser storage to avoid excessively rotating issuers on subsequent visits. This should also apply for document.hasTrustToken, as the presence of tokens can be used as a tracking vector.

First Party Tracking Potential

Cached RRs and their associated browser public keys have a similar tracking potential to first party cookies. Therefore these should be clearable by browser’s existing Clear Site Data functionality.

The RR and its public key are untamperable first-party tracking vectors. They allow sites to share their first-party user identity with third parties on the page in a verifiable way. To mitigate this potentially undesirable situation, user agents can request multiple RRs in a single token redemption, each bound to different keypairs, and use different RRs and keypairs when performing requests based on the third-party or over time.

In order to prevent the issuer from binding together multiple simultaneous redemptions, the UA can blind the keypairs before sending them to the issuer. Additionally, the client may need to produce signed timestamps to prevent the issuer from using the timestamp as another matching method.

Security Considerations

Trust Token Exhaustion

The goal of a token exhaustion attack is to deplete a legitimate user's supply of tokens for a given issuer, so that user is less valuable to sites who depend on the issuer’s trust tokens.

We have a number of mitigations against this attack:

  • Issuers issue many tokens at once, so users have a large supply of tokens.
  • Browsers will only ever redeem one token per top-level page view, so it will take many page views to deplete the full supply.
  • The browser will cache RRs per-origin and only refresh them when an issuer iframe opts-in, so malicious origins won't deplete many tokens. The “freshness” of the RR becomes an additional trust signal.
  • Browsers may choose to limit redemptions on a time-based schedule, and either return cached RRs if available, or require consumers to cache the RR.
  • Issuers will be able to see the Referer, subject to the page's referrer policy, for any token redemption, so they'll be able to detect if any one site is redeeming suspiciously many tokens.

When the issuer detects a site is attacking its trust token supply, it can fail redemption (before the token is revealed) based on the referring origin, and prevent browsers from spending tokens there.

Double-Spend Prevention

Issuers can verify that each token is seen only once, because every redemption is sent to the same token issuer. This means that even if a malicious piece of malware exfiltrates all of a users' trust tokens, the tokens will run out over time. Issuers can sign fewer tokens at a time to mitigate the risk.

Future Extensions

Publicly Verifiable Tokens

The tokens used in the above design require private key verification, necessitating a roundtrip to the issuer at redemption time for token verification and RR generation. Here, the unlinkability of a client’s tokens relies on the assumption that the client and issuer can communicate anonymously (i.e. the issuer cannot link issuance and redemption requests from the same user via a side channel like network fingerprint).

An alternative design that avoids this assumption is to instead use publicly verifiable tokens (i.e. tokens that can be verified by any party). It is possible to instantiate these tokens using blind signatures as well, achieving the same unlinkability properties of the existing design. These tokens can be spent without a round trip to the issuer, but it requires either decentralized double spend protection, or round trips to a centralized double-spend aggregator.

Request mechanism not based on fetch()

A possible enhancement would be to allow for sending Redemption Records (and signing requests using the trust keypair) for requests sent outside of fetch(), e.g. on top-level and iframe navigation requests. This would allow for the use of the API by entities that aren't running JavaScript directly on the page, or that want some level of trust before returning a main response.

Optimizing redemption RTT

If the publisher can configure issuers in response headers (or otherwise early in the page load), then they could invoke a redemption in parallel with the page loading, before the relevant fetch() calls.

Non-web sources of tokens

Trust token issuance could be expanded to other entities (the operating system, or native applications) capable of making an informed decision about whether to grant tokens. Naturally, this would need to take into consideration different systems' security models in order for these tokens to maintain their meaning. (For instance, on some platforms, malicious applications might routinely have similar privileges to the operating system itself, which would at best reduce the signal-to-noise ratio of tokens created on those operating systems.)


Sample API Usage

areyouahuman.example - Trust Token Issuer
coolwebsite.example - Publisher Top-Level Site
foo.example - Site requiring a Trust Token to prove the user is trusted.
  1. User visits areyouahuman.example.
  2. areyouahuman.example verifies the user is a human, and calls fetch('areyouahuman.example/.well-known/trust-token', {trustToken: {type: 'token-request', issuer: 'areyouahuman.example'}}).
    1. The browser stores the trust tokens associated with areyouahuman.example.
  3. Sometime later, the user visits coolwebsite.example.
  4. coolwebsite.example wants to know if the user is a human, by asking areyouahuman.example that question, by calling fetch('areyouahuman.example/.well-known/trust-token', {trustToken: {type: 'token-redemption', issuer: 'areyouahuman.example'}}).
    1. The browser requests a redemption.
    2. The issuer returns an RR (this indicates that areyouahuman.example at some point issued a valid token to this browser).
    3. When the promise returned by the method resolves, the RR can be used in subsequent resource requests.
  5. Script running code in the top level coolwebsite.example document can call fetch('foo.example/get-content', {trustToken: {type: 'send-redemption-record', issuer: 'areyouahuman.example'}})
    1. The third-party receives the RR, and now has some indication that areyouahuman.example thought this user was a human.
    2. The third-party responds to this fetch request based on that fact.

Sample Redemption Record Format

Different issuers/ecosystems should specify their own Redemption Record format so downstream consumers are able to parse it. One potential structure is:

  Redemption timestamp,
  ClientData: {
    Publisher Origin
  Metadata: {
    Trust Token Key ID
  Signature of the above verifiable by well-known public key of the issuer,
  SigAlg: <Well known algorithm identifier used to sign this RR>,
  optional expiry timestamp

The redemption timestamp is included to prove the freshness of the RR. The ClientData comes from the client as part of the redemption request and includes the publisher the redemption occurred on, allowing an issuer to bind a RR to a particular redeeming origin. The Metadata includes the key ID, so that consumers of the RR can query the issuer what different metadata values mean.