Introduction
This section is non-normative.
Many websites deliver one-time codes over SMS. [GSM-SMS]
Without a standard format for such messages, programmatic extraction of codes from them has to rely on heuristics, which are often unreliable and error-prone. Additionally, without a mechanism for associating such codes with specific websites, users might be tricked into providing the code to malicious sites.
This specification defines a format for the delivery of one-time codes over SMS. This format associates the one-time code with a specific website.
1. Infrastructure
This specification depends on the Infra Standard. [INFRA]
2. Origin-bound one-time codes
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).
(("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"
.
(("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"
.
2.1. Usage
Many User Agents help users fill out forms on websites. Sites can use features like autocomplete=one-time-code
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 to provide 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 not
null
, return failure. -
If otc’s top-level origin is same origin with doc’s origin, return
"origin"
. -
If otc’s top-level origin is same site with doc’s origin, return
"site"
. -
Return failure.
-
-
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.
3. Message format
An origin-bound one-time code message is a string for which parsing an origin-bound one-time code message successfully returns an origin-bound one-time code.
3.1. Authoring
This section is non-normative. § 3.2 Parsing is the normative text.
Origin-bound one-time code messages can optionally begin with human-readable explanatory text. This consists of all but the last line of the message. The last line of the message contains 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 can be specified. It is preceeded with a U+0040 (@) sigil.
In the following origin-bound one-time code message, 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"
In the following origin-bound one-time code message, 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\n"
.
"747723 is your ExampleCo authentication code. @example.com #747723 @ecommerce.example"
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.
The message "something @example.com #747723"
is not an origin-bound one-time code message, because it doesn’t start with the top-level host.
The message "#747723 @ecommerce.example @example.com"
is not an origin-bound one-time code message, because the fields are in the wrong order.
Exactly one U+0020 (SPACE) separates the values in the last line of the message.
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.
Trailing text in the last line is ignored. This is because we might identify additional information to include in origin-bound one-time code messages in the future. If we do, new syntax could be introduced after the existing syntax in the last line.
In the origin-bound one-time code message "@example.com #747723 @ecommerce.example $future"
, 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.
3.2. Parsing
To parse an origin-bound one-time code message from message, run these steps:
-
Let line be the last line 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 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 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 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.
4. Security considerations
This specification attempts to mitigate the phishing risk associated with the delivery of one-time codes over SMS by enabling User Agents to know what website the one-time code is intended for.
This specification does not attempt to mitigate other risks associated with the delivery of one-time codes over SMS, such as SMS spoofing, SIM swapping, SIM cloning, ISMI-catchers, or interception of the message by an untrusted party.
Sites would do well to consider using non-SMS technologies such as [WEBAUTHN] for authentication or verification.
5. Privacy considerations
Any party which has access to a user’s SMS 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 SMS.
On some platforms, User Agents might need access to all incoming SMS 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 in origin-bound one-time code messages.
Acknowledgements
Many thanks to Aaron Parecki, Elaine Knight, Eric Shepherd, Eryn Wells, Jay Mulani, Ricky Mondello, and Steven Soneff for their valuable feedback on this proposal.