Skip to main content

Email Verification Protocol
draft-hardt-email-verification-00

Document Type Active Internet-Draft (individual)
Authors Dick Hardt , Sam Goto
Last updated 2026-06-17
RFC stream (None)
Intended RFC status (None)
Formats
Stream Stream state (No stream defined)
Consensus boilerplate Unknown
RFC Editor Note (None)
IESG IESG state I-D Exists
Telechat date (None)
Responsible AD (None)
Send notices to (None)
draft-hardt-email-verification-00
TBD                                                             D. Hardt
Internet-Draft                                                     Hellō
Intended status: Standards Track                                 S. Goto
Expires: 19 December 2026                                         Google
                                                            17 June 2026

                      Email Verification Protocol
                   draft-hardt-email-verification-00

Abstract

   This document defines the Email Verification Protocol (EVP), the
   HTTP-level protocol by which a browser obtains a signed email
   verification token from an issuer and presents it to a relying party
   (RP).  The protocol enables web applications to verify that a user
   controls an email address without sending a verification email.  It
   uses a three-party model in which the browser intermediates between
   the RP and the issuer, hiding the RP's identity from the issuer and
   supporting private, per-RP email addresses to prevent cross-site
   correlation.

   This document covers issuer discovery, the token issuance request,
   the Email Verification Token (EVT) and Key Binding JWT (KB-JWT)
   formats, and token verification.  The browser API — how the user
   selects an email address and how the token is delivered to the RP —
   is defined in the companion W3C Email Verification API
   ([EVP-Browser]).

