WWDC2014 Session 506

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Welcome to Session 506, "Your
App, Your Website, and Safari."
My name is Ricky Mondello,
and I'm an engineer
on the Safari and WebKit team.
So before we get started,
I'm going to ask one
obvious question.
Show of hands and then
a second question.
So first off, how many of you
have apps in the App Store?
Nearly all of you.
Great. Welcome to WWDC.
You're in the right place.
How many of those apps
have an associated website?
Another show of hands.
That's excellent.
You are all in the right place.
Awesome. So yesterday you
saw Craig demo a bunch
of cool new features
with the name Continuity.
The ability to pick up writing
an email where you left off
from one device to another.
Picking up a phone call
from one device to another.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Picking up a phone call
from one device to another.
I've been thinking
about Continuity.
Continuity is more than
just a suite of features
that we've included in
OS X Yosemite and iOS 8.
Just a regular old word.
Looked it up in the dictionary.
It's the unbroken and consistent
experience or operation
of something over
a period of time.
I take comfort in this
definition because unbrokenness
and consistency are
exactly what all
of us users are looking
for today.
Many of us own more
than one device.
We move between those
devices throughout our day.
Something that's not uncommon
is starting a task within an app
on your iPhone and finishing it
up later on the app's website
on your Mac, for instance.
And this year, we've
got a cool technologies
that you can participate
in Continuity.
Handoff. That's exactly
what Craig used to move
from sending an email
on one device
to typing it up on the other.
We've got a full session
on Handoff this year.
It's tomorrow at 2 p.m. So
if you're here, you're going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's tomorrow at 2 p.m. So
if you're here, you're going
to be interested
in that as well.
But even before Handoff,
users are making these kinds
of transitions between
apps, websites
and various devices
every single day.
And in this session I'm
going to go over some
of the best opportunities
that we've identified
to make these kinds
of transitions smoother
for our users.
Ensuring Continuity for
all of our users is going
to require a holistic approach
to software development.
Bringing together three
different kinds of disciplines.
The first discipline is
that of the App developer,
whoever's writing
Cocoa, Cocoa Touch,
Objective-C and now Swift.
Probably most of you
in this audience.
But it's also going to take the
back-end website administrator.
It's also going to take the
back-end website administrator.
Whoever's running user
accounts, state, databases,
all that sort of stuff.
But finally, it's also going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But finally, it's also going
to take the front
end web developer.
Whoever is writing
JavaScript, HTML,
CSS or whatever cool new
fancy languages preprocessing
down to those these days.
So if you're here, you
probably specialize
in one of these areas.
You might know about
two of them.
You might just be
getting started.
Or if you work in a one-person
shop, you might be responsible
for all three of these aspects
of your application or service.
Regardless, no matter
which bucket you fall into,
you're going to leave
this session today
with actionable techniques
you can put into place
to make your users'
experiences better.
Specifically what
we're going to go
into today is giving your native
iOS app access to credentials
that Safari has stored
for your website
to make your users' login
experiences easier than ever.
Then we're going to learn about
AutoFill and how that works
on the web and ways to
make that better as well.
Then we're going to look at ways
that Safari promotes
your website
and your website's content.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and your website's content.
Learn how to make
that even better.
And finally we're going
to look at your website
and how we can make
your website consistent
across devices whether the
user's viewing it on an iPhone
or on a Mac with a
27-inch cinema display.
That sounds good to you?
Let's get started.
First thing I want to talk
to you about is credentials.
If your app or service
has accounts,
you're defining the credentials
these days for your users
to prove that they are
who they say they are.
Today most credentials
are in the form
of user names, passwords.
And as a matter of fact,
my colleague Andrew
has been working
on a cool new application
on the side.
It's called "Shiny," and this
application has accounts.
What it does is, every single
day that you log into "Shiny,"
it's going to show you a
picture of a shiny object,
but only if you're logged in.
That's very important to him.
Don't understand it but
it's going to be okay.
Something that I realized while
I was beta testing Andrew's app
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
is that my first run
experience with the app wasn't
as good as I wanted it to be.
I started my relationship with
"Shiny" by creating an account
on the "Shiny" website, and
then later I went to the app
for the first time and
I got this login screen,
and I couldn't do anything until
I got past the login screen.
When I run into a situation like
this, I might go ahead and look
up my password in
settings on iOS, or,
if I'm feeling a little
lazy at the moment,
I just might switch back
to using the website
or leave the app altogether.
We don't want people
to leave your apps.
We want engaged, happy users.
So today I'm very happy
to say that we're going
to solve this problem by giving
your application access to some
of the data that Safari has
stored for your website,
the user names and passwords
that are saved for your website.
Safari's technology
for saving user names
and passwords is
called AutoFill.
And I'd like to give
you a little background
on that right now.
First thing that
AutoFill does is
that it fills out forms for you.
Kind of like the forms
that you see when checking
out of the online shopping
site with information
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
out of the online shopping
site with information
from your contacts card.
AutoFill also saves and fills
user names and passwords
to make logging into
your websites a breeze.
And finally, AutoFill
generates passwords for users.
Given the state of website
security these days,
with major websites being
compromised what seems
like every other week,
it's a really good idea
to use a random password
that doesn't overlap
with passwords you're
using on other websites.
And finally with
iCloud Keychain,
AutoFill syncs your passwords
across all of your devices
so that it's a breeze
to log in no matter
which device you're on.
I really love it when my
credentials are syncing
across my devices.
When those credentials
are randomly generated,
I am in a sweet spot of both
security and convenience.
But I've already
mentioned one place
that the system breaks down.
And that's when your
application enters the picture.
When a user hits an apps login
screen anything can happen.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
When a user hits an apps login
screen anything can happen.
They might look up
their password.
They might already know it.
They might decide
to leave your app.
So what we want to do today
is take this failure point
and turn it into
something awesome,
letting your applications
leverage the security
and convenience of iCloud
Keychain and Safari AutoFill.
For your users, it's
going to mean going
from seeing an application login
screen that looks like this
to seeing a simple picker
where they can securely
and easily hand credentials
back to your application
that you can use to
attempt the login.
No typing required.
To get into the details
of how this works,
I'm excited to invite my
colleague Andrew Whalley
to the stage.
Andrew.
[ Applause ]
>> Andrew: Thank you, Ricky.
Yes. I'm Andrew Whalley from
Core OS Security Engineering,
and maybe predictably
for a security engineer,
I'm going to start off by
talking about password security.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm going to start off by
talking about password security.
Passwords are some of the most
sensitive and important data
that we have on any
of our devices.
Passwords to banking websites
have access to all our money,
and passwords to even
something like social media -
well that's really our
entire online reputation.
So we've really got
to protect them.
As we visit websites in Safari
and let Safari save user names
and passwords for us,
it's keeping track
of which websites they
came from to make sure
that they are only ever filled
back to the exact same website.
This security and
actually privacy
as well guarantee is
provided by Safari itself
since it has all the
necessary information
about which credentials
went with which website.
And I'm using credentials here
to mean a user name
and password pair.
I'm sure like me
you have hundreds
of native iOS applications
installed.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of native iOS applications
installed.
And these are all run
and managed by iOS.
So what we need to do is
provide a way to let iOS know
that a particular
app is associated
with a particular website
and to do so in a secure way.
So I'm going to be
talking about a way
to associate your
app and your website.
And it's really quite easy.
It involves adding one
file to your website
and one new entitlement
to your app.
Once you've done that,
then you've got access
to a few simple APIs,
which allows you to see
if your user has anything
saved in Safari, and if so,
gets the user name and password.
And to let Safari know if a
user has created an account
or changed their password
within your application.
So really what we're doing
is trying to make sure
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So really what we're doing
is trying to make sure
that the website
developer and the owner
of the website are really OK
with their two entities
sharing information.
Luckily we can use
cryptography for this subject.
My favorite, favorite subject.
Every iOS developer has a
key and a certificate issued
through the developer portal
or now automatically by Xcode.
Every website has or
really should have a key
and certificate issued
by a CA which they use
to secure HTTPS TLS websites.
First we're going to look
at the app side of things.
So in the same way that Safari
is maintaining internally a
mapping between a credential
and which website it came from,
you can imagine iOS having
a similar table linking apps
and websites and whether
they have been approved
to share information
between them.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to share information
between them.
You can see here that
two have been mapped
as approved, and one is pending.
So let's look and see
what it takes to go
from pending to approved.
Whenever your app is
installed, it gives iOS a list
of all the domains it
wishes to share with.
iOS then appends
apple-app-site-association
to the end to form a URL and
request it from the server.
The server then responds
with a signed file listing
all the applications
that it wants to share with.
iOS then verifies that signature
and check the two
app names match.
Once that's occurred,
we know the app name
and the website name and we
can go complete our table
and marked it as approved.
So that's the flow.
Let's go into a little
more detail.
I mention that apps
include a list of domains.
They're included in
the app's entitlements.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
They're included in
the app's entitlements.
An entitlement is a signed
key value that's included
with every application.
It's signed so iOS knows the
developer really intended
to include that information.
Anything that's added or
removed breaks the signature,
and code signing
won't let it run.
Whether you know it or not,
your application already
includes the entitlement
application-identifier.
It's added automatically
by Xcode.
And its value is in the form
of teamid.bundle-identifier,
and it looks something
like this.
Of the two parts, the team ID
is a unique ten character string
that's issued to every
developer, and you can look it
up on the developer portal.
The bundle-identifier part
you actually specify yourself
from within Xcode in the
general identity section.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
from within Xcode in the
general identity section.
Together the team ID
and bundle-identifier create an
application-identifier that's
unique for everything
single iOS app out there,
so we can specify we
really want that one.
Today in iOS 8, we're
announcing the new
associated-domains entitlement.
Its value has the form of
service:fully.qualified.
domain.name and optionally
a port.
It will look something like this
because for this feature we want
the service of web credentials.
It's easy to add values
to this entitlement.
There's a new section
under the Capabilities tab
of Xcode associated domains.
And actually that's all you
need to set up that association
on the app side of things.
Let's look at what's
needed service side.
As I mentioned, iOS is going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
As I mentioned, iOS is going
to be requesting the
apple-app-site-association file.
But if we just get
that far what's in it?
Well, it's just a
big binary blob,
but inside is a very
simple bit of JSON.
There's a dictionary
which contains a list
of application-identifiers.
In the same way you could
list multiple domains
in your entitlement,
you can list multiple
application-identifiers
in this file,
which allows a really flexible
many-to-many relationship.
The content type returned
by the web server needs
to be application/pkcs7-mime,
which means it's been signed.
The signature is
provided by CMS,
that's the Cryptographic
Message Syntax,
which is the same
format used by S/MIME.
Let's do a quick look at what
it takes to sign the file.
So here's the JSON
you saw a moment ago
but with all the
white space removed,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
but with all the
white space removed,
and I'm saving it
off into json.txt.
Next I'm providing it to open
SSL's S/MIME command and feeding
in the certificate and key
provided by the CA for our site.
This is almost certainly going
to be the same that is used
by a web server, but it doesn't
have to be as long as it's valid
for the site being associated,
in this case, example.com.
The output then is the
apple-app-site-association file
you can copy straight to
your web server for hosting.
And when that's there, that's
everything you need to do.
Except iOS is going to be
making requests of the file
from the web server, and web
servers can return different
codes, so let's have a look
at some of the statuses.
If the file exists and we
get 200 okay, iOS is going
to take the file and
check the service name
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to take the file and
check the service name
and application-identifier match
and the signature is valid.
And if it is, it marks that
app domain pair as approved.
If it gets 200 okay, but
there's a problem with any
of those checks, we go
and mark it as denied.
Likewise in the 300 or 400
range, like 301, 302 Redirect,
or 404 File Not Found, we're
going to go straight ahead
and mark it as denied.
Anything in the 500 range,
like 500 Internal Server Error,
we're going to just assume
there's a temporary glitch
with the web server and retry.
It's worth noting
that this association
and approval state is removed
any time the application is
uninstalled by the user,
which is really useful
if you're developing and
testing and need to go
through this a few
times to get it right.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
through this a few
times to get it right.
So now we've set up
that trust relationship
between our app and our website.
Let's see how we can
integrate prompting
for Safari's saved passwords
into our app's application flow.
Here we are on our home screen.
The "Shiny" app just installed
and waiting to be launched.
Once launched, it's going
to go through this flow.
Because we need a user
name and password to log
on to our back-end
server right away,
the first thing it
does is check to see
if we already have any saved.
They could be saved in the
Keychain as a user name
and password, could be
an auth token or a cookie
that we can use to log in.
Because we've just installed
it there's nothing there,
so we're just going to
have to prompt the user.
Once the user has entered their
credentials, then we're going
to save them for accessing them
next time and then we can log in
and see a wonderful "Shiny"
teapot - tea also another one
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and see a wonderful "Shiny"
teapot - tea also another one
of my favorite things.
So next time we come back
and launch the application,
our check for saved credentials
is going to be successful
and we can log straight in.
Now let's go back to see what
the first user experience flow
is like when we can check the
saved credentials in Safari.
We're just inserting
another step.
Again the app is going to check
if it's saved anything itself,
but if there isn't any, we're
going to be prompted to see
if they have saved
anything in Safari.
If they select their credential
or they select an account,
the user name and password
is going to be returned
to your application which
can then exchange it
for an auth token
and also save it
in the Keychain whatever's
required
by your back-end
server to authenticate.
And then you can
log straight in.
It might be worth noting that
you still need the user name
and password view as a fallback
in case the user hasn't
saved anything with Safari
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in case the user hasn't
saved anything with Safari
or declined to select one.
So that's the flow.
Now let's look at the APIs that
you can use to implement this.
We're introducing three today.
SecRequestSharedWebCredential,
SecAddSharedWebCredential
and SetCreateSharedWeb
CredentialPassword.
The first is what causes the
account picker be displayed.
It has three arguments
and a completion block.
The first allows you
to specify domain name,
the second a user name, if
you already know it somehow,
and then a completion
block, which will be run
after the user has
selected an item,
or it has not been
displayed for some reason.
Now you've already
listed all those domains
in your entitlements and you
have usually no idea what your
user names your users have.
So what you can do
is pass NULL for both
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So what you can do
is pass NULL for both
of those first two fields.
Passing NULL for the domain just
uses the entitlement values.
And passing NULL for the
user name will get anything
that can be found for any of
the domains in the entitlement.
So whenever that code is
executed, we get the picker,
user selects a credential,
and the completion block runs.
Into it is passed a data
structure credential
which contains the user name
and password and maybe an error
if anything's gone wrong.
So let's look at some of the
code you might want to include
in such a completion block.
And it's again pretty
straightforward.
We're just checking
that there was no error,
and a credential was returned.
We extract the user name and
password from the data structure
and pass it off to the method
that our application already had
to log in to the server.
Because this is running in
the block, I'm going to run
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Because this is running in
the block, I'm going to run
that on the main queue just in
case it needs to deal with UI.
Our error condition
down here will run
if the user didn't
select the password
or there's just none there.
And we're going to show the
login UI, which is our fallback,
and again dispatch
that to the main queue.
And that's really all there is.
However your application
might allow a user
to create an account from
within the native application,
and in this case, we need
SecAddSharedWebCredential.
This time you must
specify a domain name
and a user name and
the password.
There's a completion
block, but an error
in this case usually means
there's something amiss
with your app site linking
and the approval process,
so it's more useful
during development.
If there are no existing
accounts in Safari
when you call this, this
completes with no UI.
It just goes straight in.
Which makes it really easy
to include in your flow
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Which makes it really easy
to include in your flow
and make sure those credentials
are just there the next time the
user goes to your website in
Safari and with iCloud Keychain
on any of their devices.
If the user can change their
password within an application,
you make exactly the same call
but just supply the
new password.
In this case with an existing
item, we're going to prompt
to make sure that's
what the user wants.
To delete an account,
you just pass NULL
as the password argument.
Again the user's
going to be prompted.
Note you should only delete this
if they really are
deleting their account.
If they're just logging
out then they're going
to need their credentials next
time they log back in again.
Or maybe you've already
determined
that those credentials are stale
and they would never
work anyway.
So the final API simply returns
a random password each time
it's called.
It's in the same
format used by Safari.
Returning for a moment
to the completion block,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Returning for a moment
to the completion block,
there are a number of errors
that could be returned,
and we'll have a
look at them now.
The first is errSecParam error.
And a description of
"No domain provided."
And what tends to be happening
here is you're passing NULL
as your domain so we're going
to look at the entitlement.
But the entitlement isn't there,
so we get the "no
domain provided" error.
You can also get a
missing entitlement error,
and this means you are
specifying a domain name
but there is no entitlement.
Next you could get a
SecItemNotFound error.
And this means that there
is no proved domain,
which is the saying you get
if there just aren't any,
but you are approved.
We're returning the same error
condition for both of these
as a privacy feature,
which means that rogue
applications are never going
to get any more information
than they really deserve.
So now let's have a
quick demo of putting
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So now let's have a
quick demo of putting
that all into practice.
So first of all let's go
to the "Shiny" website.
But I haven't actually
gotten an account yet,
so I'm going to sign up.
Safari is suggesting to fill
a password, so I'm going
to accept that, and oh, today
Shiny's thing is macaroons.
That's going to go
very well with the tea.
So let's go over to
iOS and have a look
at iOS native "Shiny" app.
Well, here it is.
Going to launch it.
And here we are.
User name and password.
So it was Andrew, and I actually
have no idea what it was,
it came up too quickly.
So let's go back and see
if we can change the
application to fix that.
Here we are in the Log
On View Controller.
And if you scroll down a bit,
we've got the method
loginWithCached
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
we've got the method
loginWithCached
CredentialsIfPossible.
It in turn is calling
loginWithLocalKeychain
CredentialsifPossible.
That takes two blocks.
The first will be passed
the user name and password
if there's one in the Keychain.
And the second is
what's run on failure.
There's no credentials saved.
So I'm going to create a new
method to parallel this one.
LoginWithSafari
CredentialsifPossible.
Again taking a success
block and a failure block.
So this code is very
similar to the one I walked
through in the slides,
but instead of calling
a method directly,
we're calling the success
block and the failure block
if there was an error
or the user declines
to select anything.
So now I'm back in the error
block, the failure block
of our previous method.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of our previous method.
And instead of the back,
fallback being show log
on UI entitlements I'm
going to put a call
to our new method there.
And in this way we have
a cascade of blocks,
so if there's nothing
found in the Keychain,
it calls a failure block.
If there's no Safari
saved credentials,
it calls its failure block,
which falls back
to the login UI.
So let's give this a build
and see what happens.
So we launch it, and
yes, we get a picker.
Log in and there are
today's macaroons.
The app did provide a way
for us to change a password,
and it's already prefilled one
out from the SetCreateSharedWeb
CredentialPassword.
So I'm going to accept that.
That looks reasonably secure.
Change password, and because
I already had something
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Change password, and because
I already had something
in the Keychain,
it's prompted me.
So I'm going to go
ahead and update.
There we are.
Logged straight in.
And now I'll come
back to the Mac.
All being well, yes,
there we go.
iCloud Keychain has done
its magic and the user name
and password - yes iCloud
Keychain has done its magic.
The updated password
is over there.
[ Applause ]
So, though there are
quite a few steps,
none of them are particularly
difficult and it allows - well,
it's maintaining a very,
very high level of security -
this last broken point
in the convenience
and security ecosystem
to be made complete.
Thank you all.
[ Applause ]
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Thanks, Andrew.
I am really excited to see
what you guys are going
to do with these APIs.
It's really a personal pet
peeve of mine to get stopped
in my tracks at a login
screen, and I'm really excited
that if I've gone to Safari,
created an account there,
to never see that again.
SecAddSharedWebCredential,
the API that Andrew told you
about that you'll use to add a
password to the user's Keychain,
update a password in the user's
Keychain or delete something?
It's really neat.
It's not neat just because of
what it's going to mean for all
of us in this room as users.
But because it perfectly
captures your
application's intent.
Your app tells iOS exactly
what it wants to happen
to a user's credentials, and
they're automatically synced
across all of the user's
devices with iCloud Keychain.
It's not as clear cut
on the web however.
Your website doesn't have
a way of saying, "Hey,
Safari I just updated Andrew's
password from Foo to Bar."
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Safari I just updated Andrew's
password from Foo to Bar."
Instead, what Safari does is
it uses a series of heuristics
in order to figure out
what your website's doing
and then update your user's
passwords accordingly.
And to make this all
work, Safari needs
to understand your
websites' forms.
So here's a flow diagram
of how conceptually a password
manager could be looking
at your websites.
Users move between states
like not having an account,
registering for an
account, having the account
and logging in and out of it.
Safari does all of
this automatically.
There's nothing that
you have to do.
There's no opt in for Safari
analyzing your website
and offering password
features to its users.
Because this is automatic
and it's using heuristics,
things can go wrong.
Heuristics aren't perfect.
And when things do go wrong,
Continuity breaks
down for your users.
For instance, if Safari
didn't have a password saved
for your website when you call
SecRequestShared WebCredential
from within your iOS
app, you're going
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
from within your iOS
app, you're going
to get back an empty array.
And if Safari didn't notice
that a user had changed
their password on your site,
if Safari didn't understand
that that happened,
when you call SecRequestShared
WebCredential you're going
to get back a stale credential,
and your users aren't going
to be logged in effortlessly.
Because of this, it's in
everyone's best interest
to test their websites
with Safari AutoFill.
Fortunately, it's really
straightforward to do this.
All you have to do
is pretend to be one
of your users for a few minutes.
So let's go back to
the state diagram.
The first thing you're
going to want
to do is get yourself a clean
device or a clean user account
because you don't
want to interfere
with whatever credentials
you personally have stored
for the websites
that you're building.
And then the first
thing that you're going
to do is create an account
just like your users would.
Go to your account - website's
account creation forms
and sign up.
The two things that
you're looking
for here are the Safari offer
to generate a random credential
for the user, a random password,
and then after you've
created the account,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and then after you've
created the account,
Safari's saved the
user name and password.
And the way that you're going to
check this is by on OS X opening
up Safari's preferences and
going to the Passwords pane,
and on iOS, you'll open Settings
and go to the Safari section,
and you'll have to find
a list of passwords
and user names that
have been saved.
All right.
Now you have an account.
So now that you have an
account and you're logged in,
the first thing you're
going to do is log out
and then try to log
back in again.
And when you go to your
website's login page,
the thing that you're
looking for is
that Safari prefilled
the credentials
so that the user doesn't
have to type them in.
All right.
We've done that.
Next up, the user's going
to change their passwords
at some point during their
relationship with your website.
So you're going to want to do
that when you're logged in.
Go to your Change Password
form, and while you're there,
make sure that Safari offered
to generate a credential
for your users and that
it saved the updated
credential appropriately.
Go back to that list
and make sure
that the new credential
is saved.
And then finally if your
website offers a way for users
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And then finally if your
website offers a way for users
to change their passwords
when they have forgotten them,
go ahead and check that too.
Make sure that Safari
saves a good credential.
And then finally, to simulate
a user having started their
relationship with your website
outside of Safari's watch,
delete the credentials that
you've created for this website.
Go into Settings.
Go into Safari's
Preferences, delete them.
Then go back to your login
page, manually enter them
and make sure that Safari
saved them at that point,
so that your users have
a great experience.
All right.
Testing's over.
Hopefully everything worked
perfectly, but if it didn't,
I'm happy to say that we have
two new strategies to tell you
about today that you
can put into place
on your website's forms to
help Safari understand your
website better.
The first one is the
about declaring your
forms' intentions.
New in Safari 8 on Yosemite
and Safari on iOS 8,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
New in Safari 8 on Yosemite
and Safari on iOS 8,
Safari supports three new values
for the autocomplete attribute.
User name, current-password
and new-password.
These are a relatively
recent addition
to the HTML specification, and
they're really easy to use.
Just label your user
name fields as user name,
any field that's asking for
the user's current password
is current-password.
And you guessed it, a new
password is new-password.
So let's walk through
a few examples of this.
Here's a standard login form.
You're probably asking for the
user's user name and password.
Go ahead, label them,
input type "text."
User name autocomplete
is "user name,"
and label the password
field current-password.
On whatever form
users create accounts.
It's pretty similar.
Just label the fields as
user name and new-password,
and Safari's going to understand
your forms a little bit better
and be sure to offer password
generation for your users.
If you want your users to
confirm their passwords
to make sure they entered
them the right way both times,
that's fine.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that's fine.
Just go ahead and label
both your password field
and your confirm password
field as new-password
and Safari's going to
understand that better as well.
And then now changing passwords.
That's fine.
You're going to want to know the
user's current password to prove
that they are who
they say they are.
And you're going to
want a new password
because that's the point.
Just use current-password
and new-password.
Something that you might
notice about this slide is
that I'm specifically outputting
the current user's user name
within the form.
This is a really good idea
because what this does
is it tells Safari
which user is having
their password updated.
This is really important if
users have more than one account
on your site, but it's just
a good idea in general.
Now if your design doesn't
accommodate this sort of thing,
putting the user name out
in plain text read only
like this, don't worry about it.
Just change the input from
type "text" to type "hidden."
Your users aren't going
to see it, but Safari is,
and Safari is going to
understand your forms better
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and Safari is going to
understand your forms better
and do a better job insuring
continuity with respect
to your users' credentials.
And then finally, the
forgotten password case.
In this case you might want
to know their user name,
same thing as before.
Same caveat.
You can hide it, and this time
all you want is a new password,
so label it that way.
These three new values add to
an already long list of values
that you can use with the
autocomplete attribute
to help Safari understand
your forms
and your intentions better.
So for instance if you
have an input element
and you label it
autocomplete phone,
when the user uses AutoFill to
fill out the form, you're going
to be saying "hey Safari
when you're AutoFilling this,
please put the phone
number here -
please don't put anything else,"
and Safari's going
to do it right.
Okie doke.
That was the first
technique I want to tell you
about to make Safari
understand your forms better,
and it's pretty universally
applicable.
I mean you can use it on
any website that has forms.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The second technique
I want to tell you
about is a little
more specialized.
Specialized because it has
to do with a certain type
of web application, and that's
the kind of web application
that loads content dynamically
via XHR and using JavaScript.
You know these pages.
They don't do a full page
refresh when you click
on a link; everything
just snaps in instantly.
These pages are great for users.
This dynamism is awesome.
But it's that same
kind of dynamism,
no full page transition, that
makes it a little bit harder
for Safari to understand
that one of these transitions
in the password state
diagram had happened.
Fortunately, using
some of the same APIs
that you're probably
already using
to build these web applications,
those APIs are going
to tell Safari that something
interesting had happened
with the users' credentials.
What we're talking about is
history and history's pushState
and replaceState methods.
What you do with these
is you contribute
to the browser's back-forward
list, so if I'm a user
on your site and I
click three links
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
when I hit the back button,
if you're not using this,
you go back three
pages, not a single page.
If you're using pushState,
you're adding state
to the back-forward list and
you only go back one page.
Specifically, pushState and
replaceState take a data object
which represents the current
state of your web application.
This is what you're going
to get back when you listen
for the PopStateEvent.
When the user hits the Back
button, that event will fire,
and you'll go ahead
and re-set up the state
as if the user had just hit Back
and loaded a whole new page.
As a user it's really
easy to think
about the back-forward
list as a left-to-right
or right-to-left
series of pages.
But I want to encourage you to
change your thinking on this.
Really, what the back-forward
list is, is just a stack
of user state, and with
pushState and replaceState,
your dynamic HTML5
JavaScript-driven XHR never
reload awesome web application
can go ahead and add to it.
So the next time that a user
is on your dynamic website
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So the next time that a user
is on your dynamic website
and they go to change
their password,
just call pushState once the
password change has succeeded.
This way, Safari
is going to know
that it's a really
good time to prompt
about saving an updated
password, saying:
"It looks like you just
changed your password.
Are you sure you
want to do this?"
And remember, the history API
and everything I just showed
you really only comes into play
if you're building
one of those dynamic
JavaScript-driven applications.
If when you click on a link
or do something else a
full page reload happens,
you don't have to
worry about this.
So, by testing your website
with Safari AutoFill,
finding any problems,
and trying to fix them
with the two new techniques that
I told you about, you're going
to do a better job insuring
continuity with respect
to a user's credentials.
Their passwords will
automatically fill,
and they'll be logged in on
all their devices in Safari.
And your iOS applications will
have access to great passwords
in
SecRequestSharedWebCredential.
But if these two
techniques don't solve all
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But if these two
techniques don't solve all
of your problems, what I'm going
to do is encourage you
to please file a bug.
If you file a bug,
we might be able
to give you a workaround
for your problem.
And regardless of whether we
can give you a workaround,
your real world test case, your
problem, is exactly what we need
to make Safari's
heuristics better.
Real world test cases
make everything better
for everyone, so
please file bugs.
I promise that we'll use them.
So that was AutoFill and
ensuring continuity with respect
to your users' credentials.
The next thing I want to
tell you about is ways
that Safari promotes
your website.
As of iOS 7, a Safari user's
start page is a nice friendly
easily tappable list of a
user's handpicked favorites.
And on iOS 8, we've augmented
that view to contain a few sites
that the users visited
frequently.
And Safari 8 and
OS X Yosemite share
that same start page design.
The quality of the icon
for your website that shows
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The quality of the icon
for your website that shows
up here can make
a huge difference.
It's a first impression, and
it can make all the difference
between a user promoting
a frequently visited site
to a favorite or
removing it outright.
And I bet that you
and your teams sweat
over your applications
icons on iOS
for what you submit
to the App Store.
And it's time to do the same
exact thing for your website.
So let's get into
the details of how
to specify these kinds of icons.
First up, Favicon.
Your website probably
has a favicon.
It shows up in the
address bar next
to a website address on OS X.
Websites have been specifying
favicons for a long time.
It's really easy.
A little bit of markup in
your pages head section,
or a standard path on
your file on a server,
and Safari's going
to fetch that.
But for the start
page on iOS and OS X,
what you're really going to want
to specify is what's
called an apple-touch-icon.
You might already
be specifying this
because this is the
icon that's used
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
because this is the
icon that's used
when a user adds your website
to their home screen on iOS.
It's really easy to do this.
A simple link tag inside
of the head section,
and you can even
specify multiple of these
with different sizes
so that an application
like Safari only downloads
the one that it needs.
Downloads the lowest
resolution one possible,
conserving bandwidth
for your users.
For information on the sizing,
I'm going to encourage you
to check out "Configuring
Web Applications"
on the Safari Web Content Guide.
So the reason that we're
using Apple Touch Icons
for the start page is because
there are already a ton of them
out there and they're
already the right resolution
to be shown an a Mac
and an iOS device.
Don't let the part
where there's touch
in Apple Touch Icon
weird you out with OS X.
Just think of this as
your website's icon.
And about the icon itself,
use every single pixel
in a square canvas
available to you.
Safari is going to show
all of those pixels,
and if a user goes ahead
and adds your website
to their home screen
on iOS, where you know
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to their home screen
on iOS, where you know
that icons are rounded off, iOS
is going to handle that for you
so there's no need for
you to mask the image.
We don't want to have
mismatched corner-radii.
And finally now that Safari on
OS X is using Apple Touch icons,
you're going to want to put
the Apple Touch icon markup
on all of your pages.
Not just the ones that you're
serving to mobile devices.
There's really no cost to doing
this little bit of markup,
and only devices that care
about the icon are going
to go ahead and download them.
All right.
So that's icons.
The first impression of
how your website is seen
by users in Safari.
Let's talk about other ways that
Safari promotes your content.
Safari today is more than just a
way that people browse the web.
Safari users add pages to
read later using Reading List.
They ask Safari to clean up
articles for them to read later
or right now using
Safari Reader.
And on OS X Mavericks and iOS 7,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And on OS X Mavericks and iOS 7,
a feature called Shared Links
lets the user find articles
to read, find other
stuff that's interesting
that were shared
on social networks.
Well, new to Safari 8 on
OS X Yosemite and iOS 8,
your website can
participate in shared links.
This works, as you might expect,
using your website's RSS feed.
So as soon as the user chooses
Subscribe and Shared Links
on iOS or OS X, Safari's going
to periodically fetch your feed
and show that content to users.
The content that's shown
in the sidebar is directly
taken from your RSS feeds.
Something to note here is that
you want to serve your RSS feeds
and the markup inside of
your pages head sections
that let browsers detect them to
all devices, even mobile ones.
Safari on an iPhone is just
as capable of participating
in shared links as
Safari on a Mac.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in shared links as
Safari on a Mac.
Let's turn our attention
back to Reading List.
Even if your site
doesn't have a RSS feed,
users can add your content
to their Reading Lists.
And as you might know, many
of you in the audience,
as of iOS 7 your application can
add to a user's Reading List.
It's a piece of cake.
All you have to do is import
the Safari services framework
and call a single method
that takes a URL, a title
and some preview text.
Because you're specifying the
title in the preview text,
you're in complete control.
But hold up.
This situation should sound
a little bit familiar to you.
Yet again it's not always clear
cut on how to express these sort
of concepts on the web.
A page on your website
doesn't have a way of saying,
"When I'm added to Reading
List, use this as my title
and this as my description."
It can't say exactly
that, but there are things
that your web pages can
say that help them out.
So let's look at
an example of this.
Here's some markup taken
from the WebKit blog,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Here's some markup taken
from the WebKit blog,
a recent blog post
about the fourth tier,
LOVM JIT that makes
JavaScript and Safari superfast.
I encourage you to read it.
It's an awesome blog post.
That title doesn't really work
as the title of a user's page
because it has those bread
crumbs, Surfin' Safari archive.
But here using the open
graph metadata standard,
I've put markup on the page that
clearly expresses a good title
and a good description.
It's really simple to use.
And when your website speaks
with intention this strong,
Safari is going to listen.
Because you've expressed
the exact information
that Safari is looking for,
Safari can rely on you rather
than using heuristics
to get the job done.
There are other ways
of specifying the
same sort of data.
Here's some markup
you might be familiar
with if you're a web developer,
meta name, description.
This is one way that you might
be specifying a description
to let's say, search engines
for your pages on your site.
Safari can listen to this, too,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Safari can listen to this, too,
because the concepts are closely
aligned: your site's description
and a Reading List description.
OpenGraph is just
one metadata standard
that you should be
checking out today.
There are a bunch
of them on the web.
And this example with Reading
List and getting better titles
and descriptions
is just one example
of how metadata can
help you out today.
Browsers, search
engines, other websites.
They're all going to find uses
for this metadata in the future
as they display your
content to try
and make it more
attractive to users.
So I encourage you to check
these formats out and think
about adopting a
metadata strategy.
Okie doke.
Checkpoint.
By now, you've added the
simple file to your web server.
You've adopted entitlements
in your iOS application,
and you're ensuring
continuity with respect
to your user's credentials
by making it easy for them
to log in to your app.
You've tested Safari AutoFill.
You've made it work
great on your website.
Your icons are awesome.
Just as good as your app icons.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Just as good as your app icons.
And you've adopted some metadata
so that websites, browsers
and search engines understand
your web content better.
For the rest of our time
together, I want to go
over a few examples of how we
can make your website have a
great experience when
transitioning between devices.
Users viewing your websites
on mobile devices
and desktop devices.
The first example of
this that I want to talk
about is called The
Sticky Mobile Website.
So let me tell you
about a problem
that I just ran into
the other day.
I have this all the time,
but it actually just
happened last week.
My friend was reading an
article on her iPhone,
looked good to her, and she
thought that I might like it
so she sent me a link to it.
I was sitting at my
Mac and I opened it up
and this is what I saw.
I saw the website's mobile
layout stretch up super wide
with lines of text that
are completely unreadable.
On other websites when
I've run into this problem,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I've seen this version of it,
where the content is
constrained to say, 320 points.
This isn't readable either.
So what I was able to do
with this problem was look
at the website's address,
the page that I was on.
And notice that I was on a
mobile specific subdomain
of the site, and by removing
the m dot from the URL,
I can get a version of the
website that looked great
on a desktop with a
nice constrained width.
So some of our users are going
to be able to figure some
of this stuff out, but
they shouldn't have to,
and most of them won't.
So let's get to the
bottom of this problem
and figure out how to fix it.
So here's what I
think what happened.
This is a concept diagram.
It might not be exactly
the same from site to site,
but it's the big picture.
And what happened here is
that the user, my friend,
went to a link on her iPhone,
and when she went to example.com
in this case, the website
said, "Hey, I can tell you're
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
in this case, the website
said, "Hey, I can tell you're
on an iPhone from your
user agent string.
I'm going to send you to a
mobile version of the site
because I think that's
better for you."
And then she sent me a link to
that mobile version of the site,
and I went straight
to that mobile site.
It didn't have the kind of
same courtesy to route me back
up to the desktop
version of the site.
And now with Handoff on
OS X Yosemite and iOS 8,
it only takes one person
to reproduce this problem.
You don't need friends
sending links to each other.
So there's even more
reason than ever before
to get your URL strategy
together.
The solution in this case,
I alluded to it earlier,
is pretty simple.
Let the mobile website
route users back
to the desktop website,
giving me the version
of the website that's
appropriate
on my 27-inch cinema display.
So this would have solved
my immediate problem,
but there is a much
better solution to be had.
And that comes by
admitting that the time
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And that comes by
admitting that the time
of the mobile website is over.
Using technologies like
Responsive Design and Layout,
HTML 5, CSS, you can make
one version of your website
that looks awesome for all
of your users whether they're
on an iPhone, an iPad or a Mac.
I'm happy to say that
we have a full session
on Responsive Design this year,
and you should check it out.
It's Friday morning.
And if you're interested in this
and you have a mobile website,
you're going to want
to go to that.
Okay. One more topic
to talk about.
And that's video.
Since the dawn of iPhone,
users have been grading -
getting amazing video
on their iOS devices.
And that amazing video has been
coming to them without the use
of any browser plug-ins,
using standards based video.
And because of this, users have
been getting excellent battery
life and smooth video
playback even
on relatively low-powered
devices.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
on relatively low-powered
devices.
For a consistent
unbroken experience
for how users get
video on your site,
you should use the same
video strategy on OS X.
It works just as well there.
Give users better battery
life and smooth playback.
And if the reason that maybe
you might be avoiding losing the
plug-ins on the desktop is
because of maybe
pre-rolled advertising
of some other interactive
component, you can do that today
with JavaScript HTML and video.
It's really simple.
For more information on
Advanced Media for the Web,
you should check out -
actually you should have checked
out this session this
morning at 11:30.
Go back and watch the
video if you weren't there.
Okay. So in the last 50 minutes,
we've covered quite a bit.
And all of it has been about
ensuring continuity: unbroken,
consistent experiences
for all of our users,
whether they're using
our products and services
with an app, with a
website and no matter
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with an app, with a
website and no matter
which device they're on.
And so to recap, here's
what I want you all
to go out and do today.
First things first.
Put the signed JSON file on your
server, add the entitlements
to your application, and
call the APIs to make sure
that nobody in this room
ever sees a login screen
on an iOS app when they created
their account on the website
in Safari and Safari
has credentials.
The next thing to make
sure that those credentials
that you're getting back
from the
SecRequestSharedWebCredential
are always up to date, test your
website with Safari AutoFill.
Everything might work
great, but you should run
into the problems before your
users do, if there are any.
And if there are, look
at the two techniques
that I told you about today.
No matter what kind
of website you have,
you should adopt the
AutoComplete attribute
and use user name, current
password, and new password
to make it easier for Safari
to do the right thing
with your forms.
It might only take five minutes,
and it will make a huge
difference for your users.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Then sweat the details on
your application's icons.
Make your website's icons look
as great as that of your apps.
And then look at metadata.
Find ways to make web
browsers, search engines
and other websites
understand your content better
for when they're
showing it to users.
And then think about your
desktop and mobile websites.
If you have two different
versions
of your website,
try to have one.
If you want more information
on any of this, I encourage you
to get in touch with Evangelism,
DTS or the Support Forums.
And we've got some really cool
related sessions this year,
some of which I pointed
out earlier.
"Advanced Media for the Web,"
Touch ID and the Keychain,
Adopting Handoff to make
these smooth transitions,
just like you saw
with Craig and Mel,
and Designing Responsive
Websites.
Thank you so much everybody.
I hope you're having
an awesome WWDC.
[ Applause ]