Reputation: 6466
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 .gitignore
d .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:
.jsx
files in public/javascripts/src
, and which are compiled by gulp
into public/javascripts/build/*.js
. .js
file in public/javascripts/
which is require
d by one of the .jsx
files. .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?
Upvotes: 3
Views: 6924
Reputation: 637
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 !
Upvotes: 5
Reputation: 11677
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.
Upvotes: 5