Discussion Venues

   _Note: This section is to be removed before publishing as an RFC._

   Source for this draft and an issue tracker can be found at
   https://github.com/dickhardt/email-verification
   (https://github.com/dickhardt/email-verification).

   The browser API aspects are being developed separately by the W3C
   ([EVP-Browser]).

Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

Hardt & Goto            Expires 19 December 2026                [Page 1]
Internet-Draft                     EVP                         June 2026

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on 19 December 2026.

Copyright Notice

   Copyright (c) 2026 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.  Code Components
   extracted from this document must include Revised BSD License text as
   described in Section 4.e of the Trust Legal Provisions and are
   provided without warranty as described in the Revised BSD License.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   4
     1.1.  Verification Friction . . . . . . . . . . . . . . . . . .   4
     1.2.  Privacy Leakage . . . . . . . . . . . . . . . . . . . . .   5
     1.3.  Friction Solution . . . . . . . . . . . . . . . . . . . .   5
     1.4.  Privacy Solution  . . . . . . . . . . . . . . . . . . . .   5
   2.  Protocol Flow . . . . . . . . . . . . . . . . . . . . . . . .   6
     2.1.  Email Discovery . . . . . . . . . . . . . . . . . . . . .   7
     2.2.  Session Binding . . . . . . . . . . . . . . . . . . . . .   7
     2.3.  Email Acquisition . . . . . . . . . . . . . . . . . . . .   7
     2.4.  Token Request . . . . . . . . . . . . . . . . . . . . . .   7
     2.5.  EVT Issuance  . . . . . . . . . . . . . . . . . . . . . .   8
     2.6.  KB Creation . . . . . . . . . . . . . . . . . . . . . . .   9
     2.7.  Token Presentation  . . . . . . . . . . . . . . . . . . .   9
     2.8.  Token Verification  . . . . . . . . . . . . . . . . . . .   9
   3.  Issuer Discovery  . . . . . . . . . . . . . . . . . . . . . .  10
     3.1.  DNS Delegation  . . . . . . . . . . . . . . . . . . . . .  10
     3.2.  Issuer Metadata . . . . . . . . . . . . . . . . . . . . .  11
   4.  HTTP Message Signatures . . . . . . . . . . . . . . . . . . .  11
     4.1.  HTTP Request Signing  . . . . . . . . . . . . . . . . . .  11
       4.1.1.  Request Body  . . . . . . . . . . . . . . . . . . . .  12

Hardt & Goto            Expires 19 December 2026                [Page 2]
Internet-Draft                     EVP                         June 2026

       4.1.2.  Signature-Key Header  . . . . . . . . . . . . . . . .  12
       4.1.3.  Signature-Input Header  . . . . . . . . . . . . . . .  12
       4.1.4.  Example Signed Request  . . . . . . . . . . . . . . .  12
     4.2.  HTTP Request Verification . . . . . . . . . . . . . . . .  13
   5.  Email Verification Token (EVT)  . . . . . . . . . . . . . . .  14
     5.1.  EVT Structure . . . . . . . . . . . . . . . . . . . . . .  14
       5.1.1.  Header  . . . . . . . . . . . . . . . . . . . . . . .  14
       5.1.2.  Payload . . . . . . . . . . . . . . . . . . . . . . .  14
       5.1.3.  Format  . . . . . . . . . . . . . . . . . . . . . . .  15
     5.2.  EVT Creation  . . . . . . . . . . . . . . . . . . . . . .  15
     5.3.  EVT Verification  . . . . . . . . . . . . . . . . . . . .  15
   6.  Key Binding (EVT+KB)  . . . . . . . . . . . . . . . . . . . .  16
     6.1.  KB-JWT Structure  . . . . . . . . . . . . . . . . . . . .  16
       6.1.1.  Header  . . . . . . . . . . . . . . . . . . . . . . .  16
       6.1.2.  Payload . . . . . . . . . . . . . . . . . . . . . . .  16
     6.2.  EVT+KB Format . . . . . . . . . . . . . . . . . . . . . .  17
     6.3.  SD-JWT Compatibility  . . . . . . . . . . . . . . . . . .  17
     6.4.  KB-JWT Creation . . . . . . . . . . . . . . . . . . . . .  17
     6.5.  KB-JWT Verification . . . . . . . . . . . . . . . . . . .  18
   7.  WebAuthn Authentication . . . . . . . . . . . . . . . . . . .  18
     7.1.  WebAuthn Challenge Response . . . . . . . . . . . . . . .  18
     7.2.  WebAuthn Response . . . . . . . . . . . . . . . . . . . .  19
     7.3.  WebAuthn Verification . . . . . . . . . . . . . . . . . .  20
   8.  Private Email Addresses . . . . . . . . . . . . . . . . . . .  20
     8.1.  Request Parameters  . . . . . . . . . . . . . . . . . . .  21
     8.2.  Example Requests  . . . . . . . . . . . . . . . . . . . .  21
     8.3.  Requirements  . . . . . . . . . . . . . . . . . . . . . .  21
     8.4.  Issuer Flexibility  . . . . . . . . . . . . . . . . . . .  22
     8.5.  Example EVT Payload . . . . . . . . . . . . . . . . . . .  22
   9.  Error Responses . . . . . . . . . . . . . . . . . . . . . . .  23
     9.1.  Invalid Content-Type Header . . . . . . . . . . . . . . .  23
     9.2.  Invalid Sec-Fetch-Dest Header . . . . . . . . . . . . . .  23
     9.3.  Invalid or Missing HTTP Message Signature . . . . . . . .  23
     9.4.  Authentication Required . . . . . . . . . . . . . . . . .  24
     9.5.  Invalid Parameters  . . . . . . . . . . . . . . . . . . .  24
     9.6.  Private Email Not Supported . . . . . . . . . . . . . . .  24
     9.7.  Invalid Directed Email  . . . . . . . . . . . . . . . . .  24
     9.8.  Server Errors . . . . . . . . . . . . . . . . . . . . . .  25
   10. Privacy Considerations  . . . . . . . . . . . . . . . . . . .  25
     10.1.  Reduced Friction Tradeoff  . . . . . . . . . . . . . . .  25
     10.2.  Timing Correlation by Email Providers  . . . . . . . . .  25
     10.3.  RP Correlation via Email Addresses . . . . . . . . . . .  26
     10.4.  Issuer Knowledge . . . . . . . . . . . . . . . . . . . .  26
     10.5.  RP Knowledge . . . . . . . . . . . . . . . . . . . . . .  26
     10.6.  Browser Storage  . . . . . . . . . . . . . . . . . . . .  26
   11. Security Considerations . . . . . . . . . . . . . . . . . . .  26
     11.1.  HTTP Message Signature Security  . . . . . . . . . . . .  27
     11.2.  Signature-Key hwk Scheme . . . . . . . . . . . . . . . .  27

Hardt & Goto            Expires 19 December 2026                [Page 3]
Internet-Draft                     EVP                         June 2026

     11.3.  Email Existence Probing  . . . . . . . . . . . . . . . .  27
       11.3.1.  Uniform Error Responses  . . . . . . . . . . . . . .  28
       11.3.2.  Timing Attack Mitigations  . . . . . . . . . . . . .  28
       11.3.3.  Additional Mitigations . . . . . . . . . . . . . . .  28
   12. Design Rationale  . . . . . . . . . . . . . . . . . . . . . .  29
     12.1.  Why Not Solve Email Like SMS OTP?  . . . . . . . . . . .  29
     12.2.  Why the Three-Party Model? . . . . . . . . . . . . . . .  30
     12.3.  Why SD-JWT?  . . . . . . . . . . . . . . . . . . . . . .  30
     12.4.  Why DNS Delegation?  . . . . . . . . . . . . . . . . . .  30
     12.5.  Why JWKS Over DKIM Keys? . . . . . . . . . . . . . . . .  31
     12.6.  Why HTTP Message Signatures Rather Than Request JWT? . .  31
   13. Implementation Status . . . . . . . . . . . . . . . . . . . .  31
   14. Document History  . . . . . . . . . . . . . . . . . . . . . .  32
   15. References  . . . . . . . . . . . . . . . . . . . . . . . . .  32
     15.1.  Normative References . . . . . . . . . . . . . . . . . .  32
     15.2.  Informative References . . . . . . . . . . . . . . . . .  32
   Appendix A.  Acknowledgments  . . . . . . . . . . . . . . . . . .  33
   Authors' Addresses  . . . . . . . . . . . . . . . . . . . . . . .  33

1.  Introduction

   Web applications verify email addresses to send emails to users
   (transactional notifications, marketing, password resets) and to
   identify users (as a stable identifier for account creation and
   authentication).  The standard verification method—sending a one-time
   code via email—has two problems: verification friction and privacy
   leakage.

1.1.  Verification Friction

   The email one-time code flow requires the user to switch to their
   email client, wait for the message to arrive, find it (possibly in
   spam), read the code, return to the application, and enter it.  Many
   users abandon this process before completing it.

   Some approaches to reduce this friction:

   *  *Social login*: When a user has an account with Google, Apple, or
      another identity provider, the application can obtain a verified
      email without sending a verification message.  However, this
      requires the user to have and use a social account, and requires
      developers to integrate with each provider separately.

   *  *Magic links*: Instead of a code, the verification email contains
      a link the user clicks to verify.  This eliminates copying and
      pasting the code, but still requires switching to the email
      client, waiting for delivery, and finding the email.

Hardt & Goto            Expires 19 December 2026                [Page 4]
Internet-Draft                     EVP                         June 2026

1.2.  Privacy Leakage

   Email verification creates two privacy problems:

   1.  *RP-to-RP correlation*: When a user provides their real email
       address to multiple relying parties (RPs), those RPs can
       correlate the user across sites by comparing email addresses.

   2.  *User-RP visibility*: The email provider learns which RPs the
       user visits and when.  With email OTP, the provider sees
       verification emails from the sender and the delivery timing for
       every verification.  With social login, the identity provider
       sees every RP request.

   Reducing friction in email verification accelerates both privacy
   problems — users verify to more sites, increasing correlation
   potential and provider visibility.

1.3.  Friction Solution

   The Email Verification Protocol (EVP) enables a web application to
   obtain a verified email address *without sending an email* and
   *without the user leaving the web page*. The browser intermediates
   between the RP and an issuer, obtaining a signed token that contains
   an email address for the user that the RP can verify.  This
   eliminates the email delivery step entirely.

   *Note on deliverability*: Like social login, this protocol verifies
   that the user controls an email address — it does not verify that the
   email address can receive mail.

1.4.  Privacy Solution

   EVP addresses both privacy problems:

   *Three-party model*: The browser intermediates between the RP and
   issuer, ensuring the issuer never learns which RP requested
   verification.  See Protocol Flow (#protocol-flow) for details.

   *Private email addresses*: The browser can request a private email
   address instead of the user's actual email.  Private addresses that
   differ per RP cannot be correlated across sites.  See Private Email
   Addresses (#private-email) for details.

Hardt & Goto            Expires 19 December 2026                [Page 5]
Internet-Draft                     EVP                         June 2026

2.  Protocol Flow

   This document specifies the IETF protocol aspects of email
   verification: the HTTP-level interactions between the browser,
   issuer, and the application, aka relying party (RP).  How the browser
   obtains the email address from the user (browser APIs, user interface
   elements, etc.) and how the browser communicates with the RP is being
   defined by the W3C ([EVP-Browser]).

   *  *Issuer*: The service that verifies the user controls an email
      address.  See Issuer Discovery (#issuer-discovery) for how email
      domains delegate to issuers.

   *  *Three-party model*: The protocol uses a three-party model where
      the browser intermediates between the RP and issuer.  The issuer
      issues a email verification token (EVT) to the browser containing
      the email address and the browser's key material—but not the RP
      identity.  The browser then creates a key binding token (KB-JWT)
      that ties the EVT to a specific RP.  The combined token (EVT+KB)
      is what the RP receives.  This separation hides the RP from the
      issuer during verification.

   The following diagram illustrates the protocol flow between the RP
   Server, Browser, and Issuer:

   Step                      RP Server     Browser              Issuer
                                  |            |                    |
   2.1 Email Discovery            |            |<- discover accts ->|
                                  |            |   (push or pull)   |
                                  |            |                    |
   2.2 Session Binding            |--- nonce ->|                    |
                                  |            |                    |
   2.3 Email Acquisition          |      [obtain email from user]   |
                                  |            |                    |
   2.4 Token Request              |            |-- POST /issuance ->|
                                  |            |    (email, ...)    |
                                  |            |                    |
   2.5 EVT Creation               |            |           [create EVT]
                                  |            |                    |
   2.6 Token Issuance             |            |<------ EVT --------|
                                  |            |                    |
   2.7 KB Creation                |        [create KB-JWT]          |
                                  |            |                    |
   2.8 Token Presentation         |<-- EVT+KB -|                    |
                                  |            |                    |
   2.9 Token Verification    [verify EVT+KB]   |                    |
                                  |            |                    |

Hardt & Goto            Expires 19 December 2026                [Page 6]
Internet-Draft                     EVP                         June 2026

2.1.  Email Discovery

   Before presenting the user with email address choices, the browser
   discovers which email accounts have active sessions with an issuer.
   There are two models for this discovery:

   *Push model*: The issuer proactively pushes account information to
   the browser using the FedCM Accounts Push mechanism
   ([LightweightFedCM]).  The browser accumulates account data without
   making an explicit request.

   *Pull model*: The browser calls the issuer's accounts endpoint per
   the FedCM mechanism, as defined in the W3C Email Verification API
   ([EVP-Browser]).  The browser fetches the issuer's FedCM well-known
   configuration and requests the account list from the
   accounts_endpoint.

   The result of email discovery is the set of email addresses available
   for the current user, which the browser presents to the user in Email
   Acquisition (#email-acquisition).

2.2.  Session Binding

   The RP Server generates a cryptographically random nonce with at
   least 128 bits of entropy and binds it to a session it has with the
   browser.  The nonce MUST be unique per verification request and
   SHOULD be valid for a limited time window.  How the RP Server
   provides the nonce to the browser is being defined by the W3C
   ([EVP-Browser]).

2.3.  Email Acquisition

   The browser obtains an email address from the user.  This mechanism
   is being defined by the W3C ([EVP-Browser]).

2.4.  Token Request

   Once the browser has the email address and nonce:

   1.  The browser performs Issuer Discovery (#issuer-discovery) for the
       email address to obtain the issuer's metadata, including the
       issuance_endpoint.

   2.  The browser generates a fresh private/public key pair.  The
       browser SHOULD select an algorithm from the issuer's
       signing_alg_values_supported array, or use "EdDSA" if not
       present.

Hardt & Goto            Expires 19 December 2026                [Page 7]
Internet-Draft                     EVP                         June 2026

   3.  The browser creates a signed request per HTTP Message Signatures
       (#http-signatures) and POSTs to the issuance_endpoint, including
       the issuer's cookies.  The request body is a JSON object with the
       following parameters:

       *  email (REQUIRED): The email address to verify
       *  See Private Email Addresses (#private-email) for parameters to
          request private email addresses
       *  See WebAuthn Authentication (#webauthn-authentication) for
          parameters to respond to a WebAuthn challenge

   POST /email-verification/issuance HTTP/1.1
   Host: accounts.issuer.example
   Cookie: session=...
   Content-Type: application/json
   Sec-Fetch-Dest: email-verification
   Signature-Input: sig=("@method" "@authority" "@path" \
       "cookie" "signature-key");created=1692345600
   Signature: sig=:MEQCIHd8Y8qYKm5e3dV8y....:
   Signature-Key: sig=hwk; kty="OKP"; crv="Ed25519"; \
       x="JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"

   {"email":"user@example.com"}

   |  Note: The W3C Email Verification API ([EVP-Browser]) currently
   |  specifies a different request format: the browser constructs a
   |  signed JWT (request_token) with the public key in the header (alg,
   |  jwk) and aud, iat, and email in the payload, sent with Content-
   |  Type: application/x-www-form-urlencoded.  Existing deployments use
   |  this format; it is considered deprecated by this specification in
   |  favor of HTTP Message Signatures.

2.5.  EVT Issuance

   On receipt of a token request:

   1.  The issuer verifies the request per Request Verification
       (#request-verification).

   2.  The issuer checks if the cookies represent a logged-in user who
       controls the requested email address.  If the issuer supports
       WebAuthn (webauthn_supported: true) and cookies are not present
       or invalid, the issuer MAY return a WebAuthn challenge (see
       WebAuthn Authentication (#webauthn-authentication)).

Hardt & Goto            Expires 19 December 2026                [Page 8]
Internet-Draft                     EVP                         June 2026

   3.  If authentication succeeds, the issuer creates an EVT per EVT
       Creation (#evt-creation) and returns it as the value of
       issuance_token in an application/json response.  The issuer MAY
       include Set-Cookie headers to establish or update session state:

   HTTP/1.1 200 OK
   Content-Type: application/json
   Set-Cookie: session=...; Secure; HttpOnly; SameSite=None

   {"issuance_token":"eyJhbGciOiJFZERTQSIsImtpZCI6IjIwMjQtMDgtMTkiLCJ0eXAiOiJldnQrand0In0...~"}

   The browser MUST process any Set-Cookie headers in the response.

2.6.  KB Creation

   On receiving the issuance_token:

   1.  The browser verifies the EVT per EVT Verification (#evt-
       verification), additionally confirming:

       *  The email claim matches the email address being verified
       *  The cnf.jwk claim matches the public key the browser generated

   2.  The browser creates a KB-JWT per KB-JWT Creation (#kb-creation-
       detail), binding the EVT to the RP's origin and session nonce.

   3.  The browser concatenates the EVT and KB-JWT to form the EVT+KB.

   Example EVT+KB (line breaks for display):

   eyJhbGciOiJFZERTQSIsImtpZCI6IjIwMjQtMDgtMTkiLCJ0eXAiOiJldnQrand0In0.
   eyJpc3MiOiJpc3N1ZXIuZXhhbXBsZSIsImlhdCI6MTcyNDA4MzIwMCwiY25mIjp7...}.
   signature~
   eyJhbGciOiJFZERTQSIsInR5cCI6ImtiK2p3dCJ9.
   eyJhdWQiOiJodHRwczovL3JwLmV4YW1wbGUiLCJub25jZSI6IjI1OWM1ZWFlLTQ4...}.
   signature

2.7.  Token Presentation

   The browser provides the EVT+KB to the RP.  This mechanism is being
   defined by the W3C ([EVP-Browser]).

2.8.  Token Verification

   The RP receives the EVT+KB and verifies it by:

   1.  Verifying the KB-JWT per KB-JWT Verification (#kb-verification)
   2.  Verifying the EVT per EVT Verification (#evt-verification)

Hardt & Goto            Expires 19 December 2026                [Page 9]
Internet-Draft                     EVP                         June 2026

   3.  Verifying the KB-JWT signature using the public key from the
       EVT's cnf.jwk claim

   If all verification steps pass, the RP has successfully verified that
   the user controls the email address in the email claim.

3.  Issuer Discovery

   Both the browser and the RP need to discover information about the
   issuer for a given email address.  This section describes the
   discovery process.

   |  Note: The W3C Email Verification API ([EVP-Browser]) uses FedCM's
   |  well-known configuration (/.well-known/fedcm.json) for issuer
   |  discovery.  This specification uses /.well-known/email-
   |  verification.  These two specifications will align on a single
   |  well-known file.

3.1.  DNS Delegation

   The email domain delegates email verification to an issuer via a DNS
   TXT record.  Given an email address, parse the email domain
   (EMAIL_DOMAIN) and look up the `TXT` record for `_email-
   verification.EMAIL_DOMAIN.  The contents of the record MUST start
   withiss=followed by the issuer identifier.  There MUST be only
   oneTXTrecord for_email-verification.$EMAIL_DOMAIN`.

   Example record:

   _email-verification.email-domain.example   TXT   iss=issuer.example

   This record states that email-domain.example has delegated email
   verification to the issuer issuer.example.

   If the email domain and the issuer are the same domain, then the
   record would be:

   _email-verification.issuer.example   TXT   iss=issuer.example

   |  Access to DNS records and email is often independent of website
   |  deployments.  This provides assurance that an issuer is truly
   |  authorized as an insider with only access to websites on
   |  issuer.example could not setup an issuer that would grant them
   |  verified emails for any email at issuer.example.

Hardt & Goto            Expires 19 December 2026               [Page 10]
Internet-Draft                     EVP                         June 2026

3.2.  Issuer Metadata

   Once the issuer identifier is known, fetch the metadata document from
   https://$ISSUER/.well-known/email-verification.

   The metadata document is JSON containing the following properties:

   *  _issuance_endpoint_ - the API endpoint the browser calls to obtain
      an EVT
   *  _jwks_uri_ - the URL where the issuer provides its public keys to
      verify the EVT
   *  _signing_alg_values_supported_ - OPTIONAL.  JSON array containing
      a list of the signing algorithms ("alg" values) supported by the
      issuer for both HTTP Message Signatures and issued EVTs.
      Algorithm identifiers MUST be from the IANA "JSON Web Signature
      and Encryption Algorithms" registry.  If omitted, "EdDSA" is the
      default.  "EdDSA" SHOULD be included in the supported algorithms
      list.  The value "none" MUST NOT be used.
   *  _webauthn_supported_ - OPTIONAL.  Boolean indicating whether the
      issuer supports WebAuthn authentication as an alternative to
      cookies.  If true, the issuer may return a WebAuthn challenge when
      cookies are not present or invalid.  Defaults to false.
   *  _private_email_supported_ - OPTIONAL.  Boolean indicating whether
      the issuer supports generating private email addresses.  Defaults
      to false.

   Following is an example .well-known/email-verification file:

   {
     "issuance_endpoint": "https://accounts.issuer.example/email-verification/issuance",
     "jwks_uri": "https://accounts.issuer.example/email-verification/jwks",
     "signing_alg_values_supported": ["EdDSA", "RS256"],
     "webauthn_supported": true,
     "private_email_supported": true
   }

4.  HTTP Message Signatures

   This section defines how HTTP Message Signatures ([RFC9421]) are used
   in token requests.  The browser signs requests to prove possession of
   a key pair, and the issuer verifies these signatures.

4.1.  HTTP Request Signing

   The browser creates a signed request by:

   1.  Creating a JSON request body with the email address and optional
       parameters

Hardt & Goto            Expires 19 December 2026               [Page 11]
Internet-Draft                     EVP                         June 2026

   2.  Creating the Signature-Key header using the hwk scheme
       ([I-D.hardt-httpbis-signature-key]) with the browser's public key
   3.  Creating the Signature-Input header specifying the covered
       components
   4.  Computing the signature base per [RFC9421] Section 2.5 and
       signing with the browser's private key
   5.  Creating the Signature header with the base64-encoded signature

4.1.1.  Request Body

   The request body is a JSON object with the following fields:

   *  email (REQUIRED): The email address to verify
   *  private_email (OPTIONAL): Request a new private email address.
      See Private Email Addresses (#private-email).
   *  directed_email (OPTIONAL): A previously issued private email
      address to reuse.  See Private Email Addresses (#private-email).

   Example:

   {
     "email": "user@example.com"
   }

4.1.2.  Signature-Key Header

   The Signature-Key header uses the hwk scheme to convey the browser's
   public key:

   Signature-Key: sig=hwk; kty="OKP"; crv="Ed25519"; \
       x="JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"

4.1.3.  Signature-Input Header

   The covered components MUST include @method, @authority, @path, and
   signature-key.  The cookie component MUST be included when the Cookie
   header is present, and MUST be omitted when it is not (per [RFC9421]
   Section 2.5).  The created parameter MUST be included.

   Signature-Input: sig=("@method" "@authority" "@path" \
       "cookie" "signature-key");created=1692345600

4.1.4.  Example Signed Request

Hardt & Goto            Expires 19 December 2026               [Page 12]
Internet-Draft                     EVP                         June 2026

   POST /email-verification/issuance HTTP/1.1
   Host: accounts.issuer.example
   Cookie: session=...
   Content-Type: application/json
   Sec-Fetch-Dest: email-verification
   Signature-Input: sig=("@method" "@authority" "@path" \
       "cookie" "signature-key");created=1692345600
   Signature: sig=:MEQCIHd8Y8qYKm5e3dV8y....:
   Signature-Key: sig=hwk; kty="OKP"; crv="Ed25519"; \
       x="JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"

   {"email":"user@example.com"}

4.2.  HTTP Request Verification

   The issuer MUST verify the request headers:

   *  Content-Type is application/json
   *  Sec-Fetch-Dest is email-verification
   *  Signature-Input is present
   *  Signature is present
   *  Signature-Key is present with sig=hwk scheme

   The issuer MUST verify the HTTP Message Signature by:

   1.  Parsing the Signature-Key header and extracting the public key
       from the hwk parameters (kty, crv, x for OKP keys)
   2.  Parsing the Signature-Input header to determine the covered
       components
   3.  Verifying that the signature covers at minimum: @method,
       @authority, @path, and signature-key.  The signature MUST also
       cover cookie when the Cookie header is present.
   4.  Reconstructing the signature base per [RFC9421] Section 2.5
   5.  Verifying the signature in the Signature header using the
       extracted public key
   6.  Verifying the created timestamp in Signature-Input is within 60
       seconds of the current time

   The issuer MUST verify the request body:

   1.  Parsing the JSON body and extracting the email field
   2.  Verifying the email field contains a syntactically valid email
       address

Hardt & Goto            Expires 19 December 2026               [Page 13]
Internet-Draft                     EVP                         June 2026

5.  Email Verification Token (EVT)

   The Email Verification Token (EVT) is a JWT issued by the issuer that
   contains a verified email address and the browser's public key.  This
   section defines the EVT structure and how it is created and verified.

5.1.  EVT Structure

   The EVT is a JWT with the following structure:

5.1.1.  Header

   *  alg (REQUIRED): Signing algorithm
   *  kid (REQUIRED): Key identifier of the key used to sign
   *  typ (REQUIRED): Set to "evt+jwt"

   Example:

   {
     "alg": "EdDSA",
     "kid": "2024-08-19",
     "typ": "evt+jwt"
   }

5.1.2.  Payload

   Required claims:

   *  iss: The issuer identifier
   *  iat: Issued at time (seconds since epoch)
   *  cnf: Confirmation claim containing the browser's public key in jwk
      format (for SD-JWT Key Binding compatibility)
   *  email: The verified email address
   *  email_verified: Boolean, MUST be true

   Optional claims:

   *  is_private_email: Boolean, set to true when the email is a private
      address

   Example:

Hardt & Goto            Expires 19 December 2026               [Page 14]
Internet-Draft                     EVP                         June 2026

   {
     "iss": "issuer.example",
     "iat": 1724083200,
     "cnf": {
       "jwk": {
         "kty": "OKP",
         "crv": "Ed25519",
         "x": "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"
       }
     },
     "email": "user@example.com",
     "email_verified": true
   }

5.1.3.  Format

   The EVT has a ~ appended to it for SD-JWT compatibility (see SD-JWT
   Compatibility (#sd-jwt-compatibility)).

5.2.  EVT Creation

   After verifying the request (see Request Verification (#request-
   verification)) and authenticating the user, the issuer creates the
   EVT:

   1.  Construct the header with alg, kid, and typ
   2.  Construct the payload with iss, iat, cnf (containing the public
       key from the Signature-Key header), email, and email_verified
   3.  If a private email is requested, include is_private_email: true
       and set email to the private address
   4.  Sign the JWT with the issuer's private key corresponding to the
       kid
   5.  Append ~ to the signed JWT

   |  Note: The is_private_email claim name matches Apple's Sign in with
   |  Apple for compatibility with existing RP implementations.

5.3.  EVT Verification

   Both the browser and RP verify the EVT.  The verification steps are:

   1.  Parse the EVT into header, payload, and signature components
   2.  Extract and validate the alg and kid from the header
   3.  Extract and validate the iss, iat, cnf, email, and email_verified
       claims from the payload
   4.  Perform Issuer Discovery (#issuer-discovery) for the email domain
       to verify the iss claim matches the issuer identifier

Hardt & Goto            Expires 19 December 2026               [Page 15]
Internet-Draft                     EVP                         June 2026

   5.  Fetch the issuer's public keys from the jwks_uri in the issuer
       metadata
   6.  Verify the EVT signature using the public key identified by kid
   7.  Verify iat is within an acceptable time window
   8.  Verify email_verified is true

   The browser additionally verifies:

   *  The email claim matches the email address being verified
   *  The cnf.jwk claim matches the public key the browser generated

6.  Key Binding (EVT+KB)

   Key Binding ties an EVT to a specific RP and session through a Key
   Binding JWT (KB-JWT).  The combined EVT+KB is what the RP receives
   and verifies.

6.1.  KB-JWT Structure

   The KB-JWT is a JWT with the following structure:

6.1.1.  Header

   *  alg (REQUIRED): Signing algorithm (same as the browser's key pair)
   *  typ (REQUIRED): Set to "kb+jwt" for SD-JWT library compatibility

   Example:

   {
     "alg": "EdDSA",
     "typ": "kb+jwt"
   }

6.1.2.  Payload

   *  aud (REQUIRED): The RP's origin
   *  nonce (REQUIRED): The nonce from the RP's session
   *  iat (REQUIRED): Issued at time
   *  sd_hash (REQUIRED): SHA-256 hash of the EVT for SD-JWT library
      compatibility

   Example:

Hardt & Goto            Expires 19 December 2026               [Page 16]
Internet-Draft                     EVP                         June 2026

   {
     "aud": "https://rp.example",
     "nonce": "259c5eae-486d-4b0f-b666-2a5b5ce1c925",
     "iat": 1724083260,
     "sd_hash": "X9yH0Ajrdm1Oij4tWso9UzzKJvPoDxwmuEcO3XAdRC0"
   }

6.2.  EVT+KB Format

   The EVT+KB is formed by concatenating the EVT and KB-JWT separated by
   a tilde:

   <EVT>~<KB-JWT>

   The EVT already has a trailing ~ from its SD-JWT format, so the full
   structure is:

   <JWT>~<KB-JWT>

6.3.  SD-JWT Compatibility

   The EVT+KB format is compatible with SD-JWT with Key Binding as
   specified in [I-D.ietf-oauth-selective-disclosure-jwt], though this
   protocol does not use selective disclosure features.  The following
   SD-JWT features are used:

   *  *Trailing ~ on EVT*: The EVT uses the SD-JWT format (JWT with ~
      suffix)
   *  *cnf claim*: The EVT includes the cnf claim with jwk for holder
      key binding
   *  *typ: "kb+jwt"*: The KB-JWT uses the SD-JWT Key Binding JWT type
   *  *sd_hash claim*: The KB-JWT includes the SD-JWT hash of the EVT
   *  *Concatenation format*: The EVT+KB uses the SD-JWT <Issuer-signed-
      JWT>~<KB-JWT> format

   Standard SD-JWT libraries can be used to parse and validate EVT+KB
   tokens.

6.4.  KB-JWT Creation

   After verifying the EVT (see EVT Verification (#evt-verification)),
   the browser creates the KB-JWT:

   1.  Construct the header with alg and typ
   2.  Construct the payload with:
       *  aud: The RP's origin
       *  nonce: The nonce from the RP's session
       *  iat: Current time

Hardt & Goto            Expires 19 December 2026               [Page 17]
Internet-Draft                     EVP                         June 2026

       *  sd_hash: SHA-256 hash of the EVT (including the trailing ~)
   3.  Sign the KB-JWT with the browser's private key
   4.  Concatenate with the EVT to form the EVT+KB

6.5.  KB-JWT Verification

   The RP verifies the KB-JWT by:

   1.  Parse the EVT+KB by separating at the tilde
   2.  Parse the KB-JWT into header, payload, and signature
   3.  Extract alg from the header and aud, nonce, iat, sd_hash from the
       payload
   4.  Verify aud matches the RP's origin
   5.  Verify nonce matches the nonce from the RP's session
   6.  Verify iat is within a reasonable time window
   7.  Compute the SHA-256 hash of the EVT and verify it matches sd_hash
   8.  Verify the KB-JWT signature using the public key from the EVT's
       cnf.jwk claim

7.  WebAuthn Authentication

   When the issuer supports WebAuthn (webauthn_supported: true in
   metadata) and a token request lacks valid authentication cookies, the
   issuer MAY return a WebAuthn challenge to authenticate the user.
   This enables email verification even when the user is not logged into
   the issuer via cookies, using any WebAuthn-compatible credential
   (passkeys, security keys, platform authenticators).

7.1.  WebAuthn Challenge Response

   Instead of returning an error or an EVT, the issuer returns a
   WebAuthn challenge.  The issuer MAY include Set-Cookie headers to
   maintain challenge state:

   *HTTP 401 Unauthorized*

Hardt & Goto            Expires 19 December 2026               [Page 18]
Internet-Draft                     EVP                         June 2026

   HTTP/1.1 401 Unauthorized
   Content-Type: application/json
   Set-Cookie: webauthn_state=...; Secure; HttpOnly; SameSite=None; Max-Age=300

   {
     "webauthn_challenge": {
       "challenge": "dGVzdC1jaGFsbGVuZ2UtZGF0YQ",
       "timeout": 60000,
       "rpId": "issuer.example",
       "allowCredentials": [
         {
           "type": "public-key",
           "id": "Y3JlZGVudGlhbC1pZA"
         }
       ],
       "userVerification": "preferred"
     }
   }

   The webauthn_challenge object follows the structure of
   PublicKeyCredentialRequestOptions as defined in [WebAuthn].

   The browser MUST process any Set-Cookie headers in the response.  The
   issuer can use cookies to maintain challenge state, enabling
   stateless verification of the WebAuthn response.  Alternatively, the
   issuer MAY store challenges server-side with a short TTL.

7.2.  WebAuthn Response

   After the browser obtains a WebAuthn assertion (this mechanism is
   being defined by the W3C ([EVP-Browser])), it sends a new request to
   the issuance endpoint with the webauthn_response.  The browser MUST
   include any cookies set by the challenge response:

Hardt & Goto            Expires 19 December 2026               [Page 19]
Internet-Draft                     EVP                         June 2026

   POST /email-verification/issuance HTTP/1.1
   Host: accounts.issuer.example
   Cookie: webauthn_state=...
   Content-Type: application/json
   Sec-Fetch-Dest: email-verification
   Signature-Input: sig=("@method" "@authority" "@path" "cookie" "signature-key");created=1692345600
   Signature: sig=:...:
   Signature-Key: sig=hwk; kty="OKP"; crv="Ed25519"; x="JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"

   {
     "email": "user@example.com",
     "webauthn_response": {
       "id": "Y3JlZGVudGlhbC1pZA",
       "rawId": "Y3JlZGVudGlhbC1pZA",
       "response": {
         "authenticatorData": "...",
         "clientDataJSON": "...",
         "signature": "..."
       },
       "type": "public-key"
     }
   }

   The webauthn_response object follows the structure of
   PublicKeyCredential as defined in [WebAuthn].

   |  Note: The cookie component MUST be included in the signature when
   |  cookies are present (such as those set by the challenge response).
   |  If no cookies are present, the cookie component is omitted per
   |  HTTP Request Signing (#request-signing).

7.3.  WebAuthn Verification

   The issuer verifies the WebAuthn response against its stored
   credentials for the email address.  If verification succeeds, the
   issuer returns the EVT as described in EVT Issuance (#evt-issuance).

8.  Private Email Addresses

   Private email addresses allow users to provide site-specific email
   addresses to RPs, preventing RP-to-RP correlation of users by email
   address.  A private email address can be:

   *  *Single-use*: The browser requests a new private email and does
      not store it
   *  *Reusable*: The browser stores the private email and passes it
      back via directed_email for account continuity

Hardt & Goto            Expires 19 December 2026               [Page 20]
Internet-Draft                     EVP                         June 2026

   The choice between single-use and reusable is made by the browser or
   user, not the issuer.  The first request to an RP always uses
   private_email: true to obtain a new private email address.  For
   subsequent requests, the browser can either request another new
   private email or reuse an existing one by passing it in
   directed_email.

8.1.  Request Parameters

   The token request body supports one of the following parameters for
   private email addresses (mutually exclusive):

   *  private_email (OPTIONAL): Boolean.  When set to true, requests a
      new private email address instead of the user's actual email.

   *  directed_email (OPTIONAL): String.  A previously issued private
      email address.  When provided, the issuer returns the same private
      email address if it is valid and linked to the email in the
      request.

8.2.  Example Requests

   Request for a new private email address:

   {
     "email": "user@example.com",
     "private_email": true
   }

   Request to reuse a previously issued private email address:

   {
     "email": "user@example.com",
     "directed_email": "u7x9k2m4@privaterelay.example"
   }

8.3.  Requirements

   *  The private email MUST be a valid email address that the issuer
      can route to the user's actual mailbox
   *  The private email SHOULD be unique per user and per RP origin
      (derived from the browser's context)
   *  If directed_email is provided and is linked to the email address
      in the request, the issuer MUST return the same private email
      address
   *  If directed_email is provided but is invalid or not linked to the
      email, the issuer MUST return an error
   *  The private email address is included in the EVT email claim

Hardt & Goto            Expires 19 December 2026               [Page 21]
Internet-Draft                     EVP                         June 2026

   *  The EVT MUST include is_private_email: true when a private email
      address is issued

8.4.  Issuer Flexibility

   The domain of the private email address does not need to match the
   domain of the user's actual email address.  Additionally, the iss
   claim in the EVT corresponds to the issuer for the private email
   domain, which may differ from the issuer the browser initially
   contacted.

   For example, a user with user@example.com may receive a private email
   address u7x9k2m4@privaterelay.different.example.  The EVT's iss claim
   would be the issuer for privaterelay.different.example.  The browser
   verifies the EVT by performing issuer discovery on the private email
   domain and validating the signature against that issuer's JWKS.  This
   allows email providers to delegate private email functionality to a
   separate service.  It also enables privacy for users with vanity
   domains (e.g., me@dickhardt.example) where the domain itself is a
   unique identifier that would otherwise reveal the user's identity.

8.5.  Example EVT Payload

   When a private email is issued, the EVT contains the private address
   in the email claim and includes is_private_email: true:

   {
     "iss": "privaterelay.different.example",
     "iat": 1724083200,
     "cnf": {
       "jwk": {
         "kty": "OKP",
         "crv": "Ed25519",
         "x": "JrQLj5P_89iXES9-vFgrIy29clF9CC_oPPsw3c5D0bs"
       }
     },
     "email": "u7x9k2m4@privaterelay.different.example",
     "email_verified": true,
     "is_private_email": true
   }

   The browser MAY store the private email address so it can provide it
   as directed_email in future requests if the user wants to reuse the
   same private email address at an RP.  This is analogous to how
   browsers store usernames and passwords for sites.

   See Privacy Considerations (#privacy-considerations) for privacy
   analysis of private email addresses.

Hardt & Goto            Expires 19 December 2026               [Page 22]
Internet-Draft                     EVP                         June 2026

9.  Error Responses

   If the issuer cannot process the token request successfully, it MUST
   return an appropriate HTTP status code with a JSON error response
   containing an error field and optionally an error_description field.

9.1.  Invalid Content-Type Header

   When the request does not include the required Content-Type:
   application/json header, the server MUST return the 415 HTTP response
   code.

9.2.  Invalid Sec-Fetch-Dest Header

   When the request does not include the required Sec-Fetch-Dest: email-
   verification header:

   *HTTP 400 Bad Request*

   {
     "error": "invalid_request",
     "error_description": "Missing or invalid Sec-Fetch-Dest header"
   }

   The error_description SHOULD specify that the Sec-Fetch-Dest header
   is missing or invalid.

9.3.  Invalid or Missing HTTP Message Signature

   When the HTTP Message Signature is missing, malformed, or
   verification fails:

   *HTTP 400 Bad Request*

   {
     "error": "invalid_signature",
     "error_description": "HTTP Message Signature verification failed"
   }

   This includes cases where: - The Signature, Signature-Input, or
   Signature-Key headers are missing - The Signature-Key header does not
   use the hwk scheme or is malformed - The signature does not cover the
   required components - The signature verification fails using the
   public key from Signature-Key - The created timestamp is outside the
   acceptable time window

Hardt & Goto            Expires 19 December 2026               [Page 23]
Internet-Draft                     EVP                         June 2026

9.4.  Authentication Required

   When the request lacks valid authentication cookies, contains
   expired/invalid cookies, or the authenticated user does not have
   control of the requested email address:

   *HTTP 401 Unauthorized*

   {
     "error": "authentication_required",
     "error_description": "User must be authenticated and have control of the requested email address"
   }

9.5.  Invalid Parameters

   When the request body is malformed, missing the email field, or
   contains invalid values:

   *HTTP 400 Bad Request*

   {
     "error": "invalid_request",
     "error_description": "Invalid or malformed request body"
   }

9.6.  Private Email Not Supported

   When the request includes private_email or directed_email but the
   issuer does not support private email addresses
   (private_email_supported is false or absent in metadata):

   *HTTP 400 Bad Request*

   {
     "error": "private_email_not_supported",
     "error_description": "This issuer does not support private email addresses"
   }

9.7.  Invalid Directed Email

   When the request includes directed_email but the private email
   address is invalid or not linked to the email address in the request:

   *HTTP 400 Bad Request*

Hardt & Goto            Expires 19 December 2026               [Page 24]
Internet-Draft                     EVP                         June 2026

   {
     "error": "invalid_directed_email",
     "error_description": "The directed_email is invalid or not linked to this email address"
   }

9.8.  Server Errors

   For internal server errors or temporary unavailability:

   *HTTP 500 Internal Server Error*

   {
     "error": "server_error",
     "error_description": "Temporary server error, please try again later"
   }

10.  Privacy Considerations

   This section analyzes the privacy properties of the Email
   Verification Protocol, following the guidance in [RFC6973].

10.1.  Reduced Friction Tradeoff

   By reducing friction in email verification, EVP makes it easier for
   users to provide their email address to more sites.  This convenience
   could accelerate the RP correlation problem—users may share a
   correlatable identifier with more RPs than they would if verification
   required more effort.

   EVP addresses this tradeoff through private email addresses.  When
   supported by the issuer, users can present a site-specific private
   email that cannot be correlated across RPs.  This makes sharing a
   non-correlatable identifier just as easy as sharing the user's real
   email address, giving users a privacy-preserving option without
   additional friction.

10.2.  Timing Correlation by Email Providers

   The three-party model (see Protocol Flow (#protocol-flow)) prevents
   the issuer from learning which RP requested verification.  When the
   RP uses the email only for identification and does not send emails,
   the email provider never learns about the RP at all.  When the RP
   does send emails, the provider eventually learns about that RP, but
   only when email is actually sent—not at verification time.  This
   dulls timing correlation.

Hardt & Goto            Expires 19 December 2026               [Page 25]
Internet-Draft                     EVP                         June 2026

10.3.  RP Correlation via Email Addresses

   Private email addresses prevent RPs from correlating users across
   sites.  Additional benefits:

   *Protection from data breaches*: If an RP suffers a data breach, only
   the private email is exposed—not the user's primary email address.

   *Protection from unwanted email*: Because the issuer controls private
   email routing, users can revoke or filter mail to specific addresses
   without affecting their primary inbox.

10.4.  Issuer Knowledge

   The issuer learns certain information through the protocol:

   1.  *Email addresses*: The issuer learns that the user controls the
       email address in the request.  This may reveal email addresses at
       domains the issuer is authoritative for that it did not
       previously know the user had.

   2.  *Verification requests*: The issuer sees that verification was
       requested but does not learn which RP requested it (maintained by
       the three-party model).

   3.  *Private email mappings*: When generating private emails, the
       issuer stores mappings between private addresses and user email
       addresses for mail routing.

   4.  *Email traffic*: When RPs send email to private addresses, the
       issuer (operating the relay) learns about those communications.

10.5.  RP Knowledge

   The RP can infer whether the user is logged into the issuer: the RP
   receives an EVT when the user is logged in, and receives an error
   when the user is not.  This is inherent to any authentication-based
   verification scheme.

10.6.  Browser Storage

   The browser MAY store the private email address per RP origin to
   enable account continuity by passing it as directed_email in future
   requests.  This is analogous to how browsers store usernames and
   passwords for sites.

11.  Security Considerations

Hardt & Goto            Expires 19 December 2026               [Page 26]
Internet-Draft                     EVP                         June 2026

11.1.  HTTP Message Signature Security

   The use of HTTP Message Signatures ([RFC9421]) provides several
   security benefits:

   1.  *Request Integrity*: The signature covers the HTTP method,
       authority, path, and cookies, preventing tampering with any of
       these components.

   2.  *Cookie Binding*: By including the cookie component in the
       signature, the browser's authentication cookies are
       cryptographically bound to the specific request, preventing
       cookie injection or manipulation attacks.

   3.  *Replay Protection*: The created timestamp in the Signature-Input
       header is verified to be within 60 seconds, preventing replay
       attacks.

   4.  *Public Key Binding*: The browser's public key transmitted via
       the Signature-Key header with the hwk scheme is bound to the
       request signature, ensuring the issuer knows which public key to
       include in the EVT's cnf claim.

11.2.  Signature-Key hwk Scheme

   The hwk (Header Web Key) scheme provides:

   1.  *Self-Contained Key Distribution*: The public key is transmitted
       inline, eliminating the need for a separate key lookup or
       registration process.

   2.  *Pseudonymity*: The browser does not need to identify itself -
       the key serves as a pseudonymous identifier for the request.

   3.  *Ephemeral Keys*: The browser generates fresh key pairs for each
       verification flow, limiting the correlation potential across
       different verification attempts.

11.3.  Email Existence Probing

   Any software—not just browsers—can send requests to an issuer's
   issuance endpoint.  An attacker could attempt to use this to probe
   for valid email addresses:

   1.  *Build email lists*: Probe many addresses to identify valid ones
       for spam targeting.
   2.  *Account enumeration*: Determine which email addresses have
       accounts at specific issuers.

Hardt & Goto            Expires 19 December 2026               [Page 27]
Internet-Draft                     EVP                         June 2026

11.3.1.  Uniform Error Responses

   To prevent probing, issuers MUST NOT return different error responses
   based on whether an email address exists.  The
   authentication_required error should be returned uniformly whether:

   *  The email address does not exist at this issuer
   *  The email address exists but the user is not authenticated
   *  The email address exists but the authenticated user does not
      control it

   This ensures attackers cannot distinguish between "email exists" and
   "email does not exist" based on error responses.

11.3.2.  Timing Attack Mitigations

   Response timing can also reveal whether an email address exists.  If
   the issuer performs a database lookup only when the email exists, or
   takes different code paths based on email existence, an attacker can
   measure response times to infer information.

   Issuers SHOULD mitigate timing attacks using techniques such as:

   *  *Uniform code paths*: Execute the same operations (database
      lookups, cryptographic operations) regardless of whether the email
      exists, avoiding early returns that skip processing steps.
   *  *Response delay normalization*: Add delays to normalize response
      times across all error conditions to a consistent baseline.

11.3.3.  Additional Mitigations

   *  *User interaction required*: The browser API requires user gesture
      and consent before initiating verification, preventing automated
      probing from browsers.
   *  *Rate limiting*: Issuers SHOULD rate-limit requests per IP address
      to slow down probing attempts from any client.
   *  *Sec-Fetch-Dest verification*: The required Sec-Fetch-Dest: email-
      verification header provides a signal that the request originates
      from a browser, though this can be spoofed by non-browser clients.
   *  *Same information as email OTP*: An attacker can already determine
      email existence by sending verification emails and checking for
      bounces.  EVP does not create new information disclosure beyond
      what is already possible.

   Issuers SHOULD implement appropriate rate limiting and abuse
   detection.

Hardt & Goto            Expires 19 December 2026               [Page 28]
Internet-Draft                     EVP                         June 2026

12.  Design Rationale

12.1.  Why Not Solve Email Like SMS OTP?

   The WebOTP API and autocomplete="one-time-code" standards
   dramatically reduced friction for SMS verification.  A natural
   question is why email verification cannot use the same approach.
   Several fundamental differences make this impractical:

   *SMS is a mobile OS feature; email is application-layer*

   SMS is integrated into mobile operating systems.  The OS receives
   incoming messages and can parse them before any application sees
   them.  This privileged position enables the OS to recognize origin-
   bound OTP formats and offer autofill directly to the browser.

   Email operates at the application layer.  There is no OS-level email
   subsystem that intercepts incoming messages.  Email clients are
   ordinary applications—whether native apps, desktop programs, or web
   applications—with no special ability to coordinate with browsers for
   autofill.

   *SMS verification is mobile; email verification spans platforms*

   SMS OTP autofill works on mobile devices where the OS controls the
   messaging stack.  Email verification happens on desktop computers,
   laptops, tablets, and phones.  Any solution for email must work
   across all these platforms, not just mobile.

   *SMS senders are aggregators; email senders are RPs*

   SMS verification messages are typically sent through aggregator
   services (Twilio, AWS SNS, etc.) that send on behalf of many relying
   parties.  The "sender" of the SMS is often a short code or phone
   number shared across multiple services.  This means the phone number
   or sender ID carries little identifying information about which RP
   sent the message.

   Email verification messages come directly from the RP's domain.  The
   sender address, domain, and email headers identify the RP.  This
   architectural difference means that email verification inherently
   reveals more about the RP to the email provider than SMS verification
   reveals to the carrier.

Hardt & Goto            Expires 19 December 2026               [Page 29]
Internet-Draft                     EVP                         June 2026

12.2.  Why the Three-Party Model?

   A simpler design would have the issuer create a token directly for
   the RP, with the RP as the audience.  This is how social login works:
   the identity provider knows which application the user is logging
   into.

   EVP uses a three-party model where the browser intermediates between
   the issuer and the RP.  The issuer creates an EVT bound to the
   browser's ephemeral public key, and the browser creates a separate
   KB-JWT that binds the EVT to the RP.  The issuer never learns the
   RP's identity.

   This design choice is driven by privacy: for users with domain-based
   email accounts (personal domains, work accounts), the email provider
   should not learn which applications the user accesses.  The
   architectural complexity of the three-party model is justified by
   this privacy benefit.

12.3.  Why SD-JWT?

   The EVT uses the SD-JWT structure (specifically, the key binding
   capability from SD-JWT+KB) rather than a plain JWT.  This choice
   provides:

   1.  *Key Binding*: The ~ separator and KB-JWT mechanism provide a
       standard way to bind a token to a holder's key, enabling the
       three-party model where issuance and presentation are separate
       operations.

   2.  *Library Support*: SD-JWT libraries already exist and can parse
       EVTs, reducing implementation burden for RPs.

   3.  *Extensibility*: While EVP does not currently use selective
       disclosure, the SD-JWT structure allows future extensions without
       changing the token format.

12.4.  Why DNS Delegation?

   The mail domain delegates email verification to an issuer via a DNS
   TXT record rather than a .well-known file.  This choice aligns with
   how email infrastructure already works:

   1.  *Email domains often lack web hosting*: Many users have personal
       domains used only for email.  Requiring a web server to host a
       .well-known file would create a barrier to adoption.

Hardt & Goto            Expires 19 December 2026               [Page 30]
Internet-Draft                     EVP                         June 2026

   2.  *Apex domain challenges*: Email domains are typically apex
       domains (e.g., example.com), which do not support CNAME records.
       Hosting a web site on an apex domain requires additional
       infrastructure.

   3.  *Familiar tooling*: Domain owners already manage DNS records for
       email (MX, SPF, DKIM, DMARC).  Adding another TXT record fits
       existing workflows.

12.5.  Why JWKS Over DKIM Keys?

   The issuer publishes signing keys via a JWKS endpoint rather than
   reusing DKIM keys.  While DKIM keys are already associated with email
   domains, JWKS provides practical advantages:

   1.  *Key rotation*: DKIM keys are rarely rotated in practice.  JWKS
       rotation is common in OIDC deployments and follows established
       patterns.

   2.  *Algorithm flexibility*: JWKS supports multiple key types and
       algorithms.  DKIM key distribution was designed for a specific
       use case.

   3.  *Operational familiarity*: Developers implementing EVP are likely
       familiar with JWKS from OAuth/OIDC work.

12.6.  Why HTTP Message Signatures Rather Than Request JWT?

   The original design used a JWT signed by the browser to carry the
   email address and browser's public key.  The HTTP Message Signatures
   approach was chosen because:

   1.  *Standards-Based*: [RFC9421] is a published standard for signing
       HTTP messages, providing better interoperability
   2.  *Cookie Binding*: HTTP Message Signatures can directly sign the
       cookie header, providing stronger binding between authentication
       cookies and the request
   3.  *Flexibility*: The signature can cover any HTTP components,
       making it easier to add additional protections in the future
   4.  *Simpler Key Distribution*: The Signature-Key header provides a
       standardized way to distribute keys inline with the request

13.  Implementation Status

   _Note: This section is to be removed before publishing as an RFC._

Hardt & Goto            Expires 19 December 2026               [Page 31]
Internet-Draft                     EVP                         June 2026

   This section records the status of known implementations of the
   protocol defined by this specification at the time of posting of this
   Internet-Draft, and is based on a proposal described in [RFC7942].
   The description of implementations in this section is intended to
   assist the IETF in its decision processes in progressing drafts to
   RFCs.

   The following implementations are known:

   *  *Hellō* — hello.coop (https://hello.coop).  Organization: Hellō.
      Role: Issuer.  Coverage: EVT issuance endpoint, issuer discovery
      via DNS TXT, JWKS endpoint.  Level of maturity: exploratory.

14.  Document History

   _Note: This section is to be removed before publishing as an RFC._

   *  draft-hardt-email-verification-00
      -  Initial draft.

15.  References

15.1.  Normative References

   [I-D.hardt-httpbis-signature-key]
              Hardt, D. and T. Meunier, "HTTP Signature Keys", Work in
              Progress, Internet-Draft, draft-hardt-httpbis-signature-
              key-04, 9 April 2026,
              <https://datatracker.ietf.org/doc/html/draft-hardt-
              httpbis-signature-key-04>.

   [I-D.ietf-oauth-selective-disclosure-jwt]
              Fett, D., Yasuda, K., and B. Campbell, "Selective
              Disclosure for JWTs (SD-JWT)", Work in Progress, Internet-
              Draft, draft-ietf-oauth-selective-disclosure-jwt-22, 29
              May 2025, <https://datatracker.ietf.org/doc/html/draft-
              ietf-oauth-selective-disclosure-jwt-22>.

   [RFC9421]  Backman, A., Ed., Richer, J., Ed., and M. Sporny, "HTTP
              Message Signatures", RFC 9421, DOI 10.17487/RFC9421,
              February 2024, <https://www.rfc-editor.org/info/rfc9421>.

15.2.  Informative References

   [EVP-Browser]
              WICG, "Email Verification API", 2025,
              <https://wicg.github.io/email-verification/>.

Hardt & Goto            Expires 19 December 2026               [Page 32]
Internet-Draft                     EVP                         June 2026

   [LightweightFedCM]
              FedID CG, "Lightweight FedCM", 2025,
              <https://github.com/fedidcg/LightweightFedCM>.

   [RFC6973]  Cooper, A., Tschofenig, H., Aboba, B., Peterson, J.,
              Morris, J., Hansen, M., and R. Smith, "Privacy
              Considerations for Internet Protocols", RFC 6973,
              DOI 10.17487/RFC6973, July 2013,
              <https://www.rfc-editor.org/info/rfc6973>.

   [RFC7942]  Sheffer, Y. and A. Farrel, "Improving Awareness of Running
              Code: The Implementation Status Section", BCP 205,
              RFC 7942, DOI 10.17487/RFC7942, July 2016,
              <https://www.rfc-editor.org/info/rfc7942>.

   [WebAuthn] Jones, M., Kumar, A., and E. Lundberg, "Web
              Authentication: An API for accessing Public Key
              Credentials - Level 3", W3C Recommendation, 2023,
              <https://www.w3.org/TR/webauthn-3/>.

Appendix A.  Acknowledgments

   The authors would like to thank reviewers for their feedback on this
   specification.

Authors' Addresses

   Dick Hardt
   Hellō
   Email: dick.hardt@gmail.com

   Sam Goto
   Google
   Email: goto@google.com

Hardt & Goto            Expires 19 December 2026               [Page 33]