wicg / web-otp Goto Github PK
View Code? Open in Web Editor NEWThis project forked from sso-google/sms-otp-retrieval
phone number verification
Home Page: https://wicg.github.io/web-otp/
License: Other
This project forked from sso-google/sms-otp-retrieval
phone number verification
Home Page: https://wicg.github.io/web-otp/
License: Other
@dbaron, @hadleybeeman, and I took a look at w3ctag/design-reviews#391 today in our Wellington F2F. We have a variety of feedback, of which this issue is one.
In the JavaScript API, navigator.credentials.get()
takes an options dictionary that specifies that the desired credential is a one-time-code, and that it comes over SMS:
navigator.credentials.get({otp: {transport: ["sms"]})
This is in contrast to autocomplete=one-time-code
, which does not specify the source of the one-time-code. It could be from SMS, from a TOTP app, or from some other source. The author of the page doesn't have to say where the code comes from. This seems to us a simpler API to code to than the JavaScript API, that is perhaps more resilient to changes in the site's authentication mechanisms. The Rule of Least Power suggests we should prefer the simpler approach that solves the same use case.
Why tie the JavaScript API to SMS like this? Why not follow autocomplete=one-time-code
?
https://wicg.github.io/WebOTP/#intro-abort
I believe
let {code, type} = await navigator.credentials.get({
abort: signal,
otp: {
transport: ["sms"]
}
});
should be
let {code, type} = await navigator.credentials.get({
signal,
otp: {
transport: ["sms"]
}
});
There are a couple of ways I think this could go.
The first way, I'm thinking we would need some sort of convention with email providers (the same way we needed a convention for SMS messages).
It would seem we would need two parts:
(a) a machine-readable convention inside the email email with the OTP code and
(b) some sort of browser API that allows an email provider to push/pull the OTP to/from the browser.
On (a), maybe something along the lines of a meta
tag inside of the HTML email body would get the job done?
<meta name="one-time-code" content="1234">
On (b), something along the lines of browser API to push the code to the browser:
navigator.credentials.store({type: "email", audience: "https://example.com", otp: "1234"});
Or maybe an API that allows browsers to pull (maybe something like /.well-known/one-time-code
?) as opposed to waiting for the push. For example:
GET /.well-known/one-time-code HTTP/1.1
Host: www.email.com
Responds with:
HTTP/1.1 200 OK
Content-Type: text/json; charset=UTF-8
{"otp": 123}
A website would call the WebOTP API passing the transport type = email
to request it:
let {otp} = await navigator.credentials.get({transport: "email"});
Or declaratively:
<input autocomplete="one-time-code">
WDYT?
Hi,
@dbaron, @hadleybeeman, and I took a look at w3ctag/design-reviews#391 today in our Wellington F2F. We have a variety of feedback, of which this issue is one.
It looks like one of the main purposes of the JavaScript API is so it can be used to polyfill autocomplete=one-time-code
. It seems unlikely to us that a browser will ship with the JavaScript API but without autocomplete=one-time-code
, so it seems to us that the API can't realistically be used to polyfill the autofill feature in the wild since browsers which lack the autofill feature also lack this JavaScript API.
Do you anticipate that there will be browsers with the JavaScript API but without autocomplete=one-time-code
?
In the initial launch of the WebOTP API, because we didn't find enough demand that outweighs the risk / complexity, we deliberately ignored the cross-origin iframe support. i.e. calling the API in a cross-origin iframe does not work.
With more partners requesting the feature, we should revisit the underlying privacy issue / risks and add the support if considered necessary.
There are ongoing discussions regarding how to update the existing "Origin-bound one-time codes delivered via SMS" specification to accommodate cross-origin iframes. We proposed the following format to preserve backward compatibility for other UAs:
@top #code @iframe
See the discussions for more details.
From the extensibility’s point of view, we should support an arbitrary level of nested iframes in the long run. In theory, we should include origins from all the intermediate frames to reduce ambiguity. For example, consider the following artificial example:
store.com -> productA.com -> payment.com
store.com -> productB.com -> payment.com
On the random merchandise website store.com there are two products from two different origins. However both products use the same payment widget to verify the payment info. In this case, when payment.com sends out the SMS, it must include the intermediate origin otherwise the user will receive two SMSes with the same format:
SMS 1: @store.com #1234 @payment.com
SMS 2: @store.com #5678 @payment.com
However there are some practical concerns:
Including all intermediate origins may easily break the 160 character limit for SMS (and 67 char for UCS-2 encoding)
Including all intermediate origins may confuse users
There are security concerns for the innermost iframe to access top-frame’s origin to use it in the SMS.
As a result, we proposed to limit the support to cross-origin iframes who have no more than 1 unique origin in its ancestor chain. In the following scenarios:
using WebOTP in b.com will be supported but not in c.com.
Note that the following scenario is not supported because of lack of demand and UX complexities.
By default, navigator.credentials.get()
requires a secure origin and all its ancestor frames must have the same origin as the requestor does. Therefore we should add an otp-credentials
permissions policy to obtain the credentials assertions in cross-origin iframes. Note that navigator.credentials.create()
is still disabled in cross-origin iframes. Sample usage:
<! -- top_origin.com -->
<iframe allow="otp-credentials" src="cross-origin.com"></iframe>
Chromium tracking issue: https://bugs.chromium.org/p/chromium/issues/detail?id=1136506
While crawling WebOTP API, the following links to other specifications were detected as pointing to non-existing anchors, which should be fixed:
This issue was detected and reported semi-automatically by Strudy based on data collected in webref.
Below points i want to know about web-otp API
please help me in above points
Thanks & Regards
Pralhad
The specification draft link in the README is a dead link
In https://wicg.github.io/WebOTP/#security-availability you describe a number of checks, yet the actual algorithm instead checks if the origin is opaque. As such it is unclear (to me) what the actual limitations for usage are.
Is there any current thinking about how software-based OTP applications would be supported with this specification? I'm imagining a scenario, as is common today, in which a user scans a QR code to create a new OTP on their favorite authenticator app.
Obviously, in order to facilitate auto-filling by the browser, the application would have to have some sort of transport (bluetooth, internal, etc) to connect with the browser. This transport may even be a way to create an OTP in the application, rather than having to scan a QR code.
That being said, it is conceivable that the web app will not know which transports are available (unlike SMS or email, which require server involvement in creating/delivering the OTP). Is it expected to define transports for such cases? Or leave the transport unspecified?
As Apple decided to never support extending any element but HTMLElement
Step 1 asserts that it does. However, this dictionary member is not required per https://wicg.github.io/WebOTP/#CredentialRequestOptions.
My guess is that there's some sort of dynamic dispatch involved, where [[DiscoverFromExternalSource]] only gets called if otp
is present? If so I'd expand on the assert to say something like:
Assert: options["otp"] exists, because otherwise the credential management specification machinery would not have called this method.
Hello,
May I ask the supported browser/version for this specification?
This is because dictionaries are ordered maps, which use the bracketed lookup syntax.
See WebAuthn's and FedCM's there too:
https://github.com/w3c/webappsec-permissions-policy/blob/main/features.md
Chrome 79.0.3945.136 on Android 9 doesn't have a permission to read SMS listed and it doesn't ask for it when using SMS Receiver API, thus it's impossible to use this API.
Seems the API used on Android doesn't need additional permissions. Nevertheless, even though I have the Origin Trial token in place and the API available, SMS is not received. My test code is here.
Tested on Huawei device and on Xiaomi Device, double-checked in the system there's no permission for SMS granted for Chrome app. Also checked Chrome Beta (80.0.3987.68) and Chrome Canary (81.0.4036.0) - same problem.
How would I test this API @samuelgoto?
Looking through the howto and the associated link for obtaining hashes on Android, is there a way to acquire the hash within the page? Currently it seems as if the developer would need to check the browser user agent to obtain a version number and map that to a specific channel which will also update on a regular basis.
Would there be any risk / issue to exposing something like navigator.sms.appHash
?
Or given "Long term, we expect the formatting to be browser agnostic…" is the purely something that is an expected implementation detail for early adopters / experimenters?
/cc @agektmr
The explainer says:
Secondly, Safari on iOS has a declarative autocomplete API that provides an integration with the native keyboard. iOS applies heuristics to extract OTPs from SMSes to pass it back to the element. Here is what it looks like:
<input autocomplete="one-time-code"/>
This is only somewhat true. A few points:
To characterize Safari's feature as a comparable API is misleading, because Safari's feature is not a declarative autocomplete API; it is a browser feature with standardized markup that can inform it.
PSA: repo was renamed to adhere to the WICG naming policy as part of WICG/admin#112
Team, while reading sms, can we handle text message with/ without space after 'For:' ?
'For: https://.....' => Promise rejects/ resolve
'For:https://.....' => Promise in pending state (no timeout)
Sometime it gets tough for developer to figure out this missing space.
@samuelgoto
E.g.
If effective domain is not a valid domain, then return a DOMException whose name is "SecurityError" and terminate this algorithm.
can just be
If effective domain is not a valid domain, then return a DOMException whose name is "SecurityError".
https://wicg.github.io/WebOTP/#security-availability makes some claims, but it's not clear how they are enforced.
I think the secure contexts requirement is enforced via Web IDL's [SecureContext]
attribute. If so it'd be good to state that.
I have no idea how the top-level frames requirement is enforced. Maybe as part of credential management? I didn't see any spec text for it.
OTPCredentialRequestOptions
specifies a transport
, of type sequence<OTPCredentialTransportType>
. However, it's not specified if the ordering has any meaning. I know only one is currently defined, but I think this needs to be specified now.
This issue is to talk about defining parameters to get an OTP while thinking about extensibility. Although the {otp:true}
is simple and straight forward, are we binding ourselves from extending the API in the future. If we want to extend this beyond just recieving OTP by SMS, would we want to be able to specify a transport type? What other aspects of extensibility should we be thinking about?
Ex.
navigator.credentials.get({otp: ["sms"]}).then((credentials) => {
// ....
});
In step 2 in https://wicg.github.io/WebOTP/#sctn-discover-from-external-source you seem to re-assign |options| to be the OTPCredentialRequestOptions inside the CredentialRequestOptions object, however later in that algorithm you still use |options| to refer to the outer CredentialRequestOptions object. You should probably not use the same name for two different objects/variables.
It's not working with my URL. Please help
I'm not Android developer and don't know any technical details, but in my company Android devs use native Android API that does not require permissions and special message formatting for handling messages that contain code.
Maybe we should look in this direction?
The AbortSignal / AbortController API has changed recently to support passing a reason. This reason should be checked instead of the aborted flag
, see the DOM spec.
@hober, @hadleybeeman and I are looking at w3ctag/design-reviews#391 in a breakout at our Wellington face-to-face.
There appears to be a somewhat substantive difference between the privacy characteristics of the declarative version and the imperative API. With the declarative version, the user is proving that they're in possession of the device with that phone number (or closely communicating with the person in possession of it), but with the API version they're proving that the web site access is actually happening on the device with that phone number. While this may not be a huge difference, it does seem like it could be substantive in a number of cases.
We're curious what you think about this difference and whether it influences your opinions on the tradeoffs between the two forms of the API. It also seems like this difference should perhaps be discussed in the explainer and/or the responses to the Security and Privacy Questionnaire.
Apologies if I’ve missed it, currently on my phone, but I can‘t find a reason why this would break if I add the sender to one of my contacts?
For example, one bank I use sends messages from “HSBCUKTOKAC”. So I see something less suspicious, I’ve added that to the banks contact details (and don’t get me started on the other weird and stupid things they do).
“If the sender's phone number is included in the receiver's contact list, this API will not be triggered due to the design of the underlying SMS User Consent API.”
“The message was sent by a phone number that's not in the user's contacts.“
https://github.com/WICG/WebOTP/blob/master/FAQ.md
No mention?
A few minor issues.
Probably useful to replace (in the Intro section)
sending one-time-passwords
with
sending one-time-passwords (OTP)
so that OTP is defined somewhere.
Typos:
"happilly" in section https://wicg.github.io/WebOTP/#security-tampering
"targetted" in 3rd paragraph of https://wicg.github.io/WebOTP/#privacy
"Nonetheless, The" in the 5th paragraph.
In https://wicg.github.io/WebOTP/#security-availability, replace "when the origin match, but" with "when the origins match, but" or "when the origin matches, but"
This issue is to talk about how we should define credential.id. There has been a few opinions that have come up which I've listed below but other options/opinions are welcome as well.
Defining credential.id as OTP. This defines id as the user identifier from the the code distributor perspective and also removes the need to have a redundant otp field within credentials.
navigator.credentials.get({otp: true}).then((credential) => {
// credential.type == "otp"
// credential.transport = "sms"
// credential.id == "ABCD893443"
});
Defining credential.id as undefined. However leaving the opportunity to let it be set to other user identifiers such as email addresses if in the future we add support to other transports like email OTP retrieval.
navigator.credentials.get({otp: true}).then((credential) => {
// credential.type == "otp"
// credential.transport = "sms"
// credential.otp == "ABCD893443"
// credential.id == undefined | empty
});
/cc @samuelgoto @sso-google @mikewest
Also please correct me if I've misstated something.
In https://wicg.github.io/WebOTP/#OTPCredentialRequestOptions is written "This OPTIONAL member contains a hint as to how the server might receive the OTP. The values SHOULD be members of OTPCredentialTransportType but client platforms MUST ignore unknown values.".
However WebIDL requires that converting a string to an enum throws a TypeError
(https://heycam.github.io/webidl/#es-enumeration) if the string is not a valid enum member. If you do want the behavior you're describing, you should probably define transport as a sequence<DOMString>
instead?
Is there an option to abort sms.receive
?
In both the explainer and the spec you say "We don't entirely adopt the concept of trustworthy urls because it covers more schemes (e.g. data://123)", however data URLs are opaque origins, and opaque origins are not trustworthy.
There might be other reasons why using "trustworthy url"/trustworthy origin doesn't match what you want, but the given explanation seems wrong.
Earlier, @mikewest said:
I'm curious about the value of informing the developer about the transport over which the OTP was delivered. Won't they know how they went about sending the value to the user? Is there additional benefit to encoding that in the OTPCredential object as well?
In this thread. This issue is tracking the resolution to that question.
interface OTPCredential : Credential {
readonly attribute DOMString code;
}
https://wicg.github.io/WebOTP/#OTPCredential uses a <dl>
to define the attributes. I imagine this was done similar to another spec, but I think it's bad practice and fairly confusing.
Right now the <dl>
mixes together three things:
I would suggest a structure more like the following.
The
[[type]]
internal slot ofOTPCredential
objects is set to the string "otp
".The
code
attribute's getter returns...
Now, the getter needs to have an algorithm that actually returns something. Right now it just says "The retrieved one time password", but this isn't helpful. How does it get retrieved?
Instead, you need to define a getter algorithm. Usually this returns some internally-held value, which is set by some other algorithm. I can't find where in the spec this value would actually be set; in fact the "code" attribute only seems to be mentioned in examples. So, you need to have some algorithm that stores an internal code value at some point (perhaps in a [[code]]
internal slot---which will need a default value!). And then you need to write the getter algorithm to return that internal value.
Hello there,
According to the specification, transport mechanisms such as SMS
, email
, and hardware devices
can be used to enable OTP in a browser. Currently, the SMS option is being explored extensively and I was able to implement OTP retrieval on Chrome with provided code snippets. I believe web push notifications
could serve as a good alternative to SMS transport in the mobile web landscape. Is there any plan or ongoing work to add web push notifications as a transport mechanism to deliver OTP on mobile browsers via web push notifications?
The introduction to [[DiscoverFromExternalSource]] is very informative, and even helpful. However, I worry that by basically reproducing the parts of the credential management spec (albeit in a more-readable form), you're breaking the abstraction boundary and creating a potential maintenance burden.
I think this section of the spec should just be concerned with the implementation, leaving discussion of the interface up to the credential management spec.
One way of thinking about this is if in C++ or JS, you duplicated the documentation for your superclass onto the subclass, when overriding a protected virtual method. That seems not great; the understanding is that the superclass takes care of the interface, and you, the subclass, take care of the implementation.
This OPTIONAL member contains a hint as to how the server might receive the OTP.
It's unclear why a sequence of strings, which can only be "sms", would provide a hint. Maybe something more like "This member contains a list of hints as to how the server might receive the OTP"? But I don't know, it's still pretty confusing.
The values SHOULD be members of OTPCredentialTransportType but client platforms MUST ignore unknown values.
First, I don't know what a "client platform" is. Is it a user agent?
Second, this isn't how Web IDL works. Web IDL will automatically throw an exception if a different type is in the sequence.
I think this second sentence should just be deleted, leaving the type system stuff to Web IDL.
I can't implement the current spec on SMS in spanish. It would be nice to have the next SMS format instead:
123456 es tu código OTP
http://localhost/?otp=123456&EvsSSj4C6vl
Where the OTP is the first number appearing in the SMS message and the origin is the last url in the SMS message.
When using a web OTP with windows.navigator the popup to access newly received message appears, it is fine. But this popup appears even after aborting the abortcontroller.
Try hitting submit without sending sms , this aborts controller, now send sms, the popup still appears.
Stackblitz example
Steps to reproduce:
const abortController = new AbortController();
const otpConfig = {
otp: { transport: ['sms'] },
signal: abortController.signal
};
credentials.get(otpConfig).then(<some more code>)
.......
abortController.abort()
where to discuss abt the security issues ? i tried it without the otp it will work too , this gonna become large amount of abuse in future.
It currently copies the whole thing. But, it would be a better experience for me if it says "Copy OTP" and does just that. Thanks!
I noticed this repo is a fork. That's going to cause issues for folks contributing, as pull requests will always try to go back to "sso-google/sms-otp-retrieval". Ideally, the repo should have been transferred, not forked.
It's might be worth while transferring the repo over to the WICG still, and we can transfer the issues from here to the new repo (and delete this one).
Hi all,
@hober, @dbaron and I are looking at w3ctag/design-reviews#391 in a breakout at our W3C TAG Wellington face-to-face.
One thing I'm concerned about:
The Imperative API, as I read it, operates by pulling SMS content from the operating system, without the user knowing that that's what's happening.
While I understand that that creates a smooth UX, it also feels counter to the rest of the web architecture that doesn't escape from the user agent into the OS without the user's explicit permission. (I'm thinking of device APIs, for example, which would allow the camera to send video or the microphone to send audio – after getting the user's permission by a prompt.)
The way you're recommending this work, it doesn't do that; it just reaches in and takes. This seems the complete opposite of solutions like autocomplete="one-time-code"
, which leave the control – and indeed, the content of the SMS – in the hands of the user.
The Imperative API's approach seems counter to the W3C TAG's Ethical Web Principles, specifically the principle on Security and Privacy, which includes:
We will start by creating web technologies that create as few risks as possible, and will make sure our users understand what they are risking in using our services.
I'd be grateful for your thoughts on this.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.