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?
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;
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
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/
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");
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.
Related
I'd like to know the mechanism for storing a secret key on a mobile application for session authentication. I have a Tornado webserver that will use third party external services to authenticate users with E.g. Facebook or Google. I'm familiar with storing cookies using the set_secure_cookie when using a browser. However what if a mobile application is now connecting and doing the authentication. What mechanism would I use to store a secret like a secure cookie for future session authentication? The below shows the code for validating a user:
class GoogleOAuth2LoginHandler(tornado.web.RequestHandler,
tornado.auth.GoogleOAuth2Mixin):
async def get(self):
if self.get_argument('code', False):
user = await self.get_authenticated_user(
redirect_uri='http://your.site.com/auth/google',
code=self.get_argument('code'))
# Save the user with e.g. set_secure_cookie
else:
await self.authorize_redirect(
redirect_uri='http://your.site.com/auth/google',
client_id=self.settings['google_oauth']['key'],
scope=['profile', 'email'],
response_type='code',
extra_params={'approval_prompt': 'auto'})
How would this be modified for a mobile application that doesn't rely on a browser and cookie support?
In iOS, there is an API in the NSHTTPCookie class where you can save the entire http response string.
The code will be something like below to create a cookie.
if let requestUrl = url {
let httpCookies = HTTPCookie.cookies(withResponseHeaderFields: response.allHeaderFields as! [String : String], for: requestUrl)
}
Then you can save the cookie,
HTTPCookieStorage.shared.setCookies(httpCookie, for: url, mainDocumentURL: url)
You can also access this cookie and set it to the WebView if needed.
I don't know whether it is what you are looking for but you could you use the SharedPreferences system, it is very simple and allows to save locally key-pair values to store any useful information.
With Android you can use the SharedPreferences or the EncryptedSharedPreferences to add an extra security layer…
And with iOS you have roughly the same mechanism called NSUserDefaults that allows as well to store key-pair values, allowing also extra security layers.
I want to encrypt and decrypt with symmetrically with android Keystore KMS. I'm aware with Google cloud KMS, and AWS KMS, but I don't want to handle with that platform.
How to manage this generated Android Keystore private key for both (client, server) sides?
I have created a private key for encrypting and decrypting, but hard to manage for the store and share this key.
I had stored that private key in Private SharedPreferences for reuse but There is one problem is that, this private SharedPreferences is not secured because all can observe this private SharedPreferences file in the rooted device.
Refer this link to get information about generating a private key for Android Keystore.
I'm new with tink, so please help me to out this. if there is a wrong thing in my idea then feel free to give your opinion.
Android Keystore is a client side KMS, you cannot use it on server side.
If you want to use Tink with Android Keystore on Android, please take a look at AndroidKeysetManager. Here's an example:
String masterKeyUri = "android-keystore://my_master_key_id";
AndroidKeysetManager manager = AndroidKeysetManager.Builder()
.withSharedPref(getApplicationContext(), "my_keyset_name", "my_pref_file_name")
.withKeyTemplate(SignatureKeyTemplates.ECDSA_P256)
.withMasterKeyUri(masterKeyUri)
.build();
PublicKeySign signer = PublicKeySignFactory.getPrimitive(manager.getKeysetHandle());
This will read a keyset stored in the my_keyset_name preference of the my_pref_file_name preferences file. If the preference file name is null, it uses the default preferences file.
If the keyset is not found or invalid, and a valid KeyTemplate is set with AndroidKeysetManager.Builder.withKeyTemplate(com.google.crypto.tink.proto.KeyTemplate), a fresh keyset is generated and is written to the my_keyset_name preference of the my_pref_file_name shared preferences file.
On Android M or newer and if a master key URI is set with AndroidKeysetManager.Builder.withMasterKeyUri(java.lang.String), the keyset is encrypted with a master key generated and stored in Android Keystore. When Tink cannot decrypt the keyset it would assume that it is not encrypted.
The master key URI must start with android-keystore://. If the master key doesn't exist, a fresh one is generated. Usage of Android Keystore can be disabled with AndroidKeysetManager.Builder.doNotUseKeystore().
On Android L or older, or when the master key URI is not set, the keyset will be stored in cleartext in private preferences which, thanks to the security of the Android framework, no other apps can read or write.
In Google's OIDC guide, section Exchange code for access token and ID token states that I must provide a client_secret.
If I select the relevant client ID from the API console, I do indeed get a JSON file named client_secret_.... However, none of the fields of the JSON object are named secret or anything similar. (The fields are named client_id, project_id, auth_uri, token_uri, auth_provider_x509_cert_url, and redirect_uris.)
So, where do I get this client_secret?
I think the secrete used to be in the file but alternatively you can also find it by looking at the page were you downloaded your json file and you can also click the button to reset said secret.
I would make sure that the credentials are looking at are under OAuth 2.0 client IDs and not Service account keys or API keys only the first one needs a secret I believe.
Update from comments: Creating Oauth Client Id for android will not give you a secret because its not needed in android application should should probably be following Add google sign-in to your android App
The app uses Google Cloud Messaging and contains a google-services.json file which itself contains Google API authentication info, including the API key. GCM functions as expected.
The app contains a testing facility that sends a GCM message using HTTP, and it needs the API key. How do I access that key, the one stored in google-services.json? I do not want to use GoogleCloudMessaging to send the messages (I'm using OkHttp and it does the job nicely).
Hopefully it is not necessary to duplicate it in the app.
Sorry, a bit late to the game here...
The google-services.json file gets parsed and its values get added to an xml which you have access to:
https://developers.google.com/android/guides/google-services-plugin
In your case, you could get the api key with:
activity.getResources().getString(R.string.google_api_key);
You can just get the API key off your GoogleCloud platform then go to credentials and you can grab your API key off of there.
https://console.developers.google.com/
Is that what your looking for?
But if you need to access it (which is should never change unless your change the json file itself) Then you could just parse the json file with a parser. But thats adding more work than needed. I would just copy and paste it from the web.
Ok I see what you going for try using this and using the NSDefualts
Store the token like this:
if (registrationToken != nil) {
self.registrationToken = registrationToken
print("Registration Token: \(registrationToken)")
//store the registation token for use in the postData function in the login page
self.loginInformation.setObject(self.registrationToken, forKey: "GCMToken")
let userInfo = ["registrationToken": registrationToken]
And retrieve it anywhere in the project like this:
myNoteGCMID = loginInformation.objectForKey("GCMToken") as! String
Then if it changes you don't have to change it in but just one place. The change will occur everywhere you call it.
How i can store my password (string) in titanium application?
Is titanium have analog for android secret key, for example?
(i need it only for android)
Thanks!
iOS (and Mac) has a mechanism for storing passwords and things like that securely called the Keychain. With Titanium, there is a module that supports this API called securely.
Once you have securely installed, it is a simple matter to save the password at this point:
var securely = require('bencoding.securely');
//You can provide optional identifier, if none provided securely uses your bundle id
// This wraps the Keychain functions
var SecureProperties = securely.createProperties({
identifier:"Foo",
accessGroup:"Bar"
});
// Now add it to the properties
SecureProperties.setString('Password', the_password_var);
// Get it back
var MyPassword = SecureProperties.getString("password");
Have you checked the FileSystem of Titanium. You can use Properties to store data
Have you tried using this
Titanium.App.Properties.setString("password","P#ssw0rD");
var MyPassword = Titanium.App.Properties.getString("password");
Please check this also