8

I have an Android application that interacts with a WebAPI through OAuth security. For getting the access token, I need to send the OAuth credentials (i.e. client id and client secret) in the header of the request. My question is, where should I keep these 2 values (client id and client secret) for the application to use it when required. Currently, I have just hardcoded it in the call. Is it safe to keep these in the strings.xml file?

Abhinav Nair
  • 958
  • 1
  • 8
  • 29
  • But I need to ship the application with client id and secret. So I have to still write it to the SharedPreference in code. Is that right or did I misunderstand? – Abhinav Nair Mar 31 '16 at 06:11
  • How did you solve this? I also have the client_id and client_secret given to me for the first network call and I can't just "store" them in `SharedPreferences` – jlively May 24 '17 at 09:53

5 Answers5

5

Hidden in BuildConfigs

First, create a file apikey.properties in your root directory with the values for different secret keys:

CONSUMER_KEY=XXXXXXXXXXX

CONSUMER_SECRET=XXXXXXX

To avoid these keys showing up in your repository, make sure to exclude the file from being checked in by adding to your .gitignore file:

apikey.properties

Next, add this section to read from this file in your app/build.gradle file. You'll also create compile-time options that will be generated from this file by using the buildConfigField definition:

def apikeyPropertiesFile = rootProject.file("apikey.properties")
def apikeyProperties = new Properties()
apikeyProperties.load(new FileInputStream(apikeyPropertiesFile))

android {

  defaultConfig {

     // should correspond to key/value pairs inside the file   
    buildConfigField("String", "CONSUMER_KEY", apikeyProperties['CONSUMER_KEY'])
    buildConfigField("String", "CONSUMER_SECRET", apikeyProperties['CONSUMER_SECRET'])
  }
}

You can now access these two fields anywhere within your source code with the BuildConfig object provided by Gradle:

// inside of any of your application's code
String consumerKey = BuildConfig.CONSUMER_KEY;
String consumerSecret = BuildConfig.CONSUMER_SECRET;
Victory
  • 1,184
  • 2
  • 11
  • 30
2

It seems you should be using a different OAuth Flow. As you experinced, Native Apps can't keep secrets. You can read about recommendations for OAuth and native apps here. https://www.rfc-editor.org/rfc/rfc8252

Your probably want to look at Authorization Code Flow with PKCE. Here you accept the fact that a native apps can't keep a secret. You can find a relatively simple explanation of the flow here: https://auth0.com/docs/flows/concepts/auth-code-pkce

As an alternative you can look at dyanmic client registration (https://www.rfc-editor.org/rfc/rfc7591) but it might be overkill for your application. Using dynamic client registration you won't have to hard code the client secret

Community
  • 1
  • 1
Simon
  • 306
  • 1
  • 12
1

If you are concerned about security then you can save the data in SharedPreference by encrypting and saving encryption keys in Android Keystore.

The Keystore is not used directly for storing application secrets such as password, however, it provides a secure container, which can be used by apps to store their private keys, in a way that’s pretty difficult for malicious (unauthorised) users and apps to retrieve.

Here is nice tutorial for creating keystores. http://www.androidauthority.com/use-android-keystore-store-passwords-sensitive-information-623779/

crashOveride
  • 839
  • 6
  • 12
  • 1
    I got that. But my question is, how am I supposed to put the client id and secret in the sharedpreference without writing it in code?. When a user downloads and installs my application, he/she is going to make a network call. For that network call to work, the oauth credentials are required. So that means I need to package the credentials in the app. How do I go about it? – Abhinav Nair Mar 31 '16 at 09:56
  • Aren't you tight coupling the entire architecture if you are saving the oauth initially on the app? The android client should make a initial webcall to server to get the oauth credentials. If you worried about the security of this call, use pushnotification mechanism. register for pushnotitfication and ask the server to send oauth in gcm tickle. GCM tickles are secure as they have app signature check. – crashOveride Mar 31 '16 at 10:33
  • But...if he can get the oauth credentials via webcall, so can everybody else...I'm sorry, but the whole OAuth2 mechanism seems deeply flawed if the goal is to make sure that the client who's requesting data is actually a trusted client. – wickermoon Nov 24 '18 at 19:48
-3

No, it's not safe to keep it in strings.xml. Use SharedPreferences instead. For example:

SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);

and then store your client ID and client secret like this:

sharedPreferences.edit()
.putString("client_id", "your_client_id")
.putString("client_secret", "your_client_secret")
.apply();

To get the client ID and client secret back from SharedPreferences:

String clientId = preferences.getString("client_id", "No ID");
String clientSecret = preferences.getString("client_secret", "No Secret");
  • But I need to ship the application with client id and secret. So I have to still write it to the SharedPreference in code. Is that right or did I misunderstand? – Abhinav Nair Mar 31 '16 at 05:22
  • You should avoid keeping them (especially your secret) in xml files because they can be decompiled by reserve engineering tools such as "apktool". Keeping them in SharedPreferences is a safer method, I think. – Doko Demo Doa Mar 31 '16 at 06:38
  • 1
    I got that. But my question is, how am I supposed to put the client id and secret in the sharedpreference without writing it in code?. When a user downloads and installs my application, he/she is going to make a network call. For that network call to work, the oauth credentials are required. So that means I need to package the credentials in the app. How do I go about it? – Abhinav Nair Mar 31 '16 at 09:54
  • Actually SharedPreferences are stored as XML in your app data folder. You can just store it somewhere, for example, the "Application" class, hardcode it if you would like to. Check this out: http://stackoverflow.com/questions/6146106/where-are-shared-preferences-stored – Doko Demo Doa Apr 04 '16 at 02:49
-6

Please use SharedPreferences to store secure data, because if any one reverse engineer your application, they will get hard coded strings. SharedPreferences is a secure place where you can store data.

superus8r
  • 751
  • 1
  • 11
  • 24
J.D.
  • 1,401
  • 1
  • 12
  • 21
  • 4
    I got that. But my question is, how am I supposed to put the client id and secret in the sharedpreference without writing it in code?. When a user downloads and installs my application, he/she is going to make a network call. For that network call to work, the oauth credentials are required. So that means I need to package the credentials in the app. How do I go about it? – Abhinav Nair Mar 31 '16 at 09:56
  • @AbhinavNair Encrypt your credential and put encrypted text in your code check if app launch first time than decrypt that text and store in shared pref and use that pref for further use. because every time decrypt is no a good solution. – J.D. Mar 31 '16 at 10:29
  • if you don't mind, can you kindly give me some reference links to encrypt and decrypt strings on Andriod? – Abhinav Nair Mar 31 '16 at 13:12
  • @AbhinavNair Do one thing create a new application and through that app encrypt your value and store that value in your app. only implement decrypt function in your code after decode store that value in sharedpref – J.D. Mar 31 '16 at 13:16
  • But...if the decryption method is also in the code and the encrypted value as well then...wouldn't it be easy to reverse engineer for the value and the decryption method? This seems to be some flawed sense of security. So instead of just having to search for the key in the code, the attacker has to search for what looks like an encrypted key, and the method to decrypt it. That doesn't sound secure at all. – wickermoon Nov 24 '18 at 19:51
  • @J.D. Where I store the decryption key ? – Victory Dec 05 '19 at 09:45