Subject: [OAUTH-WG] user-agent flow needs a rewrite

From: Brian Eaton <[email-masked]>
Date: Sat, 10 Jul 2010 20:55:06 -0700

The draft 9 spec has no efficient way for a javascript client to
request a verification code.  The spec creates extra client-to-server
round trips.  There is also some inaccurate description of the
properties of the profile.  The problems are located in section 1.4.2:
http://tools.ietf.org/html/draft-ietf-oauth-v2-09#page-11.

The spec requires that the verification code is always returned on the
query string.  This ends up busting the browser cache and creating an
extra client-to-server round trip.  It basically defeats the purpose
of the user-agent profile entirely.  (If you could afford an extra
client-to-server round trip, you would just use the web server flow.)
To clarify, here's how the flow works in practice:

client web site loads
relay page is loaded from the client web site.  This page is typically
heavily cached.  It is almost always loaded from browser cache; it is
very rarely actually fetched from the server, for performance reasons.
client web site redirects browser to authorization server
authorization server redirects back to relay page, with new data on the fragment
there is no client-to-server round trip*.  the client javascript is
loaded from cache, and parses the fragment data
if necessary, the client javascript uses XMLHttpRequest (XHR) to pass
data up to the web server.  This typically happens in the background,
however, while the user is otherwise interacting with the web
application.

Here's what would happen if someone implemented the spec as written, though:

client web site loads
relay page is loaded from the client web site.  This page is typically
heavily cached.  It is almost always loaded from browser cache; it is
very rarely actually fetched from the server, for performance reasons.
client web site redirects browser to authorization server
authorization server redirects back to relay page, with new data on
the fragment, *plus a verification code on the query string*
*browser fetches new copy of relay page from web server*
*user sits and waits*
*kittens die when users have to wait*

There are also several problems with the description of the flow.
Most of the description seems to be left over from the time when the
flow was spec'ed to only return an access token.  Now that it can
return a verification code, sentences like "does not utilize the
client secret" are no longer true.

The phrase "because the access token is encoded into the redirection
URI, it may be exposed to the end-user and other applications residing
on the computer" is just silly.  That's equally true of the web server
flow.

So basically I think section 1.4.2 needs a rewrite, starting with the
entire justification of the flow.

Here's a brief description of how the flow should work:

client web site loads
client redirects to authorization server with:
   type="user_agent"
   client_id=client identifier
   redirect_uri=absolute URL on client web site
   response_type="code-and-token" or "token"  (The client chooses the
response type based on whether they want long-lived access or
short-lived access to the user's data.  Short-lived: just use
"token".)

authorization server confirms user consent (which might or might not
require user interaction...)
authorization server confirms redirect_uri is associated with the client_id.
authorization server redirects to redirect_uri, with all of the return
parameters on the URL fragment.

Here's my proposed text for section 1.4.2.

The user-agent profile is suitable for client applications residing in
a user-agent, typically implemented in a browser using a scripting
language such as JavaScript.  These clients typically have strict
latency requirements, and must be implemented using a minimum number
of client-to-server calls.  The client may have supporting code
running on a web server.  Authentication of the client-side components
is based on the redirect URI and the user-agent's same-origin policy.
Authentication of the server-side components is based on the client
secret.

Unlike other profiles, the user-agent profile returns data on the
client on the URI fragment.  In addition, the user-agent profile
returns an access token directly on the redirect URI, to reduce the
number of round trips required before the client can use the token.
The client is able to immediately use the token to communicate to
resource servers, using client-side cross-domain communication
techniques such as window.postMessage, jsonp, and iframes.  [Maybe
just mention iframes here, better not to clutter the spec with
references to all of the ways around same-origin...)

Figure 5: this probably needs to change so that it looks more like
Figure 4.  Changes from Figure 4 would be:

Step (C) returns access token and optional verification code

New step (D): client using the access token directly with a resource server.

Old step D becomes step E, but otherwise looks the same.  Except it is optional.

Step E: if this step occurs, refresh token is no longer optional

More normative language (largely based on merging the user-agent
language with the web-server language.)

The user-agent flow illustrated in Figure 5 includes the following steps:

(A) [no change] The clients sends the user-agent to the end-user
authorization endpoint as described in section 3.  The client includes
its client identifier, requested scope, local state, and a redirect
URI to which the authorization server will send the end-user back once
authorization is granted.

(B) [no change]

