I am working locally with react and a nodejs server. I have configured my nodejs server to communicate with react and it works.
From react I want to check if external urls (for example youtube) exist, but the cors error always jumps.
I have tried with axios, XMLHttpRequest, fetch and I have used the header : 'Access-Control-Allow-Origin': '*',
I can remove the cors validation from the browser for testing, but what happens when I upload it to the server?
How can I check if an image, page, video... on an external server exists?
CORS is only applied when you try to do it directly from your browser. Then you can create your own server, create an API endpoint to check if a URL exists, and then, from your react page, you send requests to your API and your API check the page existence. – (by Pipe)
I made a weather app in Create React App (create-react-app). How do I hide the API key so that I can commit to GitHub?
Right now, the key is in App.js:
const API_KEY = "123456";
Unfortunately, keeping any key in your React client, even if you are using gitignore and an .env file, is not secure. As pointed out by Claudiu Creanga, React environment variables are embedded in the build and are publicly accessible.
You should really only save API keys or secrets in your backend such as Node.js or Express.js. You can have your client send a request to your backend API, which can then make the actual API call with the API key and send the data back to your client.
Disclaimer
WARNING: Do not store any secrets (such as private API keys) in your
React app!
Environment variables are embedded into the build, meaning anyone can
view them by inspecting your app's files.
The following answer provides a correct way to store non-secret data in environment variables. Remember that secret data is accessible through developer tools, making it unsafe to store as environment variables. If you want to store some secret data then storing in the backend is the better option and if the client wants to access secret data, it can be accessed by making a request to the server. (Refer to Antonia's answer for more details on storing secret data.)
As it turns out, create-react-app has some built-in functionality to help you with that. Thank you George Karametas for this insight. To access that functionality, you need to:
1. Create a file called .env in the root of your project's directory.
- your_project_folder
- node_modules
- public
- src
- .env <-- create it here
- .gitignore
- package-lock.json
- package.json
2. Inside the .env file, prepend REACT_APP_ to your API key name of choice and assign it.
The create-react-app tool uses REACT_APP_ to identify these variables. If you don't start your API key name with it, create-react-app won't see it.
// .env
REACT_APP_API_KEY=your_api_key <-- yes
API_KEY=your_api_key <-- no
// Example (from 이준형's response):
REACT_APP_WEATHER_API_KEY=123456
3. Add the .env file to your .gitignore file.
After you add the line below, save the .gitignore file and do a git status to make sure your .env file does not appear as a new file in git.
// .gitignore
# api keys
.env <-- add this line
# dependencies
/node_modules
...
4. Access the API key via the process.env object.
To check that you can access your API key, go to your App.js file and add a console.log at the top below the require statements. After saving the file and reloading the page, if the console log does not show your API key, try restarting the react server. Be sure to remove the console log line before committing your code.
// src/App.js
import React, { Component } from 'react';
import './App.css';
console.log(process.env.REACT_APP_WEATHER_API_KEY)
class App extends Component {
...
Warning
Unless you're making tutorial applications, don't put secrets such as API keys in client-side source code (e.g., a React app). From Create React App's documentation:
WARNING: Do not store any secrets (such as private API keys) in your
React app!
Environment variables are embedded into the build, meaning anyone can
view them by inspecting your app's files.
First, create an .env file in the root of your project, i.e., where you would run react-scripts start (or yarn start) outside of your source folder.
Then, add
REACT_APP_WEATHER_API_KEY=123456
Before commit, you should exclude this .env file, so find the .gitignore file and add .env.
The name of the variable needs to begin with REACT_APP_ which protects you from accidentally including secrets with your build.
Don't forget to add .env in the .gitignore file.
To use the environment variables in your code:
const API_KEY = process.env.REACT_APP_WEATHER_API_KEY;
In order to read environment variables after having added them to .env, restart your server.
From the React documentation:
WARNING: Do not store any secrets (such as private API keys) in your React app!
Environment variables are embedded into the build, meaning anyone can
view them by inspecting your app's files.
Although the question has already been answered by Antonia Blair, I would like to through some more light on some basic rules.
1: Most of the answers are suggesting to make use of the .env file. I would like to make it clear for once and all that .env is not here to add any security layer. The .env as the name depicts is only here to set up an environment at build time. e.g. by using the environment variables you set some global values at build time and can access these values in your application at runtime.
2: React is simply a framework running your JavaScript code in the client browser. So the client has complete access to the JavaScript (React) code. Nothing is secure on the client-side. So never think of making something secure or hidden from the client by just keeping all your code client-side. Whenever you need to hide something from the client, there is something server-side which you need to incorporate. Only the server-side code is secure from the client-side.
3: So what you do is, you will keep your secure keys on the server-side.
Suppose the purpose of your secure keys is to make a cookie for your client. so the client needs the cookie not the secure keys, right? So the client-side makes a request to the server for a cookie, the server makes the cookie by using the secure keys and returns the cookie to the client. After all the client is only here to eat the cookie and not to know how do we make a cookie right?
4: So the thumb rule is that wherever you have some confidential data, you will keep it on the server. The server will use this confidential data and return the result data to be exposed to the client.
A user has asked for a coding example, so I have put up a real-time scenario which I have handled using the above described technique.
Here is my use case:
I have a React app which submits a public form to non public API.
The non public API is Harvest API hosted by:
https://www.greenhouse.io/
This API requires an authentication header for making requests with it. I have subscribed with the API owner and received a secret token from them which I can use with my requests to get access to their API
Af course, I want to keep my token personal and do not expose it to public users
I have used the Axios client to communicate with the API
I have two ways to perform the above described scenario:
The Incorrect Method
I am making requests to the API directly from my React application
Let’s say below is the API endpoint which I want to hit
apiURL = https://boardsapi.greenhouse.io/v1/boards/xyz/jobs/" + jobId + ""
The above API endpoint requires an authorization header, and I will provide my secret token in it.
const config = {
headers: {
"Authorization": "Basic ####MySecretCode#####",
} };
Suppose I want to post some form data with this request
let formData = MyFormData
I can now send my request using the Axios client like below
let result = await axios.post(apiURL, formData, config);
Using the above technique, I can successfully post my form data to the Harvest API.
But like I said, that it's an incorrect way to communicate with this API. Because I have exposed my secret token on the client side.
The Correct Way
I built an API on Node.js and hosted it publicly.
Suppose I want to post some form data to the Harvest API
let formData = MyFormData
I am not going to hit the Harvest API directly from my client application. And instead I have exposed and endpoint in my middleware API to handle this.
Let’s say the below is the endpoint URL of my middleware API which I want to hit
apiURL = https://proxy-server/apply
The above API endpoint does not requires an authorization header. So I can send a post requests using the Axios client like below:
let result = await axios.post(apiURL, formData);
The difference is clear. I have not supplied the secret token this time in my request. Because this is not a direct request to the Harvest API and instead it's a request to a middle-ware API which is developed and hosted by me.
I receive this request in my middle-ware API, add my secret token with it and forward it to the Harvest API. The response from Harvest API is returned to our middle_ware API and hence forward back to our React client application.
The secret token now resides on my server-side API and safe from external users.
Here's what worked for me:
I created the .env file in the root folder.
Within that folder I added my key:
REACT_APP_API_KEY_YT = "key"
// I added 'YT' for YouTube which is where my API key is from
Then I went to .gitignore. Or create a .gitignore file in your root directory if you don't have it. Within .gitignore, I added .env
# API key
.env
Then I went back to the root of my App js file. For me, that was index.js. For others, it is probably App.js.
There I created a const API_KEY
const API_KEY =`${process.env.REACT_APP_API_KEY_YT}`
I checked if it was working by console logging it.
console.log("API", API_KEY)
I was getting undefined.
I stopped the server (Ctrl + C) and restarted the server.
Afterwards I was able to see the key.
Here is an example of finding the API key in code even when you attempt to hide it in an environment variable.
I built a very simple app using the NewsAPI, which required me to register for an API key. Here is my fetch to the NewsAPI endpoint using the API key as an environment variable.
fetch(`https://newsapi.org/v2/top-headlines?q=${keyword}&apiKey=${process.env.REACT_APP_API_KEY}`)
.then(res => res.json())
.then(
(result) => {
setIsLoaded(true);
setArticles(result.articles);
})
However, when I inspected the network request with Chrome dev tools, you will be able to see the actual value of the API key. I hope this helps folks see how somebody could find an API key on the client even if you store it as an environment variable.
How one could hide an API key:
You could make the HTTP request from your server side logic, so you can safely hide an API key in the .env file. In the below example I created an enpoint to /top-headlines/:searchTerm. Once a request to that endpoint is received, then I send the Axios request to the news API using the "NEWS_API_KEY" environment variable which is stored in my .env file.
route.get("/top-headlines/:searchTerm", async (req, res) => {
const { searchTerm } = req.params;
try {
const articlesResponse = await axios.get(
`https://newsapi.org/v2/top-headlines?q=${searchTerm}&apiKey=${process.env.NEWS_API_KEY}`
);
const articlesData = articlesResponse.data;
res.send(articlesData);
} catch (error) {
console.log(error);
}
});
If you use the API key for local development purposes, put it under the .env.development file and Git ignore it. Credentials in the .env file will be picked up by the build process, which will expose the data in production.
For details, see What other .env files can be used?
Be advised! If you put any credentials in a React client, they are not secure, even if you are using gitignore and an .env file. Still they are not secure.
You should really only save API keys or secrets in your backend, such as Node.js or Express.js. Use a proxy, send the request from the front end to the backend and then the backend will make a request for fetching data to front end.
If you are in production, then you cannot use environment variable directly there for frontend (React). You need to follow the instructions on How to implement runtime environment variables with create-react-app, Docker, and Nginx in order to achieve this goal if you want to access environment variables in production.
The secure key/secret should never be sent to the client side. Say, you want to download a file from S3 down on the client machine via your app (running in a browser).
Make a call to the server to obtain a ephemeral token (which expires with time)
the server (which has the secret and everything) makes the token and sends it back
the client uses the token to access S3
The token itself is not a secret and it's useless once it expires.
Creating a .env file is helpful as stated in previous answers. But one point to notice here is that:
If you are using API_KEY in your URL as state like this,
this.state = {
url:`http://newsapi.org/v2/everything&apiKey=${process.env.REACT_APP_API_KEY}`
}
then it will be visible in React developer tool.
Instead, you can put your API_KEY directly at the location of fetch. For example,
fetch(`http://newsapi.org/v2/everything?&apiKey=${process.env.REACT_APP_API_KEY}`)
I have one extension api, I upload it form web/resource/REST API, affter upload, it works well. however, I used the code to upload, i used the PageAPI.createPage() to upload extension, it upload success, but it doesn' work, I check the file on server, from the server, I can't find the extension from the ${BONITA_HOME}\bonita\client\tenants\1\work, it only exist on ${BONITA_HOME}\bonita\client\tenants\1\temp, debug, the files is invode the pageAPI servlet, and invode the PageDataStore.createEngieenPage(), so my question is how can i use the REST API to add extension and deploy it?
In order to deploy a Bonita REST API extension programmatically you need to:
Call the loginservice REST API for authentication
Send the file to a temporary folder on server side using the uploadPage servlet
Register the new REST API extension by calling the portal/page REST API
I create a basic Groovy script that demonstrate that.
I'd like to configure my gulp webserver task to pass an environment variable into the angular app. Each team member has his own VM running the API and the variable would instruct the Angular app of the base API url. I'm trying to eliminate the need for every team member to remember to edit the config file after every TFS update.
I thought of simply setting a response header via middleware, but javascript cannot see response headers for the current page - only those of XHR responses.
So I try initializing the config service by performing a HEAD request against the web root, but this requires resolving a $http promise which requires adding a resolve to the route config to ensure it gets resolved before something tries to use it.
I tried just injecting a cookie via middleware and reading it with the $cookies service, but Internet Explorer apparently doesn't see 'localhost' as a valid domain name for cookies and does not read them.
So what other ways are there to allow an environment variable (or other form of local config) to be passed into the angular app?
We have solved this problem in many ways for different situations.
We don't use the base URL but just relative "/folder/resource".
We have an HttpHandler that resolves files with custom extension i.e. ".xyz". Then we have a file named "config.xyz" which is just a JavaScript file with something like:
{
baseUrl: [BASE_URL]
}
When the handler is asked to provide this file, the handler reads the file and does the replacements and then serve its content.
Use the one fake name for the server that serves the API. I.e: thisismylocalfake and then ask developers to configure their hosts file in system32
Have a gulp tasks that, when you compile the application, takes one config.js file and uses the machine name to replace a tag like in option 2.
I ended up adding middleware to the gulp-webserver to intercept a request for our config service file. Then I used gulp-replace and gulp-respond to inject the url from the environment variable directly in the stream. No files edited, technically and it works without having to have any sort of dev-specific code in the project.
I'm using AngularJS with UI-Router and am attempting to attach a query parameter to a url on all http requests across my site.
I have an OAuth system on the backend and was previously applying Authorization headers to all requests, however to preserve backwards compatibility - have discovered I will have to instead apply a url parameter with the user identification to the backend.
My issue is that, I cannot use $httpInterceptor in the config portion of the app, because at that point in the app I don't have the current User, and can't inject $http to resolve the current user because that creates a circular dependency.
I was trying to use $http.defaults.transformRequest in the run portion of the app, but that didn't seem to be able to append a parameter to the url.
Is there a way to do this short of hand writing it on every REST request across the app?
I had similar problem in my current project.
To solve the problem I manually request current user info before app bootstapping & store it in localStorage.
Then bootstrap the app & in the config section you will have accesss to current user info.
TIP: to get user info before app bootstrap you can still use $http service by manually injecting it:
angular.injector(['ng']).get('$http');