Ways to store Client ID and Secret securely for automated executions in Google Scripts - api

I'm writing a Google Script that will call an external API and pull the resulting data into a Google Sheet. The API requires a Client ID and Secret value for authorization, and I need to keep those values secure. I would also like to trigger the script to run periodically (basically, I'm trying to automate the updating of this sheet as much as possible).
I'm no data security expert, but keeping the Client ID and Secret hardcoded seems like a terrible idea. Most of the search results I've found recommend using the Properties Service to store those values, but in order to set those properties I'd have to hardcode them in the same script, correct? If so, that doesn't solve the security problem.
Other recommendations involve prompting the user to enter the credentials to authorize each run of the script. This solves the security requirement, but I want this process to be as automatic as possible. If I'm opening the script and providing my credentials each time it runs, then I may as well skip the triggered executions.
Are there any other solutions? For context, I am the only person who needs to access this script and no one else should be able to access the Client ID and Secret.

Since you are the only one who has access to the script (having View access to the spreadsheet doesn't allow users to look at the bound script), hardcoding the Client ID and Secret shouldn't be a problem. Just don't give them Edit access to the spreadsheet.
If you don't want to hard-code the data directly anyway, you have some alternatives:
Using Properties Service:
Use Properties Service, as you mentioned. You could, for example, set the Client ID by running this once (in the legacy IDE, you can set these properties manually too):
function setClientId() {
var props = PropertiesService.getScriptProperties();
props.setProperty('Client ID', '{YOUR_CLIENT_ID}');
}
Once the property was set, you can remove '{YOUR_CLIENT_ID}', or even the whole function, if you don't want to keep it hard-coded. The script could then retrieve the stored property the following way:
function getClientId() {
var props = PropertiesService.getScriptProperties();
return props.getProperty('Client ID');
}
Using library:
Another option could be to store this information in a different script, to be used as a library (see Gain access to a library):
var CLIENT_ID = "YOUR_CLIENT_ID";
var SECRET = "YOUR_SECRET";
And then import this library in your main script (see Add a library to your script project). In the sample below LIBRARY is the library Identifier name:
Code.gs (from main script):
function getData() {
const clientId = LIBRARY.CLIENT_ID;
const secret = LIBRARY.SECRET;
// ...
}
Note:
Please note that, even if you don't hard-code your data directly, anyone who can execute your script can potentially retrieve this data. For example, they could log what's returned by getClientId().
If the script has access to some data, users who can execute the script can access this data too.

Related

Shopify app access token - how to make it more secure?

When store owner installs my app I save access tokens into database for later use. Having access tokens from store is huge security responsibility because anybody with these tokens can modify stores from any domain/address, there is no ip or domain lock.
What method could I use to make this more secure? I was thinking to save tokens offline and then upload it only when needed (in case I need to make some global updates for all stores), then delete it again. In case when merchant access app configuration within admin, I would just save it into session. Is there any better method?
Good question.
I save them in a database as well but I encode them with a separate key from the Shopify App password. That way even if someone have access to the database because of some backdoor entrance he won't be able to use them. That said if someone have access to the code he will be able to figure out how to decrypt it since he will have access to the key.
That said I make sure that each and every request is authenticated before I show any response from the server. Since I'm using NodeJS as the back-end I make sure that there are no global variables that can be accessed or modified from different stores. Everything is neatly scoped in separated functions so that the session is scoped for the current store and no other ones will be able to dirty the other store session.
In addition I make sure that there is a webhook that fires when the client uninstall his app in order to clear my database from any information regrading his store.
I know some people are using sessions for this ( online method ) but they pose other problems that I didn't like so I stuck with a database ( offline ) since that is the quicker way to access the App instead of multiply redirects in order to save the session.
As for proposals I can give you a few tips that I learn on my way while building a few basic Apps. ( I'm not an expert on the subject by any means )
don't rely on any cookies when it comes to sensible information
authenticate every request that comes from the front-end
don't trust the user and validate any input that comes from the front-end
don't over-complicate your setup, while it's good to have high security it's bad if it makes your app slow for the user and you lose customers
look to other ready to use popular solutions that can guide you to the correct path
don't get greedy with the App scopes, only request the scopes that you need for you app
remember to clean up after yourself when it's possible but don't over do it ( too many Apps modify the code of customers and break it only to prevent any way to clean it afterwards ) Example use the ScriptTag API instead of a liquid snippet using the Asset API. If you have to use the Asset API add only the parts that you know that won't break a site. Creating a variable is ok if you are using var if the site supports IE11 creating a variable using const or let is not OK or using vanilla JS is OK but using jQuery without knowing for sure that the site has it installed globally is not OK.
More insights on the matter can be seen here:
https://help.shopify.com/en/api/getting-started/authentication/oauth/api-access-modes
https://community.shopify.com/c/Shopify-APIs-SDKs/Best-way-to-store-shops-that-have-installed-my-app-and-their/m-p/402972

dynamic credential allocation in aa client 11.3.2

I need to use credential for log in to a system in AA for a bot that may run on different machines with a technical user for the system associated to each machine/bot.
Lets say the system is Stackoverflow.
Lets say I have two Virtual Machines,named:VM1, VM2
I name my credentials "Stackoverflow-VM1", "Stackoverflow-VM2" and want the automation to dynamically access those credentials, so that running on VM1 the automation will always use the VM1 credential.
I cannot find out how to use such a machine-dynamic access in AA while this is easy to do in other automation softwares and credential vault seems to be pretty useless without this functionality, especially with the extra concept of lockers...Any help?
Already tried:
1) The credential variables in AA will look like this from the client: $Stackoverflow-VM1(username)$, so i tried to simply write (not using the F2 variable list): $Stackoverflow-$Machine$(username)$ into the Set Text field but that results in the string "$Stackoverflow-VM1(username)$" written into the corresponding text field, which is consistent with the AA documentation:
https://docs.automationanywhere.com/bundle/enterprise-v11.3/page/topics/aae-client/bot-creator/using-variables/credential-variables.html
"Credential variables contained in the Credential Lockers can be seen and accessed only from the Insert Variables window."
2) I tried to create different lockers, where VM1 will only see "Stackoverflow-Locker-VM1" and a corresponding locker for VM2 exists. Now if i could create credentials with the same name but different content in each locker i could easily do this, but i cannot create identically named credentials, since they are aware of each other and not only defined in the context of a locker.
3) This page suggests its not possible: https://apeople.automationanywhere.com/s/question/0D56F00005dy3Ri/can-we-able-to-use-credential-vault-dynamically-?language=en_US
but its a 8 month old thread and possibly it has changed now. Everything suggested in this thread is not possible in terms of scalability.
Thankful for any input,
Thank you.
First thing I would suggest that you should always use F2 to fetch the variable list.
Returning to the question, to me, it seems that you have a system where you want to log in using different devices (bot runners) using different credentials.
It is possible by creating provided credentials values.
When you create an attribute for any credential, there is an option to mark the value as provided. That way, the associated users will get the credential request.
Each user will have to provide their own set of values. The bot can be created using those credentials. At run time, based on the user who is logged in, appropriate values will be fetched.
Disclaimer: I work for Automation Anywhere.

