1 of 76

Making the Web work for users

Sign-in and Web Payments

@cwilso

Chris Wilson

2 of 76

The web is better than ever

3 of 76

The web is about reducing friction

4 of 76

…and building relationships

5 of 76

  • Getting users �to come back�
  • Getting users to give you money

6 of 76

how many of you work on sites with user logins?

7 of 76

Passwords.

8 of 76

Use short & simple passwords.

Typical users...

9 of 76

Use short & simple passwords.

Typical users...

10 of 76

Use short & simple passwords.

Reuse passwords across sites.

Typical users...

11 of 76

Use short & simple passwords.

Reuse passwords across sites.

Do not enable 2nd factor auth.

Typical users...

12 of 76

Identity should be a first class citizen of the web platform

13 of 76

Federated login should be supported by automated login.

14 of 76

Help password managers do their jobs

15 of 76

9B forms and passwords filled per month

(just in Chrome)

16 of 76

Top 3 issues...

making life hard for password managers

  1. Broken markup and improper annotations
  2. Unnoticeable form submissions
  3. Mixing HTTP and HTTPS

17 of 76

Markup and annotations

Use <form> tags to group belongs together.

Do not use empty or duplicate name and id attributes.

Provide autocomplete annotations

<input

name="..."

type="text|password"

autocomplete="username|current-password|new-password">�

18 of 76

Unnoticed form submissions

Use

old-school form HTTP posts or

XHRs/fetch() followed by form removal and history.pushState()

to help detect form submission.

19 of 76

We ♥ HTTPS�Use it everywhere

<form action=”https://example.com/signin”>� ...�</form>

http://example.com

goo.gl/6e0mKk

20 of 76

We ♥ HTTPS�Use it everywhere

goo.gl/6e0mKk

<form action=”https://example.com/signin”>� ...�</form>

http://example.com

<iframe src=”https://example.com/signin”>� ...�</iframe>

http://example.com

21 of 76

45% success rate for a well-designed phishing page!

http://services.google.com/fh/files/blogs/google_hijacking_study_2014.pdf

Or you can do half screen if you have text

22 of 76

A user who doesn’t know their password is hard to phish.

23 of 76

24 of 76

The Credential Management API

25 of 76

By showing account chooser dialog, users can sign in just by selecting an account to sign-in with.

One tap sign-in

26 of 76

Provides seamless login account selection experience between id/password and federated logins.

Remembers federated login

27 of 76

Helps websites with short session duration and also cross device access.

Enables auto sign-in

28 of 76

29 of 76

30 of 76

41%� higher sign-in rate

85% fewer sign-in failures

11% better conversion rate

31 of 76

Getting a credential

navigator.credentials.get({� password: true,� federated: {� providers: ['https://accounts.google.com']� }���}).then(credential => {� ...�});

No credentials: Returns `undefined`

1 credential: Returns a credential immediately

2+ credentials: Shows account chooser dialog

32 of 76

Getting a credential

navigator.credentials.get({� password: true,� federated: {� providers: ['https://accounts.google.com']� },� unmediated: true,��}).then(credential => {� ...�});

No credentials: Returns `undefined`

1 credential: Returns a credential immediately

2+ credentials: Shows account chooser dialog

33 of 76

Getting a credential

navigator.credentials.get({� password: true,� federated: {� providers: ['https://accounts.google.com']� },� unmediated: true,� mediation: 'silent'�}).then(credential => {� ...�});

No credentials: Returns `undefined`

1 credential: Returns a credential immediately

2+ credentials: Shows account chooser dialog

New! Starting in Chrome 60

34 of 76

Turning off auto sign-in

// Turn off auto sign-in.�navigator.credentials.requireUserMediation();

Enforces to show account chooser dialog

35 of 76

