Learn Measure Blog Live About
A pile of envelopes.

Signed Exchanges (SXGs)

Signed Exchanges (SXGs)

An SXG is a delivery mechanism that makes it possible to authenticate the origin of a resource independently of how it was delivered.

A signed exchange (SXG) is a delivery mechanism that makes it possible to authenticate the origin of a resource independently of how it was delivered. This article provides an overview of SXGs.

Browser compatibility

SXGs are supported by Chromium-based browsers (starting with versions: Chrome 73, Edge 79, and Opera 64).

Overview

Signed Exchanges (SXGs) allow a site to cryptographically sign a request/response pair (an "HTTP exchange") in a way that makes it possible for the browser to verify the origin and integrity of the content independently of how the content was distributed. As a result, the browser can display the URL of the origin site in the address bar, rather than the URL of the server that delivered the content. Separating content attribution from content distribution advances a variety of use cases such as privacy-preserving prefetching, offline internet experiences, and serving content from third-party caches.

The SXG format

An SXG is encapsulated in a binary-encoded file that has two primary components: an HTTP exchange and a signature. The HTTP exchange consists of a request URL, content negotiation information, and an HTTP response.

Here's an example of a decoded SXG file:

format version: 1b3
request:
method: GET
uri: https://example.org/
headers:
response:
status: 200
headers:
Cache-Control: max-age=604800
Digest: mi-sha256-03=kcwVP6aOwYmA/j9JbUU0GbuiZdnjaBVB/1ag6miNUMY=
Expires: Mon, 24 Aug 2020 16:08:24 GMT
Content-Type: text/html; charset=UTF-8
Content-Encoding: mi-sha256-03
Date: Mon, 17 Aug 2020 16:08:24 GMT
Vary: Accept-Encoding
signature:
label;cert-sha256=*ViFgi0WfQ+NotPJf8PBo2T5dEuZ13NdZefPybXq/HhE=*;
cert-url="https://test.web.app/ViFgi0WfQ-NotPJf8PBo2T5dEuZ13NdZefPybXq_HhE";
date=1597680503;expires=1598285303;integrity="digest/mi-sha256-03";sig=*MEUCIQD5VqojZ1ujXXQaBt1CPKgJxuJTvFlIGLgkyNkC6d7LdAIgQUQ8lC4eaoxBjcVNKLrbS9kRMoCHKG67MweqNXy6wJg=*;
validity-url="https://example.org/webpkg/validity"
header integrity: sha256-Gl9bFHnNvHppKsv+bFEZwlYbbJ4vyf4MnaMMvTitTGQ=

The exchange has a valid signature.
payload [1256 bytes]:
<!doctype html>
<html>
<head>
<title>SXG example</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div>
<h1>Hello</h1>
</div>
</body>
</html>

The expires parameter in the signature indicates a SXG's expiration date. A SXG may be valid for at most 7 days. If the expiration date of an SXG is more than 7 days in the future, the browser will reject it. Find more information on the signature header in the Signed HTTP Exchanges spec.

Web Packaging

SXGs are a part of the broader Web Packaging spec proposal family. In addition to SXGs, the other major component of the Web Packaging spec is Web Bundles ("bundled HTTP exchanges"). Web Bundles are a collection of HTTP resources and the metadata necessary to interpret the bundle.

The relationship between SXGs and Web Bundles is a common point of confusion. SXGs and Web Bundles are two distinct technologies that don't depend on each other—Web Bundles can be used with both signed and unsigned exchanges. The common goal advanced by both SXGs and Web Bundles is the creation of a "web packaging" format that allows sites to be shared in their entirety for offline consumption.

SXGs are the first part of the Web Packaging spec that Chromium-based browsers will implement.

Loading SXGs

Initially, the primary use case of SXGs will likely be as a delivery mechanism for a page's main document. For this use case, a SXG could be referenced using the <link> or <a> tags, as well as the Link header.

<a href="https://example.com/sxg">
<link rel="prefetch" as="document" href="https://example.com/sxg">

Although a SXG could theoretically be referenced using a <script> or <img> tag, this is not the recommended approach to loading subresources using SXG. Tooling support for the SXG subresource loading is less mature, and therefore this use case is not covered in this document - however, you can read more about it in Signed Exchange subresource substitution.

Like other resources, a SXG can be loaded by entering its URL in the browser's address bar.

Serving SXGs

Content negotiation

