Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Proper OAuth2 flow for public first-party clients

Tags:

I'm a regular reader here at stack overflow but this is my first question.

I'm developing an authorization-server using the OAuth2 specs. And I just got stuck with how do I ensure the first-party client authenticity while using the password flow. I read many forums and this is what I got:

  1. Javascript single-page clients

    This blog post by Alex Bilbie, he states that to avoid the client_secret problem we should just:

    It’s simple; proxy all of your API calls via a thin server side component. This component (let’s just call it a proxy from here on) will authenticate ajax requests from the user’s session. The access and refresh tokens can be stored in an encrypted form in a cookie which only the proxy can decrypt. The application client credentials will also be hardcoded into the proxy so they’re not publicly accessible either.

    But now this proxy can be accessed by someone impersonating my angular app. And then I came across this blog post from Andy Fielder: How Secure is the OAuth2 Resourc Owner Password Flow for Single Page Apps. He basically says to rely on CORS to avoid impersonating JS clients.

    It is a good idea to use both approaches to secure my JS app?

  2. Native Apps (Desktop and Mobile)

    In the case of mobile apps, I only found cases for Authorization Code and Implicit flows. This is not what I want, as the redirects will compromise the user experience. So my thoughts on this is:

    I will use the ROP flow and then register the client with a client_id generated for this particular installation and attach it to the user account, receiving the access_token and a client_secret as response. Any other token request made by this client MUST carry this credentials (as the client_id is specific for the installation, I will be able to check if this client is already authenticated). This way if someone uses any credential for impersonating a client, or even registers a bogus client, I can take mesures to revoke the user and client access.

I know that this can be overthinking, and I also know that some of this matters doesn't avoid anything. I just feel that is my job to protect my API as much as I can.

I would really appreciate your thoughts about this matters! Am I really overthinking? Should I just use the concept of a 'public client' and carry on?

Thank you all and happy coding!

like image 351
Bruno Castro Avatar asked May 13 '16 03:05

Bruno Castro


People also ask

Which OAuth 2.0 Flow should I use?

For most cases, we recommend using the Authorization Code Flow with PKCE because the Access Token is not exposed on the client side, and this flow can return Refresh Tokens. To learn more about how this flow works and how to implement it, see Authorization Code Flow with Proof Key for Code Exchange (PKCE).

What is client credentials flow in OAuth?

The OAuth 2.0 client credentials grant flow permits a web service (confidential client) to use its own credentials, instead of impersonating a user, to authenticate when calling another web service.

What happens during an OAuth2 authentication flow?

The user clicks a login link in the application and enters credentials into a form managed by the app. The application stores the credentials, and passes them to the OAuth authorization server. The authorization server validates credentials and returns the Access Token (and an optional Refresh Token).


1 Answers

First of all, this problem is not a common priority because most applications are developed first with website, and after with the API. This is probably the reason because no one knows how to deal first clients with oauth2, because everyone have developed other ways to do that and oauth2 is needed only to grant user access to third party applications.

Even if you have develop the oauth2 authorization server only for your first clients applications (thinking about a single authentication mechanism instead of developing many), you should try to develop the authorization code or implicit grant types. You will realize that you need a way to check what user is actually logged in.

The two common methods are:

  • user session (based on Cookies)
  • user access from localStorage (based javascript)

In either ways you need to check your application security, user session is vulnerable to CSRF, localStorage are vulnerable to XSS. There are a lot of articles about how to secure your website against either, so I will not suggest anything here, you just need to know that they exist.

Now that you choose your authentication method we can start to do some consideration about:

Javascript single pages applications

  1. Proxy
    Having a proxy that filter all requests in my opinion is like to have a door with the keys always inserted. It's useless even build the door. However, for session based authentication it's the only way to do it. Allowing session authentication on your Rest API will open to CSRF security issues, so you need to have a proxy layer that get the user session, retrieve the access token from the session and do the request to the Rest API adding the Authorization header.

  2. CORS
    With this method you need to store the user access token in the localStorage, because the token is retrieved from the Js client directly.
    Using CORS you are sure that other websites cannot do requests to your Rest API from a browser. But your first client need to be public (ie: it does not have a client_secret).

Native Apps (Desktop and Mobile)

In my first application I tried to use the same mechanism that you suggest to secure the auth flow. However that type of mechanism require that you identify every user client in an unique way. This is not possible in iOS for privacy reasons and with some probability it will denied in the future releases of Android. So you should rely on a public client and add only the client_id in your native application code.

This means that your native app client/your js client can be impersonalized?
Yes, and there is no way to prevent this with oAuth2 resource owner password credentials grant type.

The main reason about this is because oAuth2 is not for authentication, only for third-party authorization, and that grant type was added only for specific third-party applications trusted enought to use directly the user password. You could read more about this argument here and here.

At the end

You still need a way to auhorize your user, and I think that the best you can achieve using oAuth2 is what Auth0 did. Essentially this Saas manage your users with an oAuth2 server + OpenID connect, so you are always managing your users like its a third-party application and everything works fine.

Indeed, you can see on this page that for mobile applications they suggest to use a browser based login form, because the native one can be impersonalized by everyone that decompile your application, but if you wrap it into an authorization code flow it works fine.

like image 134
NeoKree Avatar answered Sep 20 '22 14:09

NeoKree