return fetch('/signin', {� method: 'POST',� credentials: credential� }).then(response => {� // handle auth response� });����

36 of 76

return fetch('/signin', {� method: 'POST',� credentials: credential� }).then(response => {� // handle auth response� });�� let password = credential.password;� // Use your easiest way to authenticate�

New! Starting in Chrome 60

37 of 76

if (credential.password === undefined) {� return fetch('/signin', {� method: 'POST',� credentials: credential� }).then(response => {� // handle auth response� });�} else {� let password = credential.password;� // Use your easiest way to authenticate�}

38 of 76

Store a credential

<form id="signin" method="post">� <input name="email" type="text"

autocomplete="username">� <input name="password" type="password"

autocomplete="current-password">� <input type="submit" value="Sign Up!">�</form>

var form = document.querySelector('form#signin');

var credential = new PasswordCredential(form);�navigator.credentials.store(credential);

39 of 76

Store federated login account

  • identity provider
  • id
  • name (optional)
  • iconURL (optional)

var credential = new FederatedCredential({� provider: 'https://accounts.google.com',� id: 'cwilso@gmail.com',� name: ‘Chris Wilson',� iconURL: 'https://lh3.googleusercontent.com/***'�});�navigator.credentials.store(credential);

id token (OpenID Connect)

access token (OAuth)

40 of 76

Between same subdomains

Sharing credentials

41 of 76

Between same subdomains

Between different domains

Sharing credentials

Planned for Chrome 61

42 of 76

Sharing credentials between different domains

http://digitalassetlinks.org

// https://www.example.com/.well-known/assetlinks.json�// Content-Type: application/json��[{� "relation": [

"delegate_permission/common.get_login_creds"

],� "target": {� "namespace": "web",� "site": "https://www.example.jp"� }�}]��

  • Use "Digital Asset Links"

43 of 76

Learn more

44 of 76

Paying for stuff is still hard.

45 of 76

This is still how we buy things online.

Or you can do half screen if you have text

46 of 76

Long checkouts are one of the leading causes of abandonment

47 of 76

US mobile commerce sales will be over $150 billion this year

Source: eMarketer

48 of 76

The web needs a better answer for payments.

49 of 76

Good news: It exists

PaymentRequest is an

open-standard,

cross-browser,

ready-to-be-used-today

API for transacting on the web.

50 of 76

Not a processor.

51 of 76

Demo

https://polykart-credential-payment.appspot.com/

52 of 76

53 of 76

PaymentRequest

A primer

54 of 76

Define how you can get paid

var methodData = [{� supportedMethods: ['basic-card']�}, {

supportedMethods: ['https://google.com/pay']

}];

55 of 76

Define how you can get paid

var methodData = [{� supportedMethods: ['basic-card']�}, {

supportedMethods: ['https://google.com/pay']

}];

56 of 76

Define details of the transaction

var txDetails = {� total: {� label: "Purchase Amount",� amount: { currency: "GBP", value: "24.99" },� },

displayItems: [{� label: 'Subtotal',� amount: { currency: 'GBP', value: '10.00' },� }, { }]�};

57 of 76

Define details of the transaction

var txDetails = {� total: {� label: "Purchase Amount",� amount: { currency: "GBP", value: "24.99" },� },

displayItems: [{� label: 'Subtotal',� amount: { currency: 'GBP', value: '10.00' },� }, { }]�};

58 of 76

Request additional information

var options = {� requestShipping: true,� requestPayerEmail: true,� requestPayerPhone: true,� requestPayerName: true�}

59 of 76

Request additional information

var options = {� requestShipping: true,� requestPayerEmail: true,� requestPayerPhone: true,� requestPayerName: true�}

Fully dynamic, paired with shipping options

60 of 76

Construct the request

var pr = new PaymentRequest(methodData, transactionDetails, options);��pr.show().then(function(paymentResponse) {� // Send paymentResponse to server or gateway� paymentResponse.complete('success').then(function() {� // UI has been closed down� });�});

61 of 76

Show the sheet, get paid

var pr = new PaymentRequest(methodData, transactionDetails, options);��pr.show().then(function(paymentResponse) {� // Send paymentResponse to server or gateway� paymentResponse.complete('success').then(function() {� // UI has been closed down� });�});

62 of 76

Close the sheet

var pr = new PaymentRequest(methodData, transactionDetails, options);��pr.show().then(function(paymentResponse) {� // Send paymentResponse to server or gateway� paymentResponse.complete('success').then(function() {� // UI has been closed down� });�});

63 of 76

Know ahead of time if a user can pay

request.canMakePayment().then(function(result) {� if (result) {� // User has way to pay� } else {� // User doesn't have a way to pay� }�}).catch(function(err) {� console.log("Uh oh...")�});

64 of 76

65 of 76

Works cross-browser

Or you can do half screen if you have text

COMING SOON

66 of 76

67 of 76

A challenge

What percentage of your transactions, especially on mobile, have one item in the cart at checkout?

68 of 76

Up to 80% of checkouts only contain a single product

69 of 76

Add a “Buy now” button directly on product pages

Or you can do half screen if you have text

Conditionally show with canMakePayment

70 of 76

Enabling users around the globe to pay with any form of payment

Third party payment types

71 of 76

Early partners we’re working with

Or you can do half screen if you have text

72 of 76

Integrating your app

Three simple steps

1. Define an identifying URL

2. Update your application

3. Set up your manifests

73 of 76

Web app support up next

No installation. Immediate availability. Global reach.

Or you can do half screen if you have text

74 of 76

Get started

PaymentRequest integration guide

g.co/PaymentRequestGuide

Android 3P Integration Guide

g.co/PayAppIntegration

PaymentRequest codelab

g.co/PaymentRequestCodeLab

75 of 76

76 of 76

Thank you!

@cwilso

This deck: goo.gl/F9PGxY