9

I'm struggling to decide what to do to get an access token from a mobile app.

I'm sure this has been covered before, but I can't find it.

I've enabled resource owner credentials grant on my oauth2 server. The grant requires client id, secret, and a user's username and password.

If I don't want to store my client secret in my mobile app, is it safe to send ONLY client id and issue an access token if client id value stored in the user record matches the client id sent from a mobile app?

What's the best practice for this use case?

6

There are multiple problems with what you are trying to do...

General Information

OAuth2 in the "traditional" way is not meant to be used on anything other than a webbrowser. This means that if you have a desktop application or a mobile application, you should not use "traditional" OAuth2 for authentication. By "traditional", I mean the one where you get redirected to the provider website to enter your username/password then redirected back with a token that will be used by the client and etc.

Now let's start the explanation... OAuth2 documentation can be a bit confusing at first. What they refer to as a client is what we usually refer to as server when we are developing web application. There is 3 part to OAuth2 :

  1. Service Provider : Google, Facebook, etc.
  2. Client (webserver, desktop application, mobile application communicating with the service provider)
  3. User (the application the physical user is using)

The problem with mobile and desktop application is that the client and the user is the same thing AND they reside on the client machine. Ever heard the saying "there is no security client side"? This pretty much apply here.

Problem 1 : The client secret

You are right to not want to put your client secret in the mobile app because your app can be "decompile" and hacker will retrieve your client secret. Once they have it, they can create their own application and impersonate your app.

Problem 2 : Username / Password

Don't use the "traditional" OAuth2 on a mobile/desktop application. The problem here is how you enter the username/password and how you retrieve the token that the service provider give the user after he logs in. Let's look at possible way to get it "working securely"...

Fail attempt 1 : Ask your user to enter username/password directly through your interface.
Reason for being bad : Congratulation, you just stole the facebook login of all your users.

Fail attempt 2 : Open a browser with the provider page.
Reason for being bad : How do you get the token back from the browser now? There is no way to get it (unless you have a malicious application constantly reading what is in the browser of the user)

Fail attempt 3 : Open a fake browser to lure the user to give you it's log in information.
Reason for being bad : Same at attempt #1. Mobile application can go full screen and control everything you see so you cannot trust them. Desktop application can open new window that could mimic your browser, etc.

The hard fact is that there is no way to make "traditional" OAuth2 work without a secure webbrowser that acts as the "user" and an https webserver that acts as the "client".

OAuth2 was never designed to provide authentication but rather just authorization. There is a big distinction between the two. OAuth2 protocol was "hacked" in order to make it able to provide authentication also (check OpenId). The only problem with this "hack" is that it only works in webbrowser like explained previously.

A real solution

If you still want to continue using OAuth2/OpenID for your login and wanna do it in a secure way, it will be a bit different than what you have imagined. Using OAuth2 for login is still a good idea as it saves your users the trouble of remembering yet another username/password.

  1. You will need a server where your client id and secret will be stored. Your mobile app will connect to this server to send the token.

  2. When ask for log in, redirect the user to the service provider webpage in a browser. Alternatively, the user could go directly to your https website to log in which will again redirect them. The service provider webpage is the only place your should enter your log in information.

  3. Create an https webpage where the user will be able to see the token once he logs in using the service provider.

  4. Ask the user to copy this token into your application. Your application then send the token to your server. The server add the client id and client secret and forward it to the service provider.

Your user can now use their "facebook" login to log into your application and there is no way for your application to steal their log in information or for an hacker to steal your client secret.

Additional Note

The case of phishing attacks and OAuth2 when used outside a web browser is an interesting one as well but that would be the subject of another question.

  • "How do you get the token back from the browser now?" Callback URL in http://localhost:xxxxx origin, or callback URL with some custom scheme part that the app has registered with the OS. – Damian Yerrick Nov 24 '16 at 23:00
  • 1
    @DamianYerrick You manually copy it from the webpage into your application... Frankly, there is no ideal scenario for OAuth2 outside a browser. Either you sacrifice security or usability. – Gudradain Nov 25 '16 at 15:14
  • 1
    I think this answer misses to address the very real usecase when the app (client), api (resource server) and authorization server is developed/managed by the same organization. In that case you don't "steal your users' facebook logins", because you don't have them log in via facebook, but against your own authorization server, with passwords you already have. – Gabor Lengyel Jul 13 '18 at 20:58
-1

I believe there is a relevant conversation here https://stackoverflow.com/questions/19615372/client-secret-in-oauth-2-0 but not really an answer to the issue.

If you're worried about not hard-coding the secret in the App, and therefore issues with recompilation,then one solution may be to use a secondary server to securely store the secret which can be downloaded with a different username/password that you ask the user for i.e. the flow goes:

  1. ask the user to supply username and/or password

  2. use those credentials to log onto a secure service that returns the secret

  3. use the secret as intended (don't store locally!)

It's a lot more work and management, but it does provide a secure solution to the hardcoded secret problem.

  • 1
    But a malicious client can just ping the service to get the password. Now you've gained nothing. The secret is also exposed to debugging filter. – Neil Smithline Oct 6 '15 at 15:30
  • 1
    The client can't ping the service without the username and password entered each time by the user. The security issue isn't with a 'malicious client' but with the fact that someone could decompile the client and read the secret hard coded into it. This scheme doesn't allow that. – David Scholefield Oct 6 '15 at 15:32
  • 1
    But you can watch the network traffic and grab the secret when the client is getting it back from the server. – Neil Smithline Oct 6 '15 at 15:34
  • 1
    A debugging proxy will show you contents of https as well. – Neil Smithline Oct 6 '15 at 16:31
  • 1
    @DavidScholefield Neil is right. If I'm a malicious user, I can enter my valid username/password and retrieve the secret. At this point, the secret is stored on my machine so I can retrieve it in many ways; the proxy is probably the easiest one. Since there is only one client secret, it is game over. – Gudradain Oct 6 '15 at 19:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.