Content negotiation is a mechanism for serving different representations of the same resource at the same URL depending on the capabilities and preferences of a client—for example, serving the gzip version of a resource to some clients but the Brotli version to others. Content negotiation makes it possible to serve both SXG and non-SXG representations of the same content depending on a browser's capabilities.

Web browsers use the Accept request header to communicate the MIME types they support. If a browser supports SXGs, the MIME type application/signed-exchange will automatically be included in this list of values.

For example, this is the Accept header sent by Chrome 84:

accept:
text/html,
application/xhtml+xml,
application/xml;q=0.9,
image/webp,image/apng,
\*/\*;q=0.8,
application/signed-exchange;v=b3;q=0.9

The application/signed-exchange;v=b3;q=0.9 portion of this string informs the web server that Chrome supports SXGs—specifically, version b3. The last part q=0.9 indicates the q-value.

The q-value expresses a browser's relative preference for a particular format using a decimal scale from 0 to 1, with 1 representing the highest priority. When a q-value is not supplied for a format, 1 is the implied value.

Best practices

Servers should serve SXGs when the Accept header indicates that the q-value for application/signed-exchange is greater than or equal to the q-value for text/html.

The following regular expression can be used to match the Accept header of requests that should be served as SXG:

Accept: /(^|,)\s\*application\/signed-exchange\s\*;\s\*v=[[:alnum:]\_-]+\s\*(,|$)/

Note that the subexpression (,|$) matches headers where the q-value for SXG has been omitted; this omission implies a q-value of 1 for SXG. Although an Accept header could theoretically contain the substring q=1, in practice browsers don't explicitly list a format's q-value when it has the default value of 1.

Debugging SXGs with Chrome DevTools

Signed Exchanges can be identified by looking for signed-exchange in the Type column of the Network panel in Chrome DevTools.

Screenshot showing a SXG request within the 'Network' panel in DevTools
The Network panel in DevTools

The Preview tab provides more information about the contents of a SXG.

Screenshot of the 'Preview' tab for a SXG
The Preview tab in DevTools

To see a SXG firsthand, visit this demo in one of the browsers that supports SXG

Tooling

This section discusses the tooling options and technical requirements of SXGs.

At a high level, implementing SXGs consists of generating the SXG corresponding to a given URL and then serving that SXG to users. To generate a SXG you will need a certificate that can sign SXGs.

Certificates

Certificates associate an entity with a public key. Signing a SXG with a certificate allows the content to be associated with the entity.

Production use of SXGs requires a certificate that supports the CanSignHttpExchanges extension. Per spec, certificates with this extension must have a validity period no longer than 90 days and require that the requesting domain have a DNS CAA record configured.

This page lists the certificate authorities that can issue this type of certificate. Certificates for SXGs are only available through a commercial certificate authority.

Web Packager

Web Packager is an open-source, Go-based tool that is the de facto tooling for generating ("packaging") signed exchanges. You can use it to manually create SXGs, or as a server that automatically creates and serves SXGs. Web Packager is currently in alpha.

Web Packager CLI

The Web Packager CLI generates a SXG corresponding to a given URL.

webpackager \
--private\_key=private.key \
--cert\_url=https://example.com/certificate.cbor \
--url=https://example.com

Once the SXG file has been generated, upload it to your server and serve it with the application/signed-exchange;v=b3 MIME type.

Web Packager Server

The Web Packager server, webpkgserver, acts as a reverse proxy for serving SXGs. Given a URL, webpkgserver will fetch the URL's contents, package them as an SXG, and serve the SXG in response.

This is the server's default interface: https://localhost:8080/priv/doc/https://example.com.

In the above example, an instance of webpkgserver running on localhost:8080 would return the contents of https://example.com as an SXG. /priv/doc/ is the default name of the webpkgserver endpoint. Use the webpkgserver configuration file to customize the name of this endpoint, as well as many other settings.

In production, webpkgserver should not use a public endpoint. Instead, the frontend web server should forward SXG requests to webpkgserver. These recommendations contain more information on running webpkgserver behind a frontend edge server.

Other tooling

  • NGINX SXG Module

    The NGINX SXG module generates and serves SXGs. Sites that already use NGINX should consider using this module over Web Packager Server.

    The NGINX SXG module only works with CanSignHttpExchanges certificates. Setup instructions can be found here.

  • gen-signedexchange

    gen-signedexchange is a tool provided by the webpackage specification as a reference implementation of generating SXGs. Due to its limited feature set, gen-signedexchange is useful for trying out SXGs, but impractical for larger-scale and production use.

Further reading

Last updated: Improve article