I'm trying to develop a desktop app which would need to make a few private API calls, authenticated using some secret keys.
The keys are created for me by external IT service providers outside of my organisation - they are responsible for the security so there are a few constraints:
They said even though they have already taken steps on their end to secure the API and there are mitigation strategies in place even if a breach happens, but still they would like to make sure that I treat the keys with a security-conscious mindset and take whatever steps possible on my end as well to make sure they remain secured.
I'm not allowed to just create random middleware / gateway on a private server or serverless platform to perform the API calls on my app's behalf as these calls may contain business data.
I have done some research and from what I can find, the general recommendation is to set up a ".env" file in the project folder and use environment variables in that file to store the API keys.
But upon reading the Vue CLI documentation I found the following:
WARNING
Do not store any secrets (such as private API keys) in your app!
Environment variables are embedded into the build, meaning anyone can
view them by inspecting your app's files.
So, given the constraints, is there a way to store these keys securely in a Vue CLI 4 + Electron Desktop app project?
Thanks.
In general, especially if you have a lot of environment variables, it would be better practice to store environment variables in a dot env file (.env), however, it's possible that this file could be leaked when you package your electron app. So, in this case it would be better to store your environment variables from the terminal/command line. To do so follow this guide (https://www.electronjs.org/docs/api/environment-variables).
Keep in mind anything that requires the API key/private information try to keep it on the backend, i.e., the electron process and send the results to the Vue front end.
Here's an example of how you could implement this:
On windows from CMD:
set SOME_SECRET="a cool secret"
On POSIX:
$ export SOME_SECRET="a cool secret"
Main process:
// Other electron logic
const { ipcMain } = require("electron");
// Listen for an event sent from the client to do something with the secret
ipcMain.on("doSomethingOnTheBackend", (event, data) => {
API.post("https://example.com/some/api/endpoint", {token: process.env.SOME_SECRET, data});
});
Client side:
const { ipcRenderer } = require("electron");
ipcRenderer.send("doSomethingOnTheBackend", {username: "test", password: "some password"});
Also note, to use the ipcRenderer on the client side nodeIntegration needs to be enabled.
Here are some more resources to help you get started:
https://www.electronjs.org/docs/api/ipc-renderer
https://www.electronjs.org/docs/api/ipc-main
I have following Node.js app structure:
- main.js - main file
- ./requests/requestSetName.js - different functions sending different requests to API, so I have e.g. userRequests.js, vechicleRequests.js etc.
First thing I do in main.js is I send a request with login credentials to get access token. For all other requests I need to put this token in the request header. So each function in all modules in request folder needs to have access to it.
What is the best way to store this token and to be able to use it across different modules in Node.js ?
I think you shoud use classes for each request file and inject another class (Globals) witch contains the token , in the constructor of each request class, typescript should make It clean.
I wrote a very simple service using sails.js. It uses Basic Authentication for access to its services.
I also have a separate front end written in Angular, using the #angular/cli.
I have two sets of environment variables to set for prod and dev. For example:
// dev
ADMIN=admin
ADMIN_PASS=mypassword123
API_ENDPOINT=http://localhost:1337/endpoint
This would obviously be different for prod. My issue is that I am deploying this using Heroku. You can easily set the env vars in heroku, but I don't know how to access them. I know you can set things in src/environments but this would then put my variables in code control.
I have also tried process.env but I learned this is a node.js thing not and angular thing.
How do I access system environment variables from angular2?
example of how I'd us it:
#Injectable()
export class HeroService {
private heroesUrl = 'api/heroes'; // <- this should be grabbed from environment
private adminUser = 'admin'; // this line too...
private adminPass = 'myPassword'; // same with this line...
constructor (private http: Http) {}
getHeroes(): Observable<Hero[]> { ...}
}
Programing Point of View
Use process.env then server side(nodejs) can put them into a structure. Since you are using sails.js, setup a post route or an api call that will send this structure in json format.
Front end(browser) app can make a http.post call to pick it up at run time.
This way the set of parameters are not bundled/hardcoded in your front end app code base.
Security Point of View
If password credential is required for 3rd party service, such call is better handled from the server side like following:
(browser) -- api call --> (your server) -- api call --> (3rd-party)
This way credential to 3rd party is not exposed. And api call to your server should be protected by some authentication mechanism.
I have created a new api using sails sails generate api tasks, using the default configuration of sails 0.12.
With Sails awesome blueprints, I can access localhost:1337/tasks and see the list of tasks or localhost:1337/tasks/create?text=yo to create a new one.
But what I want it to connect these endpoints to an .ejs view.
I tried creating a new folder tasks and placing show.ejs or index.ejs files in it but it's still returning the Json.
Is there a default way to render .ejs files through the default blueprint urls, without creating new routes and controller methods?
Well it took me a while to find the answer, so for anyone looking to use sails.js development speed, here is the way to do it:
After generating the api, create a folder inside your views folder (named after your controller). The files in it should be:
+ tasks (the folder with the same name as your controller)
- find.ejs (list of all items)
- findOne.ejs (view a specific item)
- create.ejs (after a successful creation)
- update.ejs (after a successful update)
- destroy.ejs (after a successful deletion)
These files are connected by default to the different api endpoints. So, when you access the url localhost:1337/tasks sails will automatically render tasks/find.ejs. Same for the other endpoints.
Another point is that each view will have a global variable named data that will include the result of the api request (i.e. the records that were fetched / modified).
You can see a small example here: https://github.com/web-development-course/Bootstrap (look at the 'things' api)
I hope it will help you guys
I'm building my first Express app, which needs to interact with an API, using an API key that ideally remains secure.
So I wanted to follow a basic pattern of keeping the key (and any future environment variables), in a .gitignored .env file in the root directory.
To not reinvent the wheel, I used this package, and set my env variables like so, in my app.coffee file (the root file of the application):
env = require('node-env-file')
env __dirname + '/.env'
console.log process.env.MY_API_KEY
That console.log prints out the right key to the server logs. The problem arises later:
If I try to access that same variable in one of the JS files loaded later on by my app, process.env is an empty object, so the API key is undefined. This doesn't appear to be a problem with the above package, because if I define the variable in the CL (API_KEY=whatever npm start), the behavior is the same -- it console logs correctly from app.coffee but is unavailable later.
Some information on how the files in which the key is unavailable are being loaded:
The app is running React, which I write to a few .jsx files in public/javascripts/src, and which are compiled by gulp into public/javascripts/build/*.js.
I'm trying to access the key in a .js file in public/javascripts/ which is required by one of the .jsx files.
In that required .js file, process.env returns an empty object. When I try to access process.env in the .jsx files, I'm actually told that process itself is undefined.
Any ideas what's going on here? I'm new to Express/React, and unclear where this process object, which I thought was global and defined on npm start is defined, and what's happening to all the env info in it.
Thanks! Please let me know if any other information would be helpful, orif anyone has any suggestions for how better to handle private env info in my situation.
EDIT:
I tried the suggestions below, and created a separate endpoint internally, which hits the external API and then returns a response. I've strung things up correctly, so that this responds correctly:
router.get '/images', (req, res, next) ->
res.json({ some: 'json' });
but this (which uses a separate class to make a request to an external API), throws an error:
router.get '/images', (req, res, next) ->
new Images('nature').fetch (images) ->
res.json({ some: 'json' })
Essentially, it looks like the asynchrony of the response from the external API (and not even the data itself, which I ignored), is creating a problem. How do I hit this external endpoint and then respond to the internal request with the incoming data?
Back-end vs Front-end
It seems like you are trying to access back-end data from a front-end location, in a wrong way.
The great power of Node.js is having JavaScript in the front and in the back, but it is quite confusing in the beginning to understand on which side each script is executed.
In an Express project, all Javascript files that are sent to the front-end, those that will directly interact with the client's page, are located in public/javascripts/. Generally you will have some AJAX functions in some of those files to exchange data and communicate with the back-end.
These back-end files are located everywhere else : in the root directory, in routes/, and all the other folders you create. Those files are pretty much all connected to your Node instance, and therefore can communicate with each other using global objects like process for example.
Your script in public/javascripts/, that is executed on the client's computer, is trying to directly access a variable located on the server running your Node instance : that's why your code doesn't work. If you wish to access data from the back-end, you must use AJAX calls in the front-end.
Server <---(AJAX only)--- Client
------ ------
app.js public/javascripts/script.js
routes.js
...
That being said, you wanted to keep your API key private, which will not happen if you send it to every client who's on that specific page. What you should do is make the call from the back-end, using the xhr module for example, and then delivering the data to front-end, without the secret API key.
I hope I was clear, Node is quite confusing at first but very soon you will get over these little mistakes !
All .jsx is, is some code, what matters is where the code is being executed. process.env is a variable that is accessible inside the Node.js runtime. When your .jsx code gets transpiled down to .js and served to the browser, the process.env variable will no longer exist. If you're making an API call inside the browser, the API key will be fundamentally available to the client. If you want to secure the key, you have to have your Node.js server expose an API route, which your React app will hit. That Node.js server will then make the call to the external service using the API key. Because that call is being made by the server, process.env will be available, and will remain hidden from the client. You can then forward the result of the API call back to the user.