Best practice for secrets, like using environmental variables?


#1

If I have items such as secret tokens I need to use, what is the best way in Nativescript to use them but keep them secret?

Normally, this is a use case for environmental variables, such as creating an env file that is outside of GIT, and then referencing those variables in the main code. Is there a way to do this in Nativescript?

I have seen discussion on github about this, like here , but I’m not clear on the current recommended approach.


#2

If you are using webpack, you can pass the environment variables.

https://docs.nativescript.org/performance-optimizations/bundling-with-webpack#nativescript-cli-commands


#3

Thanks, that looks cool. I looked at the link you referenced and then also a webpack description here, and I am almost there.

I am just missing how to connect all the dots to actually use the variable in my component ts code.

Let’s say the secret variable I want to use is “cool_secret123”, and I will use the alias “env_variable”.

In other words, I will use the term “env_variable” in my component code, and the app will know to translate that to “cool_secret”.

Steps:

  1. set up a webpack.config.js file

  2. in webpack.config.js:

module.exports = env => {
  //***WHAT IS THE CODE I NEED TO ENTER HERE TO USE THE VARIABLE ELSEWHERE? The examples I see use console.log() statements--that would not seem to actually transport the variable to other components.***
};
  1. amazingComponent.ts file:
export class amazingComponent {

private token = env_variable

...

useEnvVariable(){
    console.log('here is the environmental variable' + token)
}
  1. and run:
    $ tns build ios --bundle --env.development --env.env_variable = cool_secret123

#4

Hey all. Just following up. I’m not sure of the code that would go into the webpack.config.js file to allow me to use the variable elsewhere. See step 2 above. Any thoughts?

Is there a more straightforward way like there would be in a basic web app, such as just creating an env folder and referencing it with some special magic language elsewhere?


#5

Did you define the same variable in DefinePlugin, something like below

 plugins: [
            new webpack.DefinePlugin({
                "env_variable": JSON.stringify(env_variable) 
            }),

This is more straight forward and recommended way while using webpack for bundling.


#6

Thanks. Does that code go in webpack.config.js?

and then do you exclude webpack.config.js from source control, (ie, putting in .gitignore file)?

The point here is just to have a basic way of keeping stuff like tokens secret.


#7

Yes, it’s in webpack.config.js and it stays in source control.


#8

Do you mean it stays OUT of source control?

(If it stays in source control–meaning it is tracked by git, then what is the point? I could just have the token directly in my code with the same result.)


#9

Yes, it should be added to source control. You are not going to hard code the value in webpack config, but by using webpack config you are letting webpack know that you are going to pass a value from command line which should replace all occurrence of env_variable in actual code.


#10

That makes sense. I’ll give it a try. Thanks.

The code you provided:
webpack.config.js:

plugins: [
            new webpack.DefinePlugin({
                "env_variable": JSON.stringify(env_variable) 
            }),

is the best way to access env_variable in my component ts files?


#11

Depending on your use case, another simple approach might be to use globals. For example set it with global.secret = "xyz"; then just use global.secret in your code where you need to reference it.


#12

Thanks. That might be helpful at least during development. What file do you like to use for globals? app.component.ts?


#13

This follow-up is related to the bundle process for production.

Let’s say I create a separate file, like global_secrets.ts, and store some variables in there that I try to keep secret by keeping them out of git source control. I export those variables to access them in other files. Some details on exporting global variables is here .

This seems like the easiest way of doing environmental variables. However, is it secure for production? When I go to bundle up my app for production in iOS, does that bundling process expose the code in global_secrets.ts to anyone?


#14

UglifyJS makes it hard to read, but you might want to use any obfuscate tool to make it more secure.


#15

I am still not not sure that passing environmental variables through the webpack build is the best way to keep tokens secret.

(What I mean: I haven’t seen webpack discussion about keeping things secret–at least not related to using it in submitting moble apps. So its not clear to me that passing the environmental variables in webpack at build is a secure way to keep the secret variables out of the bundle passed to, say, the app store).

Does anyone have experience keeping things like tokens secret when they submit apps to the app store?

@manojdcoder mentioned an obfuscate tool. Maybe like this ?


#16

Just about got the environmental variables with webpack working, but there is one more piece I am missing: what is the right terminal bundle command?

Same question as on this stack overflow.

There, @NickIliev provided helpful code for accessing environmental variables in webpack (using the code he provided in the stack overflow answer):

webpack.config.js:

new webpack.DefinePlugin({
                "global.TNS_WEBPACK": "true",
                "process": undefined,
                "myGlobal.MyScarySecret": JSON.stringify("my big old secret")
            }),

main-page.ts:

declare let myGlobal: any;

export function navigatingTo(args: EventData) {
    let page = <Page>args.object;

    console.log(myGlobal.MyScarySecret); // my big old secret
}

This code helps you access the variable “myGlobal.MyScarySecret”, but that variable’s value is hardcoded in the code base. To keep it secret, I would want to avoid that, and set the value not in the code itself but in the webpack bundle command:

$ tns build …

What would be the correct command to set myGlobal.MyScarySecret in the build command?


#17

Refer the webpack docs, you can pass it as --env.variable=value, then catch that variable in the webpack config and assign it to your "myGlobal.MyScarySecret"


#18

I’ve seen those docs but my implementation yields errors–could be owing to my newness to Webpack. There is a final dot that I have not yet connected. In my case I have multiple different values to insert. But to keep it simple with just one value:

webpack.config.js:
"myGlobal.MyScarySecret": JSON.stringify(INSERT VALUE HERE) //env.first_property or "first_property" or env don't seem to work--that's what I am missing

$ tns build android --bundle --env.development --env.first_property=really_cool_secret_stuff


#19

With latest TNS and Webpack, it works. Your syntax seems correct, it works on my end.


#20

Thanks. I am not getting errors, but the results are not quite right.

Here is the detail:

When I run the following code:


$ tns run ios --bundle --env.uglify --env.aot --env.first_property="yaySecret"  //same if I do --env._property=yaySecret without quotes. Note I am running "tns run ios.." instead of "tns build ios..." bc, for some reason, I keep getting errors with the build command. error is: "warning: /Users/nsbuilduser/Library/Developer/Xcode/DerivedData/ModuleCache/......../ObjectiveC-.....: No such file or directory". This could have something to do with provisioning profiles. Don't think it effects webpack issue here.

webpack.config.js:

new webpack.DefinePlugin({
                "global.TNS_WEBPACK": "true",
                "process": undefined,
                "myGlobal.MyScarySecret": JSON.stringify(env.first_property)
            }),

main-component.ts:

declare let myGlobal: any;

export function navigatingTo(args: EventData) {
    let page = <Page>args.object;
    console.log(myGlobal.MyScarySecret); // result should equal "yaySecret", but the result comes out as "true"
}

So when I access the myGlobal.MyScarySecret the result I get is “true”, but the result should be “yaySecret”.