2
votes

We've got an app, which should use authentification through 3-rd party OAuth 2.0 server, which acts as an authorization server.

As i understand there are two possibilities.

The "right" one is:

  1. Mobile app stores client_id
  2. Mobile app starts with GET /auth to receive authorization_code
  3. Authorization server returns response with redirect to redirect_uri and attached authorization code. We assume, that redirect_uri is an endpoint on our own server.
  4. Mobile app follows redirect
  5. Our server receives request, takes authorization_code from query and exchanges it for access_token using POST /token method and client_secret (stored on server).
  6. Server responses to mobile app with access_token
  7. Mobile app takes access_token and uses it in future requests.

The "bad" one is:

  1. Mobile app stores client_id and client_secret
  2. Mobile app starts with GET /auth to receive authorization_code
  3. Authorization server returns response with redirect to redirect_uri and attached authorization code. We assume, that application intercept it and takes authorization_code (we can simply ask to redirect to localhost).
  4. Mobile app exchanges it for access_token using POST /token method and client_secret.
  5. Mobile app takes access_token and uses it in all future requests.

So i can't see real difference between this two alternatives. In both cases we end up with access token. In both cases we need real user to enter his login and password in rather secure webview.

Even if some bad guys will distribute fake application... what do prohibit them from using our server's callback to exchange authorisation code for access_token? Our server can't distinguish "bad" and "good" application - it just receives request GET \callback?code=blablabla and replies with access_token.

So why should we keep secret on server? What is the case of fraud with faked applications?

2

2 Answers

2
votes

With OAuth you have different flows that you can use according to your needs/setup. Depending of the different flows, the OAuth roles will also behave differently.

From your description I was not entirely sure what will take on the role of the Client. But the options are:

  1. Backend server is the client
  2. Mobile app is the client

For case 1, you don't need to store client ID or client secret on your app, as it will be your own backend server to communicate with the Authorisation Server and the Resource Server. If that is the case, then you can follow the Authorisation Code flow.

For case 2, it will be the app itself that communicates with Authorisation and Resource Server. In this case, the Implicit Flow is the recommended one. It is not considered a safe flow, and mobile devices or webapps are not considered a safe place to store the client secret, as you would have to store them in your app's code, somehow. A (bit convoluted) scenario to explain why this isn't safe is the following: The client secret is issued by the Authorisation Server, or Service Registry, and any hack would require you to change it, which might mean changing the code. And in the case of a mobile app this would mean your users updating to a new version. What seems to be widely suggested as an extra step of security (instead of the client secret) is to use the 'state' or 'nonce' fields to ensure that authorisation requests came from the same app to which the token was issued to. From the RFC section 4.1.1 (http://tools.ietf.org/html/rfc6749#section-4.1.1):

state

     RECOMMENDED.  An opaque value used by the client to maintain
     state between the request and callback.  The authorization
     server includes this value when redirecting the user-agent back
     to the client.  The parameter SHOULD be used for preventing
     cross-site request forgery as described in Section 10.12.

The value to be passed in the state field is up to whoever makes the request. You can generate a random (or pseudo-random) number. The reply that the Authorisation Server sends back will have the state field filled exactly the way it was sent by the Client. You can then match the state field you received with the one you sent to see if they match.

Another step you can take is to have the Client send the redirect URI with the token request. This is useful so that the Authorisation Server can validate if the redirect URI in the request matches the one it has associated with the client ID. If you're using a 3rd party Authorisation Server you should check if it has this behaviour.

As a final security recommendation, always use with HTTPS when communicating with the Authorisation Server or the Resource Server.

This post explains well the different flows of OAuth: https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2

1
votes
We assume, that redirect_uri is an endpoint on our own server.

I believe you are mixing up the role of your client and resource server here. Your resource server (the server hosting your API) should of course never return the token to the mobile app (client) as it needs that token to authenticate the client in the first place.

In OAuth2, the client should acquire a token from the authorization server before communicating with the resource server.

It can use either the implicit grant or the authorization code grant. In the latter case, it should use the grant without providing a client secret as mobile clients are considered public clients that cannot store secrets securely.