(C) If the end-user granted access, the authorization server redirects
the user-agent to the redirection URI provided earlier.  The
redirection URI includes the access token, and optional verification
code, in the URI fragment.

(D) The user-agent follows the redirection instructions by loading the
redirection URI.  The redirection URI is typically a heavily cached
web page, so this is unlikely to result in an additional client to
server round trip.

(E) The client code parses the URL fragment to retrieve the access
token and optional authorization code.

(F) The client uses the access token to contact resource servers.

(G) In parallel, the client passes the authorization code to the
client's server side components.

(H) The client's server-side components request an access token and
refresh token from the authorization server by authenticating and
including the authorization code received in the previous step.

(I) The authorization server validates the client credentials and the
authorization code and responds back with the refresh token and access
token.

Rest of the spec doesn't look like it needs to change much.

Section 4.1.1.  "Authorization Code" needs some modifications to make
it clear that the redirect_uri sent to the authorization server MUST
include any fragment included on the original authorization request.

redirect_uri
         REQUIRED.  The redirection URI used in the initial request.
If the client included a URI fragment on the redirect_uri sent to the
authorization server on the authorization request, the client MUST
include the same URI fragment here.

Cheers,
Brian

---

From: Eran Hammer-Lahav <[email-masked]>
Date: Sat, 10 Jul 2010 21:05:01 -0700

There is no user-agent flow anymore. There is a profile (of the generic endpoints described in the rest of the spec). Draft -09 added the ability to get both an authorization code and an access token. Your description makes it sound like draft -09 broke something when it was never proposed that a user-agent will obtain an authorization code. The request was to allow it to obtain both when using a web-based component together with the user-agent.

I am not arguing against your points, just that the premise of your issue is new and was not previously discussed as a requirement (ability of user-agent to obtain authorization codes and use a client secret to get an access token).

EHL

On 7/10/10 8:55 PM, "Brian Eaton" <[email-masked]> wrote:

client web site loads

client web site loads

client web site loads

(B) [no change]

redirect_uri

Cheers,
Brian
_______________________________________________
OAuth mailing list
[email-masked]
https://www.ietf.org/mailman/listinfo/oauth

---

From: Brian Eaton <[email-masked]>
Date: Sat, 10 Jul 2010 21:26:09 -0700

On Sat, Jul 10, 2010 at 9:05 PM, Eran Hammer-Lahav <[email-masked]> wrote:
> There is no user-agent flow anymore.

Yeah.  That's a bug. =(

> The request was to allow it to
> obtain both when using a web-based component together with the user-agent.

Right, this didn't use to be possible, but Brian Ellin asked for this,
and several people agreed it was a good idea.  Unfortunately when that
feature got added, it broke a bunch of other stuff:
- all of the descriptive language about the user-agent flow is inaccurate
- if anyone tries to use the verification code approach with the
user-agent flow, the user-agent flow is no longer efficient

So in the quest to add a new feature, we broke other features.  Plus
we didn't get the new feature right.  This sounds like a normal
software development project. =)

Let me know what you think of the new language I proposed.

Note that this pretty much requires that the "type" parameter return
to the authorization URL.  That's a good thing.  If authorization
servers know about the client environment, they do a better job of
meeting the client's needs.

(Also note that we tried leaving this parameter out of WRAP, and
regretted it afterwards.)

Cheers,
Brian

---

From: Eran Hammer-Lahav <[email-masked]>
Date: Sun, 11 Jul 2010 06:37:25 -0700

