chromium/third_party/blink/public/common/origin_trials/origin_trials_token_structure.md

# Origin Trials Framework Token Structure

## Overview

The use of tokens is described fully in [Origin Trials Framework Design Outline](https://docs.google.com/document/d/1qVP2CK1lbfmtIJRIm6nwuEFFhGhYbtThLQPo3CSTtmg/edit#heading=h.gdjrm0kg6sg9). Briefly, tokens are generated for a specific combination of origin and experimental feature, known as an origin trial. The origin must present the trial token when intending to use a feature, which is then verified by the browser.  This document provides the details of token structure and validation.


## Token Format

Trial tokens are base64-encoded binary structures, containing a signed JSON-encoded string, as shown in the diagram below:
```
 _____________________________________
| Token version number (1 byte)       |
|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|
| Public Key Signature (64 bytes)     |
|_____________________________________|
| Payload Length (4 bytes, big-endian)|
|‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾|
| Origin                              |
| Feature name     <=== Payload       |
| ...more               (JSON string) |
|_____________________________________|
```

**Version** (1 byte): This should be the byte 0x02 or 0x03 (the preferred version), representing version 2 and 3, which this document describes. Version 2 is supported from M51 and Version 3 is supported from M86. There is no correlation to browser version.

**Signature**: (64 bytes): Ed25519(private_key, signed_data)

**Payload_length**: (4 bytes): Big-endian unsigned 32-bit integer representing the size of the payload field, in bytes.

**Payload**: The payload is a JSON string, encoding a dictionary which should contain these keys:


*   origin
*   isSubdomain [Optional]
    *   This key will often be omitted to minimize the size of the token
*   isThirdParty [Optional]
*   usage [Optional]
    *   This key should only be specified if **isThirdParty** is true
*   feature
*   expiry

**signed_data**: This is the concatenation of the version, payload length and payload fields.

**origin** = scheme + "://" + host + ":" + port

**isSubdomain** = true|false. Indicates if the token should match all subdomains of the given origin. When the key is omitted, that is equivalent to specifying value = false.

**isThirdParty** = true|false. Indicates if the token should match third party origins. When the key is omitted, that is equivalent to specifying value = false.

**usage** = ""|"subset". Indicates the usage restriction to be applied to the token. When the key is omitted, that is equivalent to specifying value = "".

**scheme** = the UTF-8 encoding of "https"|"http"|"chrome-extension"

**host** = the UTF-8 encoding of the hostname

**port** = the UTF-8 encoding of the port number in base-10 digits.

**feature** = A UTF-8 encoded string representing the name of an feature available for origin trials.

**expiry** = the UTC timestamp, as an integer number of seconds since the Unix epoch.


## Samples


### Regular Token on version 3

_This is a typical token, which is used for one exact domain._

Origin: https://example.com/

Feature Name: "Frobulate"

Expiry Date: 2020-12-31 23:59:59 (1609459199)

Payload (83 characters)

 `{"origin": "https://example.com:443", "feature": "Frobulate", "expiry": 1609459199}`

Signed Data: (88 bytes):


```
03 00 00 00 53 7b 22 6f 72 69 67 69 6e 22 3a 20 22 68 74 74 70 73 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63 6f 6d 3a 34 34 33 22 2c 20 22 66 65 61 74 75 72 65 22 3a 20 22 46 72 6f 62 75 6c 61 74 65 22 2c 20 22 65 78 70 69 72 79 22 3a 20 31 36 30 39 34 35 39 31 39 39 7d
```


Signature: (Ed25519(private_key, data)) (64 bytes)


```
d6 13 93 95 8b 33 4b a1 5c f8 f6 38 4f dd 12 3f 26 11 d5 9b 71 63 af 0b 25 8c 35 d4 45 88 26 69 05 1b b2 9f 12 4c c7 58 bf 48 ee 69 45 3e d4 86 80 92 0d 38 9e a2 1f 6a 38 23 07 b1 cd b2 e7 0e
```


Complete Token: (152 bytes)


```
03 d6 13 93 95 8b 33 4b a1 5c f8 f6 38 4f dd 12 3f 26 11 d5 9b 71 63 af 0b 25 8c 35 d4 45 88 26 69 05 1b b2 9f 12 4c c7 58 bf 48 ee 69 45 3e d4 86 80 92 0d 38 9e a2 1f 6a 38 23 07 b1 cd b2 e7 0e 00 00 00 53 7b 22 6f 72 69 67 69 6e 22 3a 20 22 68 74 74 70 73 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63 6f 6d 3a 34 34 33 22 2c 20 22 66 65 61 74 75 72 65 22 3a 20 22 46 72 6f 62 75 6c 61 74 65 22 2c 20 22 65 78 70 69 72 79 22 3a 20 31 36 30 39 34 35 39 31 39 39 7d
```


Trial token: (204 characters)


```
A9YTk5WLM0uhXPj2OE/dEj8mEdWbcWOvCyWMNdRFiCZpBRuynxJMx1i/SO5pRT7UhoCSDTieoh9qOCMHsc2y5w4AAABTeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5IjogMTYwOTQ1OTE5OX0=
```


Meta Tag:


```
<meta http-equiv="origin-trial" content="A9YTk5WLM0uhXPj2OE/dEj8mEdWbcWOvCyWMNdRFiCZpBRuynxJMx1i/SO5pRT7UhoCSDTieoh9qOCMHsc2y5w4AAABTeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLmNvbTo0NDMiLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5IjogMTYwOTQ1OTE5OX0=" />
```

### Subdomain Token on version 3

_This token is used for matching all subdomains of an origin (e.g. valid for *.example.com)._

Origin: https://example.com/

Matches Subdomains: Yes

Feature Name: "Frobulate"

Expiry Date: 2020-12-31 23:59:59 (1609459199)

Payload (104 characters)

 `{"origin": "https://example.com:443", "isSubdomain": true, "feature": "Frobulate", "expiry": 1609459199}`

Signed Data: (109 bytes):


```
 03 00 00 00 68 7b 22 6f 72 69 67 69 6e 22 3a 20 22 68 74 74 70 73 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63 6f 6d 3a 34 34 33 22 2c 20 22 69 73 53 75 62 64 6f 6d 61 69 6e 22 3a 20 74 72 75 65 2c 20 22 66 65 61 74 75 72 65 22 3a 20 22 46 72 6f 62 75 6c 61 74 65 22 2c 20 22 65 78 70 69 72 79 22 3a 20 31 36 30 39 34 35 39 31 39 39 7d
```


Signature: (Ed25519(private_key, data)) (64 bytes)


```
31 e2 79 26 f7 35 71 d7 84 9d 73 bf 13 5c 99 47 91 df 9d 70 ce 55 f0 24 ae e9 60 cf 0c 08 57 cd 7a 7b e8 9d 98 b7 d2 44 b4 18 e2 96 52 57 88 c9 ab 6c ff 66 93 07 51 e8 88 29 8b 58 8b c6 e4 08
```


Complete Token: (173 bytes)


```
03 31 e2 79 26 f7 35 71 d7 84 9d 73 bf 13 5c 99 47 91 df 9d 70 ce 55 f0 24 ae e9 60 cf 0c 08 57 cd 7a 7b e8 9d 98 b7 d2 44 b4 18 e2 96 52 57 88 c9 ab 6c ff 66 93 07 51 e8 88 29 8b 58 8b c6 e4 08 00 00 00 68 7b 22 6f 72 69 67 69 6e 22 3a 20 22 68 74 74 70 73 3a 2f 2f 65 78 61 6d 70 6c 65 2e 63 6f 6d 3a 34 34 33 22 2c 20 22 69 73 53 75 62 64 6f 6d 61 69 6e 22 3a 20 74 72 75 65 2c 20 22 66 65 61 74 75 72 65 22 3a 20 22 46 72 6f 62 75 6c 61 74 65 22 2c 20 22 65 78 70 69 72 79 22 3a 20 31 36 30 39 34 35 39 31 39 39 7d


```


Trial token (232 characters):


```
AzHieSb3NXHXhJ1zvxNcmUeR351wzlXwJK7pYM8MCFfNenvonZi30kS0GOKWUleIyats/2aTB1HoiCmLWIvG5AgAAABoeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLmNvbTo0NDMiLCAiaXNTdWJkb21haW4iOiB0cnVlLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5IjogMTYwOTQ1OTE5OX0=
```


Meta Tag:


```
<meta http-equiv="origin-trial" content="AzHieSb3NXHXhJ1zvxNcmUeR351wzlXwJK7pYM8MCFfNenvonZi30kS0GOKWUleIyats/2aTB1HoiCmLWIvG5AgAAABoeyJvcmlnaW4iOiAiaHR0cHM6Ly9leGFtcGxlLmNvbTo0NDMiLCAiaXNTdWJkb21haW4iOiB0cnVlLCAiZmVhdHVyZSI6ICJGcm9idWxhdGUiLCAiZXhwaXJ5IjogMTYwOTQ1OTE5OX0=" />
```


### Third Party Token (only supported in Version 3)

_This token is used for matching third party origins._

Origin: https://thirdparty.com/

Feature Name: "Frobulate"

Matches Third Party Origins: True

Expiry Date: 2020-12-31 23:59:59 (1609459199)

Payload (108 characters)

 `{"origin": "https://thirdparty.com:443", "feature": "Frobulate", "expiry": 1609459199, "isThirdParty": true}`

Signed Data: (113 bytes):


```
03 00 00 00 6c 7b 22 6f 72 69 67 69 6e 22 3a 20 22 68 74 74 70 73 3a 2f 2f 74 68 69 72 64 70 61 72 74 79 2e 63 6f 6d 3a 34 34 33 22 2c 20 22 69 73 54 68 69 72 64 50 61 72 74 79 22 3a 20 74 72 75 65 2c 20 22 66 65 61 74 75 72 65 22 3a 20 22 46 72 6f 62 75 6c 61 74 65 22 2c 20 22 65 78 70 69 72 79 22 3a 20 31 36 30 39 34 35 39 31 39 39 7d
```


Signature: (Ed25519(private_key, data)) (64 bytes)


```
1f 14 b0 25 3d 11 40 51 8f c3 d9 1b 5e 3b 70 e3 bb 56 a4 7c e8 11 75 dd 34 ae eb 0d b0 46 a8 b1 cc 9f 9f 11 45 0b bc e4 22 99 7c 16 97 51 13 60 27 c0 64 c9 6f bc 0a a8 15 80 7c 1f 1a ec 64 0e
```


Complete Token: (177 bytes)


```
03 1f 14 b0 25 3d 11 40 51 8f c3 d9 1b 5e 3b 70 e3 bb 56 a4 7c e8 11 75 dd 34 ae eb 0d b0 46 a8 b1 cc 9f 9f 11 45 0b bc e4 22 99 7c 16 97 51 13 60 27 c0 64 c9 6f bc 0a a8 15 80 7c 1f 1a ec 64 0e 00 00 00 6c 7b 22 6f 72 69 67 69 6e 22 3a 20 22 68 74 74 70 73 3a 2f 2f 74 68 69 72 64 70 61 72 74 79 2e 63 6f 6d 3a 34 34 33 22 2c 20 22 69 73 54 68 69 72 64 50 61 72 74 79 22 3a 20 74 72 75 65 2c 20 22 66 65 61 74 75 72 65 22 3a 20 22 46 72 6f 62 75 6c 61 74 65 22 2c 20 22 65 78 70 69 72 79 22 3a 20 31 36 30 39 34 35 39 31 39 39 7d
```


Trial token: (236 characters)


```
Ax8UsCU9EUBRj8PZG147cOO7VqR86BF13TSu6w2wRqixzJ+fEUULvOQimXwWl1ETYCfAZMlvvAqoFYB8HxrsZA4AAABseyJvcmlnaW4iOiAiaHR0cHM6Ly90aGlyZHBhcnR5LmNvbTo0NDMiLCAiaXNUaGlyZFBhcnR5IjogdHJ1ZSwgImZlYXR1cmUiOiAiRnJvYnVsYXRlIiwgImV4cGlyeSI6IDE2MDk0NTkxOTl9
```


Meta Tag:


```
<meta http-equiv="origin-trial" content="Ax8UsCU9EUBRj8PZG147cOO7VqR86BF13TSu6w2wRqixzJ+fEUULvOQimXwWl1ETYCfAZMlvvAqoFYB8HxrsZA4AAABseyJvcmlnaW4iOiAiaHR0cHM6Ly90aGlyZHBhcnR5LmNvbTo0NDMiLCAiaXNUaGlyZFBhcnR5IjogdHJ1ZSwgImZlYXR1cmUiOiAiRnJvYnVsYXRlIiwgImV4cGlyeSI6IDE2MDk0NTkxOTl9" />
```


### Third Party Token with alternative usage restriction (only supported in version 3)

_This token is used for matching third party origins. It also contains instructions for using alternative usage restrictions._

Origin: https://thirdparty.com/

Feature Name: "Frobulate"

Matches Third Party Origins: True

Usage Restrictions: Subset

Expiry Date: 2020-12-31 23:59:59 (1609459199)

Payload (127 characters)

 `{"origin": "https://thirdparty.com:443", "feature": "Frobulate", "expiry": 1609459199, "isThirdParty": true, "usage": "subset"}`

Signed Data: (132 bytes):


```
03 00 00 00 7f 7b 22 6f 72 69 67 69 6e 22 3a 20 22 68 74 74 70 73 3a 2f 2f 74 68 69 72 64 70 61 72 74 79 2e 63 6f 6d 3a 34 34 33 22 2c 20 22 69 73 54 68 69 72 64 50 61 72 74 79 22 3a 20 74 72 75 65 2c 20 22 75 73 61 67 65 22 3a 20 22 73 75 62 73 65 74 22 2c 20 22 66 65 61 74 75 72 65 22 3a 20 22 46 72 6f 62 75 6c 61 74 65 22 2c 20 22 65 78 70 69 72 79 22 3a 20 31 36 30 39 34 35 39 31 39 39 7d
```


Signature: (Ed25519(private_key, data)) (64 bytes)


```
31 2c ed 7c d0 1b 99 2d 58 5f e9 ba ba 12 53 94 73 c4 f1 1d 11 45 21 ab 05 ed 2f 68 48 b5 9a 09 53 46 e0 84 ac 1b b1 32 95 82 19 11 f7 91 87 49 f2 0d 4c 19 f1 c1 10 67 15 57 d8 18 92 e6 f0 05
```


Complete Token: (196 bytes)


```
03 31 2c ed 7c d0 1b 99 2d 58 5f e9 ba ba 12 53 94 73 c4 f1 1d 11 45 21 ab 05 ed 2f 68 48 b5 9a 09 53 46 e0 84 ac 1b b1 32 95 82 19 11 f7 91 87 49 f2 0d 4c 19 f1 c1 10 67 15 57 d8 18 92 e6 f0 05 00 00 00 7f 7b 22 6f 72 69 67 69 6e 22 3a 20 22 68 74 74 70 73 3a 2f 2f 74 68 69 72 64 70 61 72 74 79 2e 63 6f 6d 3a 34 34 33 22 2c 20 22 69 73 54 68 69 72 64 50 61 72 74 79 22 3a 20 74 72 75 65 2c 20 22 75 73 61 67 65 22 3a 20 22 73 75 62 73 65 74 22 2c 20 22 66 65 61 74 75 72 65 22 3a 20 22 46 72 6f 62 75 6c 61 74 65 22 2c 20 22 65 78 70 69 72 79 22 3a 20 31 36 30 39 34 35 39 31 39 39 7d
```


Trial token: (264 characters)


```
AzEs7XzQG5ktWF/puroSU5RzxPEdEUUhqwXtL2hItZoJU0bghKwbsTKVghkR95GHSfINTBnxwRBnFVfYGJLm8AUAAAB/eyJvcmlnaW4iOiAiaHR0cHM6Ly90aGlyZHBhcnR5LmNvbTo0NDMiLCAiaXNUaGlyZFBhcnR5IjogdHJ1ZSwgInVzYWdlIjogInN1YnNldCIsICJmZWF0dXJlIjogIkZyb2J1bGF0ZSIsICJleHBpcnkiOiAxNjA5NDU5MTk5fQ==
```


Meta Tag:


```
<meta http-equiv="origin-trial" content="AzEs7XzQG5ktWF/puroSU5RzxPEdEUUhqwXtL2hItZoJU0bghKwbsTKVghkR95GHSfINTBnxwRBnFVfYGJLm8AUAAAB/eyJvcmlnaW4iOiAiaHR0cHM6Ly90aGlyZHBhcnR5LmNvbTo0NDMiLCAiaXNUaGlyZFBhcnR5IjogdHJ1ZSwgInVzYWdlIjogInN1YnNldCIsICJmZWF0dXJlIjogIkZyb2J1bGF0ZSIsICJleHBpcnkiOiAxNjA5NDU5MTk5fQ==" />
```

### Version 2 Tokens
Version 2 Tokens will have same payload for regular and subdomain tokens, the only difference is the first version byte becomes \x02.

Third party tokens are only supported in Version 3.

# Obsolete Versions:

## Version 1

This was the original specification, which was supported in Chrome M50, but not used to support any actual experiments in that release.