Subject: [OAUTH-WG] Re-creation of Access Token on Single Page Application

From: Tatsuya Karino <[email-masked]>
Date: Fri, 12 Mar 2021 23:24:19 +0900

Hi all,

I'm looking for the specification to generate a new Access Token with
authentication session in a Single Page Application with good User
Experience. There is a draft, OAuth 2.0 Web Message Response Mode
<https://tools.ietf.org/html/draft-sakimura-oauth-wmrm-00>. And it's called
silent authentication on Auth0. When I read the draft, I got a question
about verifying the receiver of an auth code.

The summary of the flow with response_mode=web_message is like this,

+ The client (main window) creates an invisible iframe.

+ An authorize request is sent to authorization server with authentication
session on the cookie.

+ The authorization server checks the authentication session and user
consent .

+ If it is ok, the authorization server returns an auth code with
Javascript code.

+ The auth code is delivered to the client (main window) by Web Message on
the Javascript code.

I understood this specification like that,

Returning auth code to the browser itself is acceptable.

What we want to prevent is sending the auth code to a malicious client.

It is prevented by restricting receiver of auth code by Web Message in this
spec.

It is same for other response_mode.

Then I wonder if it is possible to achieve the situation by CORS settings.

For example like this,

+ The client (SPA) send an authorize request from Javascript with the CORS
settings.

  + Access-Control-Allow-Credentials: true

+ The authorize request is sent with authentication session on the cookie.

+ The authorization server checks the authentication session and user
consent.

+ If it is ok, the authorization server returns a response that includes
auth code with CORS Headers.

  + Access-Control-Allow-Origin: domain specified for each client like
redirect_uri.

  + Access-Control-Allow-Credentials: true

+ The browser checks the origin if the domain is same with that one used
for client application.

  + If the preflight request is happened, this check will be done before
generating auth code.

+ If it is ok, the client receives the auth code.

I feel that the use case is quite small because authorization server and
client have to be provided on the same eTLD+1 at least for the safari. But
the implementation would be very simple, so it could be used if the company
has 1 authorization server and multi clients.

Is there any specification like that? or What kind of security issues are
there in the flow?

Thanks!

-- 
Tatsuya Karino

---

From: Nov Matake <[email-masked]>
Date: Sat, 13 Mar 2021 13:05:29 +0900

Your mechanism seems work fine.

However, do you need OAuth in such situation?
Same-site cookie seems much simpler there.

iPadから送信

> 2021/03/13 0:45、Tatsuya Karino <[email-masked]>のメール:
> 
> 
> Hi all, 
> 
> I'm looking for the specification to generate a new Access Token with authentication session in a Single Page Application with good User Experience. There is a draft, OAuth 2.0 Web Message Response Mode. And it's called silent authentication on Auth0. When I read the draft, I got a question about verifying the receiver of an auth code.
> 
> + An authorize request is sent to authorization server with authentication session on the cookie.
> + The authorization server checks the authentication session and user consent .
> + If it is ok, the authorization server returns an auth code with Javascript code.
> + The auth code is delivered to the client (main window) by Web Message on the Javascript code.
> 
> It is prevented by restricting receiver of auth code by Web Message in this spec.
> + The client (SPA) send an authorize request from Javascript with the CORS settings.
> + The authorization server checks the authentication session and user consent.
> + If it is ok, the authorization server returns a response that includes auth code with CORS Headers.
>   + Access-Control-Allow-Origin: domain specified for each client like redirect_uri.
> + The browser checks the origin if the domain is same with that one used for client application.
>   + If the preflight request is happened, this check will be done before generating auth code.
> I feel that the use case is quite small because authorization server and client have to be provided on the same eTLD+1 at least for the safari. But the implementation would be very simple, so it could be used if the company has 1 authorization server and multi clients.
> 
> Is there any specification like that? or What kind of security issues are there in the flow?
> 
> Thanks!
> 
> -- 
> Tatsuya Karino
> _______________________________________________
> OAuth mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/oauth

---

From: Tatsuya Karino <[email-masked]>
Date: Sat, 13 Mar 2021 15:51:36 +0900

> Same-site cookie seems much simpler there.

yeah, right. For a 1st party application, we don't need to use the
delegation of privilege.

Using Same-site cookies is simple.

But I also think if the company provide their APIs to 3rd party
applications,

it is a little heavy to provide two types of AuthN/AuthZ system (for 1st
party and for 3rd party).

Providing same AuthN/AuthZ system to 1st and 3rd party is more
sophisticated, I think.

But in this case, the feature that can be used only for 1st party (my first
mail example) is not acceptable lol.

By the way, I also wonder what is the better option to use OAuth2.0 on SPA
Client (3rd party) with good UIUX.

In my understanding, there are two options to achieve it.

1. Using response_momde=web_message or 2.Using Refresh Token with fixed
maximum lifetime.

But I have a concern on a practical use.

For 1, Some browser could be restricted to send credential cookie to the
authorization server from iframe.

For 2, The Refresh Token must be saved on the browser, but it could be
deleted on 7days in safari.

Is there any workaround? or Is there any misunderstanding on my concerns?

2021年3月13日(土) 13:05 Nov Matake <[email-masked]>:

> <https://tools.ietf.org/html/draft-sakimura-oauth-wmrm-00>. And it's
> called silent authentication on Auth0. When I read the draft, I got a
> question about verifying the receiver of an auth code.
>

-- 
Tatsuya Karino

---

From: Nov Matake <[email-masked]>
Date: Sat, 13 Mar 2021 17:02:25 +0900

