Internet-Draft | Origin-Bound One-Time Codes | December 2023 |
Wells & O'Connor | Expires 9 June 2024 | [Page] |
This specification defines a mechanism for associating one-time codes with domains that can be included in the body of an SMS message or the headers of an email.¶
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.¶
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 9 June 2024.¶
Copyright (c) 2023 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.¶
Many websites use one-time codes to provide an additional layer of security when users log in with passwords. These one-time codes can be delivered over a variety of transports, but [SMS] and email are the most common.¶
To improve the experience of dealing with these codes, User Agents might attempt to automatically extract them and present them to the user for filling. Without a well-defined format for such messages, extraction relies on heuristics, which are often unreliable and error-prone. Additionally, without a mechanism for associating such codes with specific domains, users might be tricked into providing the code to a malicious site.¶
This document defines a mechanism for associating one-time codes with origins, and formats for specifying them in SMS messages and emails. The benefits of this association are that senders of one-time codes can specify to User Agents which domains the one-time code is valid for, and User Agents can reliably extract one-time codes from these messages without relying on heuristics.¶
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.¶
For definitions of Document and Origin, see [DOM].¶
For definitions of Active Document, Browsing Context, Parent Browsing Context, Same Origin, Same Site, and Top-Level Context, see [HTML].¶
For definitions of ASCII Whitespace, Code Point, Collect a Sequence of Code Points, Normalize Newlines, Strictly Split, and Tuple, see [INFRA].¶
Many requirements in this document take the form of precise algorithms as is the norm in WHATWG (Web Hypertext Application Technology Working Group) and many W3C specifications. These algorithms are expressed per the requirements in [INFRA].¶
Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.¶
Conformance requirements phrased as algorithms or specific steps can be implemented in any manner, so long as the end result is equivalent. In particular, the algorithms defined in this specification are intended to be easy to understand and are not intended to be performant. Implementers are encouraged to optimize.¶
An origin-bound one-time code is a tuple consisting of a
top-level origin (an origin), an embedded origin (an origin
or null
), and a code (a string).¶
Example A.
(("https"
, "example.com"
, null
, null
), null
, "747723"
)
is an origin-bound one-time code whose top-level origin is
("https"
, "example.com"
, null
, null
),
whose embedded origin is null
, and whose code is "747723"
.¶
Example B.
(("https"
, "example.com"
, null
, null
),
("https"
, "ecommerce.example"
, null
, null
), "747723"
)
is an origin-bound one-time
code whose origin is
("https"
, "example.com"
, null
, null
),
whose embedded origin is
("https"
, "ecommerce.example"
, null
, null
),
and whose code is "747723"
.¶
An origin-bound one-time code SMS is a string for which the "parse an origin-bound one-time code SMS" algorithm (Section 3.1.1) returns an origin-bound one-time code.¶
An origin-bound one-time code SMS MAY begin with human-readable explanatory text. This consists of all but the last line of the string.¶
The last line MUST contain both a top-level host and a code, each prefixed with
a sigil: U+0040
(@
) before the top-level host, and U+0023
(#
) before the
code.¶
Following the code, an embedded host MAY be specified. It is preceeded with a
U+0040
(@
) sigil.¶
The fields on the last line MUST be separated by a single U+0020
(SPACE
).
The order of fields in the last line is always top-level host, code, and
embedded host (if present). Nothing can come before the top-level host in the
last line.¶
Trailing text in the last line SHOULD be ignored to preserve the ability for future documents to introduce new syntax.¶
Example C. In the following origin-bound one-time code SMS, the top-level
host is "example.com
", the code is "747723
", no embedded host is specified,
and the explanatory text is "747723 is your ExampleCo authentication
code.\n\n
".¶
747723 is your ExampleCo authentication code. @example.com #747723¶
Example D. In the following origin-bound one-time code SMS, the top-level
host is "example.com
", the code is "747723
", the embedded host is
"ecommerce.example
", and the explanatory text is "747723 is your ExampleCo
authentication code.\n
".¶
747723 is your ExampleCo authentication code. @example.com #747723 @ecommerce.example¶
Example E. The message "something @example.com #747723
" is not an
origin-bound one-time code SMS because it doesn’t start with the top-level host.¶
Example F. The message "#747723 @ecommerce.example @example.com
" is not an
origin-bound one-time code SMS because the fields are in the wrong order.¶
Example G. The message "@example.com code #747723
" is not an origin-bound
one-time code message because several characters appear between the two values
on the last line of the message.¶
Example H. In the following origin-bound one-time code SMS, the top-level
host is "example.com
", the code is "747723
", the embedded host is
"ecommerce.example
", and the explanatory text is "". The trailing text "
$future
" is ignored.¶
@example.com #747723 @ecommerce.example $future¶
To parse an origin-bound one-time code SMS from message, run these steps:¶
Let line be the last line (Section 3.1.1.2) of message, and position be 0.¶
If position points past the end of line, return failure.¶
Let top-level host be the result of extracting a marked token (Section 3.1.1.1)
from line at position with marker U+0040
(@
).¶
If top-level host is failure, return failure.¶
Let top-level origin be the origin ("https"
, top-level host,
null
, null
).¶
If position points past the end of line, return failure.¶
If the code point at position within line is not U+0020
(SPACE
), return failure.¶
Advance position by 1.¶
If position points past the end of line, return failure.¶
Let code be the result of extracting a marked token (Section 3.1.1.1) from
line at position with marker U+0023
(#
).¶
If code is failure, return failure.¶
Let embedded origin be null
.¶
If position does not point past the end of line, and if the code point
at position within line is U+0020
(SPACE
), run the following steps:¶
Advance position by 1.¶
Let embedded host be the result of extracting a marked token (Section 3.1.1.1)
from line at position with marker U+0040
(@
).¶
If embedded host is failure, set embedded origin to null
.
Otherwise, set embedded origin to the origin ("https"
,
embedded host, null
, null
).¶
Return the origin-bound one-time code (top-level origin, embedded origin, code).¶
To extract a marked token from string at position with code point marker, run the following steps:¶
If position points past the end of string, return failure.¶
If the code point at position within string is not marker, return failure.¶
Advance position by 1.¶
If position points past the end of string, return failure.¶
Let token be the result of collecting a sequence of code points which are not ASCII whitespace from string with position.¶
If token is the empty string, return failure.¶
Return token.¶
The last line of string is the result of running these steps:¶
Normalize newlines in string.¶
Let lines be the result of strictly splitting string on U+000A
(LF
).¶
Return the last item of lines.¶
In order to deliver an origin-bound one-time code via email, we define a
One-Time-Code
message header that contains the one-time code and
origin-binding information about it.¶
The information in the body of this header MUST use a DKIM-style tag list as defined in Section 3.2 of [RFC6376]. The following tag names are defined:¶
origin
The top-level origin the code is bound to¶
code
The code itself¶
embedded-origin
The embedded origin¶
The header body MUST contain exactly one code
tag. It SHOULD include one
origin
tag. If the header body contains an origin
tag, it MAY also include
one embedded-origin
tag.¶
Though it is recommended to always provide origin-binding information along with
one-time codes, senders can affirmatively decline to provide it, while still
including the code to assist User Agents with detecting it, by omitting the
origin
and embedded-origin
tags. MUAs MAY choose to ignore the
One-Time-Code
header if an origin
tag is not specified.¶
Example I. The following header specifies an origin-bound one-time code
where the code is "123456"
and the origin is "example.com"
.¶
One-Time-Code: code=123456; origin=example.com¶
Example J. The following example is an origin-bound one-time code header
with an origin of "example.com
", a code of "123456
", and an embedded domain
of "ecommerce.example
"¶
One-Time-Code: origin=example.com; code=123456; embedded-origin=ecommerce.example.com¶
Example K. The following example is not a domain-bound one-time code header
because it is missing an origin
tag.¶
One-Time-Code: code=123456; embedded-origin=ecommerce.example.com¶
Example L. The following header specifies a code, but does not specify origin-binding information. Therefore, it is not an origin-bound one-time code.¶
One-Time-Code: code=123456¶
Parsing the body of the One-Time-Code
header proceeds according to [RFC6376].¶
Many User Agents help users fill out forms on websites. Sites can use features
like autocomplete=one-time-code
(defined in HTML) to hint to User
Agents that they could assist the user with providing a one-time code to the
website. [HTML]¶
Note: This specification does not impose any requirements or restrictions on the use of one-time codes which are not origin-bound one-time codes.¶
User Agents determine whether or not to assist the user by providing an origin-bound one-time code to a website with origin-bound one-time code otc and Document doc by running these steps:¶
If doc is not the active document of a browsing context, return failure.¶
Let context be doc’s browsing context.¶
If context is a top-level browsing context, run these steps:¶
If otc’s embedded origin is null
, return failure.¶
Let match type be "origin"
.¶
If otc’s embedded origin is not same origin with doc’s
origin, set match type to "site"
.¶
If otc’s embedded origin is not same site with doc’s origin, return failure.¶
Set context to its parent browsing context.¶
While context is not a top-level browsing context, run these steps:¶
If context’s active document's origin is same origin with
neither otc’s embedded origin nor otc’s top-level origin, set match
type
to "site"
.¶
If context’s active document's origin is same site with neither otc’s embedded origin nor otc’s top-level origin, return failure.¶
Set context to its parent browsing context.¶
If context is not a top-level browsing context, return failure.¶
If context's active document's origin is same origin with otc's top-level origin, return match type.¶
If context’s active document's origin is same site with
otc’s top-level origin, return "site"
.¶
Return failure.¶
If the above steps returned "origin"
or "site"
, the User Agent MAY assist
the user with providing the origin-bound one-time code's code to the website.¶
If the above steps returned "site"
, the User Agent SHOULD indicate the
origin-bound one-time code's top-level and embedded origins to the user when
assisting them.¶
If the above steps returned failure, the User Agent SHOULD NOT assist the user with providing the origin-bound one-time code's code to the website.¶
Note: because the schemes of an origin-bound one-time code's top-level and
embedded origins are always "https"
, assisting the user with providing
origin-bound one-time codes is only available in secure contexts.¶
Per [BCP90], the following provisional message header field will be submitted to the IANA Message Headers registry:¶
This document attempts to mitigate the phishing risk associated with the delivery of one-time codes over SMS and email by enabling User Agents to know what website the one-time code is intended for.¶
This document does not attempt to mitigate other risks associated with the delivery of one-time codes over SMS or email. Interception of messages by untrusted parties, and account cloning and takeover attacks are still possible even with domain-binding information.¶
Sites would do well to consider using authentication technologies such as [WEBAUTHN] for authentication or verification.¶
Any party which has access to a user’s SMS or email messages (such as the user’s cellular carrier, mobile operating system, or anyone who intercepted the message) can learn that the user has an account on the service identified in an origin-bound one-time code message delivered over these transport mechanisms.¶
On some platforms, User Agents might need access to all incoming SMS and email messages---even messages which are not origin-bound one-time code messages---in order to support the autofilling of origin-bound one-time codes delivered over SMS or email in origin-bound one-time code messages.¶
Apple and Google ship implementations of the domain-bound one-time code parser for SMS messages.¶
Many thanks to Aaron Parecki, Arielle Davenport, Ashley Clark, Elaine Knight, Eric Shepherd, Irene Valdes Salazar, Jay Mulani, Phillip Tao, Ricky Mondello, and Steven Soneff for their valuable feedback on this document.¶