Giter Site home page Giter Site logo

web-otp's Introduction

WebOTP

This repository documents an API for accessing one time passwords to verify credentials (e.g. phone numbers).

The API has a test suite in the Web Platform Test project.

Resources

This API is inspired by and loosely based on the following discussions:

The WebOTP API has also been discussed in the following places:

web-otp's People

Contributors

ayuishii avatar cwilso avatar hober avatar iahmed5 avatar nidhijaju avatar samthor avatar samuelgoto avatar scheib avatar sideshowbarker avatar sso-google avatar tomayac avatar yi-gu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

web-otp's Issues

Space handling

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

Localize For:

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.

Improving attribute definitions

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:

  • One of the inherited attributes. (But not both of them.)
  • One internal slot.
  • One attribute of OTPCredential.

I would suggest a structure more like the following.

The [[type]] internal slot of OTPCredential 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.

Support WebOTP in cross-origin iframe

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.

Proposal

SMS format

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.

Nested iframes

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)

    • Note: this could be mitigated in verification via email
  • 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:

  • a.com -> b.com
  • a.com -> b.com -> b.com
  • a.com -> a.com -> b.com
  • a.com -> b.com -> c.com

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.

  • a.com -> b.com -> a.com

Permissions Policy

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

Message access pop-up appears even after aborting.

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:

  1. Start listening for the OTP through credentials.get
const abortController = new AbortController();

const otpConfig = {
  otp: { transport: ['sms'] },
  signal: abortController.signal
};

credentials.get(otpConfig).then(<some more code>)
.......
  1. Then abort the controller in setTimeout
    abortController.abort()
  2. Now send the sms after the controller is aborted, the message access pop-up still appears.

How to define OtpCredential.id

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.

Option 1

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"
});

Option 2

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.

Why stop working if I add sender to my contacts?

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).


https://web.dev/web-otp/

“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.”

https://developers.google.com/identity/sms-retriever/user-consent/request#2_start_listening_for_incoming_messages

“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?

Why is the JavaScript API tightly bound to SMS?

@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?

Should OTPCredential have `transport`?

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;
}

Requirements for OTPCredentialRequestOptions.transport are incompatible with WebIDL

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?

Chromes 79-81 on Android 9 don't receive SMS

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?

Email OTP

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?

SMS without hashes

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.

Screenshot_20190921-112509

Maybe we should look in this direction?

  • It does not make your SMS message look ugly. Format it as you like.
  • It's still native API for retrieving codes.
  • No cons for iOS users. They will receive clean SMSs and their keyboard suggestions will work as always.

Why is options["otp"] guaranteed to exist in [[DiscoverFromExternalSource]]?

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.

[[DiscoverFromExternalSource]] introduction duplicates credential management spec?

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.

JavaScript API can't be used for polyfilling autocomplete=one-time-code in practice

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?

Extensibility of navigator.credentials.get({otp: true})

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) => {
    // .... 
});

/cc @samuelgoto @sso-google @mikewest

Typos and other editorial issues

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"

OTPCredentialRequestOptions's transport definition is weird

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.

Repo is fork

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).

Inaccuracies in framing of "comparable APIs" in explainer

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:

  1. The Safari feature is called Security Code AutoFill.
  2. Safari on macOS has Security Code AutoFill; not just Safari on iOS.
  3. The feature on iOS is available for use in all web browsers, not just Safari. It is a system-wide feature, integrated into the keyboard.
  4. To say that Safari on iOS has a "declarative autocomplete API that provides an integration with the native keyboard" is incorrect. Safari has an AutoFill feature for SMS-delivered one-time codes that works automatically across the web. Detection of relevant form fields happens with heuristics, but websites can tell any user agent that a field is for one-time codes by using the HTML Standard’s autocomplete=one-time-code.
  5. You say "iOS applies heuristics", followed by, "Here is what it looks like". What you're showing isn't heuristics; it's an example of using standard HTML markup to inform user agents of a field's intent, which Security Code AutoFill happens to use.

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.

web opt API not working in react.js

Below points i want to know about web-otp API

  • I am trying to implement in react app but is is not working.
  • I tested available script using html file but on my chrome browser "OTPCredential" key is not found on chrome window
  • How to check which mobile device is support this web-opt

please help me in above points
Thanks & Regards
Pralhad

privacy differences between declarative and imperative forms of API

@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.

Software-based OTP Applications

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?

Long-term plan for app hashes

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

security issues

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.

Support for web push notification as a transport mechanism

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?

Permissioning, user consent, and the Imperative API

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.

Explanation for not using "trustworthy urls" is confusing

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.