On Safari, you have no workaround.
3rd-party cookie is dead, and all JS-writable data is removed in 7 days there.

What you can do is open popup or call storage access api each time you need new token.

iPadから送信

> 2021/03/13 15:51、Tatsuya Karino <[email-masked]>のメール:
> 
> yeah, right. For a 1st party application, we don't need to use the delegation of privilege.
> But I also think if the company provide their APIs to 3rd party applications, 
> it is a little heavy to provide two types of AuthN/AuthZ system (for 1st party and for 3rd party).
> Providing same AuthN/AuthZ system to 1st and 3rd party is more sophisticated, I think.
> 
> But in this case, the feature that can be used only for 1st party (my first mail example) is not acceptable lol.
> 
> 
> By the way, I also wonder what is the better option to use OAuth2.0 on SPA Client (3rd party) with good UIUX.
> 1. Using response_momde=web_message or 2.Using Refresh Token with fixed maximum lifetime.
> 
> For 1, Some browser could be restricted to send credential cookie to the authorization server from iframe.
> For 2, The Refresh Token must be saved on the browser, but it could be deleted on 7days in safari.
>

---

From: Philippe De Ryck <[email-masked]>
Date: Sat, 13 Mar 2021 09:21:48 +0100

> On 13 Mar 2021, at 07:52, Tatsuya Karino <[email-masked]> wrote:
> 

As you stated, option 1 does not work in cross-site scenarios in Safari & Brave at the moment. Other browsers are likely to follow the same pattern in the future.

Option 2 only works if there are already tokens available, which is typically not the case at first load. Also, keeping long-lived refresh tokens in a browser is not always the best idea.

One workaround goes as follows:
1. When the SPA loads the first time, check if it has token material. If yes, done, if not, go to step 2.
2. Redirect the browser to the authorization server to run a new authorization code flow with PKCE, by setting prompt=none. This will prevent any user interaction and immediately returns either an authz code or an error.
3. The SPA loads again with the autz code/error. If it is a code, it exchanges it for tokens and all is good. If it is an error, the SPA simply shows the unauthenticated state (here, the user can start a new flow with interaction by clicking the login button)

Note that step 2 will include cookies, so it can resume an existing session between the browser and the authorization server. This cookie is always present since a top-level redirect is not a third-party scenario, so third-party cookie blocking does not apply.

Hope this helps

Philippe

---

From: Tatsuya Karino <[email-masked]>
Date: Mon, 15 Mar 2021 11:36:44 +0900

> 3rd-party cookie is dead, and all JS-writable data is removed in 7 days

As you stated, option 1 does not work in cross-site scenarios in Safari &
> Brave at the moment. Other browsers are likely to follow the same pattern
> in the future.
> Option 2 only works if there are already tokens available, which is
> typically not the case at first load. Also, keeping long-lived refresh
> tokens in a browser is not always the best idea.

I see... Thank you. I understood that it is difficult to re-creation Access
Token silently. As reading your workarounds, I felt handling AccessToken
inside SPA is a little difficult.

Generally speaking, preparing Backend Server looks better from a security
and UIUX point of view. If there is a Backend Server for the SPA, we can
use the Backend as a Confidential Client, and create a session and save it
on http only cookie for the SPA. If we have a human resource to do so...

Thank you for your help!

2021年3月13日(土) 17:21 Philippe De Ryck <[email-masked]>:

> As you stated, option 1 does not work in cross-site scenarios in Safari &
> Brave at the moment. Other browsers are likely to follow the same pattern
> in the future.
>
> Option 2 only works if there are already tokens available, which is
> typically not the case at first load. Also, keeping long-lived refresh
> tokens in a browser is not always the best idea.
>
> 2. Redirect the browser to the authorization server to run a new
> authorization code flow with PKCE, by setting prompt=none. This will
> prevent any user interaction and immediately returns either an authz code
> or an error.
> 3. The SPA loads again with the autz code/error. If it is a code, it
> exchanges it for tokens and all is good. If it is an error, the SPA simply
> shows the unauthenticated state (here, the user can start a new flow with
> interaction by clicking the login button)
>
> Note that step 2 will include cookies, so it can resume an existing
> session between the browser and the authorization server. This cookie is
> always present since a top-level redirect is not a third-party scenario, so
> third-party cookie blocking does not apply.
>
> Hope this helps
>
> Philippe
>
>
>

-- 
Tatsuya Karino

---

From: David Waite <[email-masked]>
Date: Sun, 14 Mar 2021 20:48:10 -0600

> On Mar 14, 2021, at 8:36 PM, Tatsuya Karino <[email-masked]> wrote:
> 
> I see... Thank you. I understood that it is difficult to re-creation Access Token silently. As reading your workarounds, I felt handling AccessToken inside SPA is a little difficult.

Refresh tokens wind up being a bit more valuable to bridge the state in the two sandboxes and let you get new access tokens.

The AS policy can also be adjusted potentially to give longer-lived access tokens when the type of access being granted has less security impact if leaked.

> Generally speaking, preparing Backend Server looks better from a security and UIUX point of view. If there is a Backend Server for the SPA, we can use the Backend as a Confidential Client, and create a session and save it on http only cookie for the SPA. If we have a human resource to do so... 

A back-end server only changes access token availability in the case where the AS security policy is that only confidential clients can be issued refresh tokens.

If you use a backend to expose/proxy API requests via a set cookie, remember that you need to protect against CSRF attacks. Some sites use the need for a manually-applied OAuth header as CSRF protection.

-DW