Worklight v6: use multiple JSON stores concurrently in app

Is it possible to use two or more JSON stores in a Worklight app at the same time (without switching back and forth)? When I initialize a second JSON store with a username/password, collections in the "default" JSON store that were initialized properly become inaccessible.
Given that many functions in the JSON store api does not let you specify a target store, I am guessing that using multiple stores concurrently is not possible. If this is true, then how does one address the use case where it is necessary to:
Encrypt sensitive user data, and
Need access to non-sensitive data before user is authenticated.
The username field you pass to init is basically the file name for the store, for example:
WL.JSONStore.init(..., {username: 'store1'})
You will have store1.sqlite on disk, no encryption. If you want to switch to another store simply call:
WL.JSONStore.closeAll()
The closeAll function will kill all database accessors. Then you can start a second store with a password, for example:
WL.JSONStore.init(..., {username: 'store2', password: '123'})
That will create a store2.sqlite file encrypted with 256-bit AES encryption.
If you want to switch back to store1, simply call WL.JSONStore.closeAll() and then WL.JSONStore.init(..., {username: 'store1'}).
Currently you can not access store1 and store2 at the same time. You can open a feature request here.
The .sqlite files are mentioned here if you want to see them on the file system, and a bit of their internal structure is mentioned here. The code snippets above don't show it, but make sure you take into account that most JSONStore API functions are async, read more here.