The problem with the original 'type' parameter and the flows in general is that they tried to address a specific use case and then got expanded (or overloaded) with other use cases. The user-agent and web-server flows became the foundation of native applications, and there were people discussing using native application techniques for user-agent clients. At the end, the flow names and prose became more confusing than helpful (I'm not talking about the grouping of normative language).

The key here is to figure out what information about the client the server actually needs, what it should obtain during registration, and what it can figure out from other parameters. For example, if a client_id has a matching secret, do you allow it to request an access token directly in the authorization endpoint? If you do, is it going to include the same capabilities as an access token obtained using an authorization code and client authentication? It seems like we need to address these questions head on.

The server can't trust what the client is asking unless the client is authenticated *and* the server can trust that authentication (i.e. Client secret not used in a user-agent). For that, you need to establish some form of trust with the client which in today's world means registration. If you are going to perform registration, that's where you should ask about the nature of the client so you can optimize the user experience and the overall security.

The way I understand the Twitter use case is that the client isn't just a user-agent trying to get both an access token and authorization code (or refresh token), but a more complex client which includes both a user-agent and web-based components, each providing a different functionality, but both using the same, single end-user authorization (i.e. The end-user is asked once).

EHL

On 7/10/10 9:26 PM, "Brian Eaton" <[email-masked]> wrote:

Yeah.  That's a bug. =(

Cheers,
Brian

---

From: Luke Shepard <[email-masked]>
Date: Tue, 13 Jul 2010 08:06:19 +0000

On Jul 11, 2010, at 6:37 AM, Eran Hammer-Lahav wrote:

The server can’t trust what the client is asking unless the client is authenticated *and* the server can trust that authentication (i.e. Client secret not used in a user-agent). For that, you need to establish some form of trust with the client which in today’s world means registration. If you are going to perform registration, that’s where you should ask about the nature of the client so you can optimize the user experience and the overall security.

There are examples of clients that pre-register, but operate in multiple contexts. For example, an app may have both a web and a mobile version, and require different auth flows depending. We have found it useful to be able to specify in the request what type of client is making the request.

I am a big fan of pre-registration but I prefer being explicit in the request about what should be returned.

The way I understand the Twitter use case is that the client isn’t just a user-agent trying to get both an access token and authorization code (or refresh token), but a more complex client which includes both a user-agent and web-based components, each providing a different functionality, but both using the same, single end-user authorization (i.e. The end-user is asked once).

Facebook also really wants this. And we'd like to be able to return the verification code in the fragment.

I just read this bit:

   If the response type is "code_and_token", the authorization server
   adds the "code" and "state" parameters to the redirection URI query
   component and the "access_token", "scope", and "expires_in" to the
   redirection URI fragment using the
   "application/x-www-form-urlencoded" format as defined by

That strikes me as very odd - returning some params in the query, and others in the fragment is just weird. I think the request should specify whether it wants the response in the fragment or query. There are a few ways to do this:

1/ Use a 'type' param, and define the response format along with the type (for instance, user-agent means it's returned in the fragment)
2/ If the user requests either token or code_and_token, then the response comes in the fragment. Else, in the url.
3/ Create another parameter to specify how the response should come.

My preference is for #1, but I know you've tried to wrangle the spec and decided not to - and that seems fine. So then I would prefer #2.

---

From: Eran Hammer-Lahav <[email-masked]>
Date: Tue, 13 Jul 2010 08:32:24 -0700

On 7/13/10 1:06 AM, "Luke Shepard" <[email-masked]> wrote:

>> The server can¹t trust what the client is asking unless the client is
>> authenticated *and* the server can trust that authentication (i.e. Client
>> secret not used in a user-agent). For that, you need to establish some form
>> of trust with the client which in today¹s world means registration. If you
>> are going to perform registration, that¹s where you should ask about the
>> nature of the client so you can optimize the user experience and the overall
>> security.
> 
> There are examples of clients that pre-register, but operate in multiple
> contexts. For example, an app may have both a web and a mobile version, and
> require different auth flows depending. We have found it useful to be able to
> specify in the request what type of client is making the request.

The same client credentials should not be used in two different environment
where the security considerations are fundamentally different. For example,
the same client identifier and secret should not be used by a user-agent and
web-server to exchange an authorization code.

> about what should be returned.

Only when it serves an actual function (i.e. How to return parameters, which
parameters to return). Not for enforcing a security policy (that would be
silly and insecure).

>> The way I understand the Twitter use case is that the client isn¹t just a
>> user-agent trying to get both an access token and authorization code (or
>> refresh token), but a more complex client which includes both a user-agent
>> and web-based components, each providing a different functionality, but both
>> using the same, single end-user authorization (i.e. The end-user is asked
>> once).
> 

How is the client going to exchange this for an access token?

> That strikes me as very odd - returning some params in the query, and others
> in the fragment is just weird. I think the request should specify whether it
> wants the response in the fragment or query. There are a few ways to do this:
> 
> 1/ Use a 'type' param, and define the response format along with the type (for
> instance, user-agent means it's returned in the fragment)

I have no problem with a response format request parameter, but I am not
sure what the purpose is (other than making it look less odd :-)). The
current text is based on the assumption that the user-agent is never going
to directly use the authorization code (because that requires it to have
access to the client credentials and if that is the case, it can just use
the web-server profile).

> comes in the fragment. Else, in the url.

This forces the client to make another call to the server (not covered by
the redirection call which is the obvious place to handle this) to hand over
the authorization code. Again, if the client itself is exchanging the code,
what's the point?

> My preference is for #1, but I know you've tried to wrangle the spec and
> decided not to - and that seems fine. So then I would prefer #2.

Any decision made is open for debate.

My takeaway from this is that we clearly don't have a well-understood use
case. My understanding is that at the end of this hybrid mode, the
user-agent ends with one access token, and the web-server ends with another
access token. Neither side sees the access token issues to the other side
(which allows granting different access levels based on the level of client
authentication), and the user-agent never has access to the client
credentials.

EHL

---

From: David Recordon <[email-masked]>
Date: Tue, 13 Jul 2010 09:42:16 -0700

On Tue, Jul 13, 2010 at 1:06 AM, Luke Shepard <[email-masked]> wrote:

> That strikes me as very odd - returning some params in the query, and
> others in the fragment is just weird.
>

I actually think that you want this – albiet odd – combination when
requesting both a code and token. The code and state parameters are needed
by the server and thus are query parameters. The access token, scope, and
expires in shouldn't be sent to the server via HTTP and thus are within
the fragment for the JavaScript to access.

I think the request should specify whether it wants the response in the
> fragment or query.

You can't always put them into the query because you'd be exposing an access
token over HTTP. If you always put them into the fragment then you need to
write JavaScript which passes the code and state down to the server.

---

From: Brian Eaton <[email-masked]>
Date: Tue, 13 Jul 2010 11:17:09 -0700

> the fragment for the JavaScript to access.

The problem is that if you do it this way you end up busting the
browser cache.  All of the performance improvements offered by the
user-agent profile are lost.

Cheers,
Brian

---

From: Eran Hammer-Lahav <[email-masked]>
Date: Tue, 13 Jul 2010 11:39:25 -0700

Isn't that better overall than requiring the browser to make another HTTP request to pass the code over?

EHL

On 7/13/10 11:17 AM, "Brian Eaton" <[email-masked]> wrote:

On Tue, Jul 13, 2010 at 9:42 AM, David Recordon <[email-masked]> wrote:
> I actually think that you want this - albiet odd - combination when

Cheers,
Brian

---

From: Blaine Cook <[email-masked]>
Date: Tue, 13 Jul 2010 19:53:57 +0100

I don't claim to fully grok what the current state of the various
proposals are regarding the user agent flow, but fundamentally,
shouldn't we be aiming to replicate what Twitter and Facebook are
already doing?

We've already moved towards JSON as a standard format, why not go all
the way and mandate either JSONP or CORS support, and explicitly build
around a Javascript-centric model (since that's really what we're
talking about, and that's what is deployed today).

b.

---

From: Brian Eaton <[email-masked]>
Date: Tue, 13 Jul 2010 12:08:00 -0700

> shouldn't we be aiming to replicate what Twitter and Facebook are

Yes.  They are passing all variable parameter on URL fragments.

Other types of cross-domain messaging (e.g. window.postMessage) aren't
widely deployed enough to rely on exclusively.  Yet.  Give it a few
more years.

> talking about, and that's what is deployed today).

jsonp won't work for this use-case, it ends up requiring an extra
client-to-server round trip.

Cheers,
Brian

---

From: Naitik Shah <[email-masked]>
Date: Tue, 13 Jul 2010 13:01:32 -0700

> user-agent profile are lost.

This is one of the key reasons imho. JavaScript can access the query and the
fragment, so it would technically work in either case. But having the
flexibility to choose where it goes saves on one round trip to the client
application. For instance, in the Facebook SDK we would like to do this
background ping, and save the code in a cookie and fire a JavaScript
callback to let the client application know that one is available. The
client application can then decide if it wants to trigger a network request
to send the code to it's servers, or not. By allowing this data to come in
the fragment, we can use a static endpoint (potentially served from a
subdomain that goes to a CDN) and reduce the process to a single server
request in the common case.

-Naitik

---

From: Eran Hammer-Lahav <[email-masked]>
Date: Tue, 13 Jul 2010 14:06:17 -0700

This looks reasonable, however, I am no longer see the value in the hybrid mode of token and code. If the code is passed in the fragment, the client has to pass it to the server. If that is the case, why can't the server reply back with the access token? Is the entire purpose just a performance optimization so the client doesn't have to wait for the server response before it has an access token?

EHL

client web site loads

client web site loads

client web site loads

(B) [no change]

redirect_uri

Cheers,
Brian

---

From: Naitik Shah <[email-masked]>
Date: Tue, 13 Jul 2010 14:27:56 -0700

On Tue, Jul 13, 2010 at 2:06 PM, Eran Hammer-Lahav <[email-masked]>wrote:

>  This looks reasonable, however, I am no longer see the value in the
> hybrid mode of token and code. If the code is passed in the fragment, the
> client has to pass it to the server. If that is the case, why can’t the
> server reply back with the access token? Is the entire purpose just a
> performance optimization so the client doesn’t have to wait for the server
> response before it has an access token?
>
>
I think there are two use cases here, and they are not mutually exclusive.
Some apps are mostly just server side, and would end up doing a full page
refresh, and here the code in the query param would probably be acceptable.
Some apps are mostly just client side, and here the code is irrelevant and
the access token in the fragment is all that matters. But we also have
hybrids where we want the code in a cookie/JS callback, and we'll also use
the access token on the client to dynamically update the UI by accessing
some protected data (this is what the Data enabled XFBML tags do in the
Facebook JS SDK for instance). While the server can do the code to
access_token exchange, it can't return it to the JS safely if it does not
support https. Even if it did, it would mean more overhead for the developer
to build an endpoint that does this work and cooperates with a JS SDK which
wants the access_token for making API calls.

-Naitik

---

From: Eran Hammer-Lahav <[email-masked]>
Date: Tue, 13 Jul 2010 15:00:39 -0700

This is clearly a third flow - hybrid (of user-agent and web-server) - and
not just a variant of the user-agent flow. It should be presented with its
own flow diagram and description. I also think the user-agent and web-server
flow names are misleading. They need to be replaced with more descriptive
names. Something like (I don¹t like these, just trying to demonstrate):

Web-server --> 2 step flow (get code, get token)
User-agent --> direct flow (get token)
Hybrid --> hybrid flow (get code and token, get token)

In an attempt to accommodate Brian's request for more concentrated flow
descriptions, I am working on coming up with come middle ground between -05
and -10.

----

As for the specification of the end-user authorization endpoint:

Please answer this based on actual use cases. When returning parameters
using the redirection URI call, which of these combinations make sense?

         | Code | Token | Code & Token
---------+------+-------+--------------
Fragment |  a   |   1   |   3
Query    |  2   |   b   |   c
Split*   | n/a  |  n/a  |   d

* token in fragment, code in query

Known use cases:

1 - current user-agent flow
2 - current web-server flow
3 - as described by Brian and Naitik

Questionable use cases:

a - 
b -
c - 
d - current -10 code-and-token proposal

EHL

On 7/13/10 2:27 PM, "Naitik Shah" <[email-masked]> wrote:

>> This looks reasonable, however, I am no longer see the value in the hybrid
>> mode of token and code. If the code is passed in the fragment, the client has
>> to pass it to the server. If that is the case, why can¹t the server reply
>> back with the access token? Is the entire purpose just a performance
>> optimization so the client doesn¹t have to wait for the server response
>> before it has an access token?
>> 
> 
> Some apps are mostly just client side, and here the code is irrelevant and the
> access token in the fragment is all that matters. But we also have hybrids
> where we want the code in a cookie/JS callback, and we'll also use the access
> token on the client to dynamically update the UI by accessing some protected
> data (this is what the Data enabled XFBML tags do in the Facebook JS SDK for
> instance). While the server can do the code to access_token exchange, it can't
> return it to the JS safely if it does not support https. Even if it did, it
> would mean more overhead for the developer to build an endpoint that does this
> work and cooperates with a JS SDK which wants the access_token for making API
> calls.
> 
> 
> -Naitik
> 
>

---

From: Brian Eaton <[email-masked]>
Date: Tue, 13 Jul 2010 15:06:23 -0700

> descriptions, I am working on coming up with come middle ground between -05

Thank you!

---

From: Naitik Shah <[email-masked]>
Date: Tue, 13 Jul 2010 22:58:42 -0700

Thanks! That sounds great.

On Tue, Jul 13, 2010 at 3:00 PM, Eran Hammer-Lahav <[email-masked]>wrote:

> hybrid

---

From: Bouiaw <[email-masked]>
Date: Wed, 21 Jul 2010 11:47:56 +0200

Could you explain how the token fragment is removed between step C and
D in the user agent profile ?
I don't understand how the http redirect request can be modified by
the user agent ....