ExtJs:How to get Session variable

In my Java web application,when a user gets logged in,i store the user name and other details in session as follows,
session.setAttribute("userName",username);
I am using ExtJs4 for UI.How to get the session variables in extJs?
Thanks
I can second #Geronimo approach. You need to get user Id and/or permissions when you authenticate the user. However...
You can't rely just on the username/permissions that you store somewhere in your JS code because it can't be easily spoofed. If you present user with some information that can be different for different levels of access you still need to do server side validation of the user identity.
You can't get session variables off the server web container using javascript only.
I do the same thing (storing userId as a session variable in java). I use Ext.Request to perform an Ajax request to a java servlet to get it (along with other data about the user like permission settings for the webapp to enable or disable features they wouldn't be able to use).
EDIT:
I second sha's answer also, the only reason I pass the authentication information back to the client is for cosmetic reasons - so that user doesn't think he can use a feature in javascript that would be denied by my server side authentication. If he were to spoof the userId or permissions and try to use the feature, the real authentication on the server side would stop him.
I understand that the question has been asked for a long time ago, but despite the large number of views and the absence of an plain answer, I decided to offer this answer:
Assume that the session variable is registered like /index.php?PHPSESSID=9ebca8bd62c830d3e79272b4f585ff8f
In this case, you can get the variable PHPSESSID through JS object "location" and transform it through Ext.Object.fromQueryString()
So:
console.log( Ext.Object.fromQueryString( location.search ) );
will prepare PHPSESSID variable for your needs.

How to integrate atk4 login with existing PHP app

Atk4 has basic login functionality and I could build it out to add user registration, forgotten password link, email verify etc using atk4, tmail templates and so on. But if I want to integrate it with an existing open source application that already provides that functionality, what do I need to do to allow that systems login to be allowed so that atk4 protected pages can be viewed after login on the third party app?
There are four alternatives.
Separate sites, separate domains, separate servers, separate database
The most secure way to do that is by passing secure token from the other system to Agile Toolkit. The token should contain the username and hash of some secret passphrase along with that username $user.":".md5($secret.":".$user)
You can check the argument inside API Class:
$this->auth=$this->add('YourAuth');
if($_GET['login_token'])){
list($user,$token)=explode($_GET['login_token']);
if(!verify_token($token))throw $this->exception('Break-in attempt');
$this->api->auth->login($user);
}
$this->auth->check();
Separate site, domain, but same user access
You would need to build same encryption in Agile Toolkit Auth class. Fortunately you can easily do that, by re-defining encryptPassword
class MyAuth extends SQLAuth {
function encryptPassword($password,$salt=null){
return ....
}
}
If you need different connection to database you can also add:
function init(){
parent::init();
// Ouch, last occurrence of static method use!
$newdb=DBLite::connect(
$this->api->getConfig('user_dsn'));
$this->db=$newdb->dsql();
}
Sharing session - same domain and same computer, but no code access
Agile Toolkit uses the Application's realm as a name. That's the argument you specify to the constructor when you create your app instance inside index.php:
$api=new MyFrontend('myrealm');
You would need to call
session_name('myrealm');
session_start();
Then you need to set the session variable, something like myrealm_MyAuth_info, you can probably get this by dumping contents of $_SESSION from Agile Toolkit. You need to set it to something like array('user'=>'john'), as long as it's not "false" anything is ok.
Sharing computer, domain, session and some code
This is similar to previous approach, but it should be easier to do:
include 'yourapp/atk4/loader.php';
include 'yourapp/lib/Frontend.php';
$api = new Frontend();
$api->auth->login('john');
This assumes that your "Frontend" class properly sets the "auth". If this does not work, some tweaks might be needed, for example you might want to move $auth->check() into initLayout() function, if you are calling it from within API.