404 error/No Access-Control-Allow-Origin header message in Symfony 4 + React app. How to make the routing work? - reactjs

I have created simple application and would like to deploy it on a server. I am going through this for the first time – so no previous experiences I could benefit from.
The problem in general:
The app has implemented React Router, but uses Symfony routing for calls to and from database. So for navigating through app tabs, React Router takes place, for fetching in/from DB I intended to use Symfony routes.
Everything works well when I am on the local server. But when I manually dragged and dropped files on the server the app breaks on the fetch requests.
React component code:
let targetUrl = `http://serverAddress.nazwa.pl/save`;
let request = new Request(targetUrl, {
body: formData,
method: "POST",
headers: {
"Access-Control-Request-Method": "POST, GET, OPTIONS",
"Origin": "http://mySimpleAppDomain.com.pl",
}
})
fetch(request)
.then((response) => response.json())
.then((response) => {
this.setState({
isListActive: false,
currentItems: [],
currentItemsCounter: 0
})
document.getElementById("defNavEl").classList.add("default")
})
.catch((error) => {
console.error('SAVE TO DB FETCH ERROR:', error);
});
Symfony Controller code:
**
* #Route("/save", name="save")
*/
public function save(Request $request)
{
$shoppingList = new ShoppingList();
$list = $request->request->all();
if (count($list) > 0) {
$em = $this->getDoctrine()->getManager();
$shoppingList->setCreationDate(new \DateTime());
$shoppingList->setName($list['name']);
unset($list['name']);
$shoppingList->setListItems($list);
$em->persist($shoppingList);
$em->flush();
$results = $em->getRepository(ShoppingList::class)->listAllShoppingLists();
$response = $this->json($results);
$response->headers->set('Access-Control-Allow-Origin', 'https://localhost:8006');
$response->headers->set('Content-Type', 'application/json');
return $response;
} else {
return new Response();
}
}
Nelmio CORS bundle configuration:
nelmio_cors:
defaults:
allow_credentials: false
allow_origin: []
allow_headers: []
allow_methods: []
expose_headers: []
max_age: 0
hosts: []
origin_regex: false
forced_allow_origin_value: ~
paths:
'^/': null
origin_regex: false
allow_origin: ['*']
allow_methods: ['*']
allow_headers: ['*']
expose_headers: ['Link']
max_age: 3600
Observations:
When I try to fetch data to DB I receive the following message in the console:
Access to fetch at 'http://example.nazwa.pl/save' from origin 'http://myappname.com.pl' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
This happens despite the fact that I have set ‘Access-Control-Allow-Origin' header in the action that is intended to handle the request.
When I send some test requests on the http://serverAddress.nazwa.pl/save via Postman, I get 404 error.
That seems to be at odds with the CORS policy message cited in he point 1).
What I tried (among others):
I tried to reorganize controller so that there is only one action responsible for different requests. But mysteriously it didn't work. It also doesn't seem to be good idea in terms of good practices.
Calling for help:
I am out of ideas for now. Perhaps it is something with .htaccess configuration (I have installed Apache Pack, which has generated it). I will appreciate any suggestions or ideas that could help me move forward.

Your Configuration is pointing to null at this line :
'^/': null
You need to have configuration related to your route and domain like this:
Feel free to change it to your needs and use .env config if it's symfony 4:
nelmio_cors:
defaults:
origin_regex: true
allow_origin: ['%env(CORS_ALLOW_ORIGIN)%']
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
allow_headers: ['Content-Type', 'Authorization']
expose_headers: ['Link']
max_age: 3600
paths:
'^/save' :
allow_origin:
- '^http://serverAddress.nazwa.pl/'
- '^http://localhost:[0-9]+'
- '^http://serverAddress.nazwa.pl/save'
#allow_origin: ['*']
allow_credentials: true
allow_headers: ['Authorization', 'X-Requested-With', 'content-type','Content-Type', 'Accept', 'Origin', 'X-Custom-Auth']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE','PATCH','OPTIONS']
max_age: 3600
'^/': null
The Paths array will take route and apply default configuration from above and then merge it with route specific configuration so you get exact config for each routes defined.
This example defaults all other routes to block cors requests except /save route which will allow domains or paths defined in array.
Note that : allow_origin: ['*'] will allow from all other domains to request resource which is not recommended unless it is a public api and any script can request to it.

Related

Problem with cors between backend and frontend

I have a problem with my cors policy between my backend (API Rest in .NET Core 6) and my frontend (in ReactJS), the thing is that in my backend I have the following configuration:
In appsetings.json:
"AllowedHosts": "mywebsite.com"
In Program.cs:
services.AddCors(options =>
{
options.AddPolicy(name: "mycors", builder =>
{
builder.WithOrigins("mywebsite.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
app.UseCors("mycors");
This configuration doesn't work when I'm trying to fetch a post request to my API, but if I change the AllowedHosts to "AllowedHosts": "*" it works. I don't understand why I can't allow just to my frontend website.
Additional information, my post request has these parameters:
method: 'POST'
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'follow',
referrerPolicy: 'no-referrer',
headers: { 'Content-Type': 'application/json' },
body: //My parameters
The console error is:
Access to fetch at 'mybackendpostmethod' from origin 'myfronturl.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I solved putting my api that return as follows

CSRF cookie not set [Django/AngularJS]

First of all, this is not a duplicate question. I have tried all the related posts on stackoverflow but could not find a solution.
I have a Django app for the backend and and AngularJS app for the frontend. I am using djangorestframework-jwt for API authentication. I have an API endpoint that does not require any authentication and I am getting CSRF Failed: CSRF cookie not set error on the browser only for this endpoint.
In my django settings I have:
ALLOWED_HOSTS = ['*']
and it does not include any CSRF_COOKIE_SECURE, CSRF_COOKIE_HTTPONLY, or SESSION_COOKIE_SECURE settings.
The djangorestframework-jwt settings is:
JWT_AUTH = {
'JWT_SECRET_KEY': SECRET_KEY,
'JWT_ALGORITHM': 'HS256',
'JWT_VERIFY': True,
'JWT_VERIFY_EXPIRATION': True,
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=3000),
'JWT_ALLOW_REFRESH': True,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=1),
'JWT_AUTH_COOKIE': 'refresh-token'
}
I noticed that in the browser cookies if there is any refresh-token key then the endpoint works just fine. The problem arises when that key is not present in the browser cookies. I set 'JWT_AUTH_COOKIE': None or removed the following lines:
'JWT_ALLOW_REFRESH': True,
'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=1),
'JWT_AUTH_COOKIE': 'refresh-token'
from the JWT_AUTH settings but no luck.
I also tried #csrf_excempt for that endpoint but that did not work either.
Interestingly, when I send the request from postman it works.
Here is the request I am sending from the frontend:
$http({
url: url,
method: "PUT",
headers: {
'Content-Type': 'application/json'
},
data: data
})
I would like to know why I am getting the error when refresh_token key is not present in the browser cookies and how to solve this issue.
I solved my issue by adding 'X-CSRFToken': $cookies.get("csrftoken") to the Http request header, so the request now look like:
$http({
url: url,
method: "PUT",
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': $cookies.get("csrftoken")
},
data: data
})

Deno Oak Disable Cors

I am trying to 'connect' my small React JS app with my Deno API backend on my local environment with fetch().
const apiUrl = `http://localhost:8000`;
try{
fetch(apiUrl)
.then((res) => res.json())
.then((repos) => {
console.log(repos);
setAppState({ loading: false, repos: repos });
});
}catch(err){
console.log(err);
}
My app is serving on localhost:3000 and my deno api on localost:8000.
However, I am having problem with CORS:
Access to fetch at 'http://localhost:8000/' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
I tried some suggestions like:
add line '"proxy": "http://localhost:8000" to reactjs project packages.json'.
Or to add:
var options = {
method: 'get',
headers: {
"Access-Control-Request-Headers": "*",
"Access-Control-Request-Method": "*"
},
}
fetch(apiUrl, options)
Or to add:
fetch(apiUrl, {mode: 'no-cors'})
However, nothing works in my case. All the time getting the same error and some additional based on suggestions.
So,I need to disable CORS in my reactjs and deno api app to allow local dev communication between frontend and backend.
Solution in my case was pretty easy.
I had to import oakCors into my Deno API app.ts
import { oakCors } from "https://deno.land/x/cors/mod.ts";
after that, just add the excluded origin after app instantiation:
app.use(
oakCors({
origin: "http://localhost:3000"
}),
);
NOTE: I tried to set origin to origin: false and that did not work in my case.
For more options on Deno CORS here is a link: https://deno.land/x/cors
This works just fine:
app.use(oakCors({ origin: "*" }));
For me, I had to first pass oakCors configuration to the app and then the routes.
app.use(oakCors({
origin: 'http://localhost:4200',
optionsSuccessStatus: 200,
}));
app.use(router.routes());
placeapp.use(oakCors()) before your routes like this:
app.use(oakCors())
app.use(route.routes())
this is allow all CORS before to manage the routes

Axios adding headers to get request only sends options

So I have a simple axios request from my reactjs component:
let config = {headers: {'Authorization': 'Bearer token-value'}};
axios.get(routes.API + '/user', config).then(response => {
console.debug(response);
}).catch(error => {
// error
});
Backend is just a simple symfony controller that accepts GET request and should return user data.
The issue is that this request only makes OPTIONS request. And it fails because my backend function is only supposed to accept get. It fails because of method not allowed. If I allow OPTIONS request method it fails, because of authorization error. And I never want to authorize OPTIONS because it would fetch user from the database.
Also it never does GET request.
If I remove config object and only leave url the request works as it should and never sends OPTIONS request, but I need header to pass my authorization token.
I have these headers enabled on my backend nginx server:
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
What am I missing here?
That's not really an axios specific behaviour, you should make sure that your server is able to handle CORS properly. For Symfony - there is a bundle that does it for you, I had to use it when having a similar issue:
https://github.com/nelmio/NelmioCorsBundle
Here is a sample config:
nelmio_cors:
defaults:
allow_credentials: false
allow_origin: []
allow_headers: []
allow_methods: []
expose_headers: []
max_age: 0
hosts: []
origin_regex: false
forced_allow_origin_value: ~
paths:
'^/api/':
allow_origin: ['*']
#Without this the OPTIONS request by axios won't work
allow_headers: ['Content-Type']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE']
max_age: 3600

Call symfony 2 rest api with Angular JS, cors

I'm using angularJS to call a restfull API in symfony 2.
My angularJS app url is angular.me.dev
My symfony2 api url is api.me.dev
I followed this tutorial to make my restfull api.
The problem is when I try to call this api
$http.({
method: 'GET',
url: 'http://api.me.dev/api/articles',
headers: {
'Authorization': 'Bearer ' + token
}
})
An error occured: (here on google chrome):
XMLHttpRequest cannot load http://api.me.dev/api/articles. Response for preflight has invalid HTTP status code 405
(and on on firefox):
The Same Origin Policy disallows reading the remote resource
what did I find about this ?
AngularJS Sends OPTIONS request instead of POST
AngularJS performs an OPTIONS HTTP request for a cross-origin resource
Then I decide to allow headers, origin, ... on my server like this:
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Credentials "true"
Header always set Access-Control-Allow-Methods "PUT, DELETE, POST, GET, OPTIONS"
Header always set Access-Control-Allow-Headers "*"
No change
I add to AngularJS
#coffee script
app.config ['$httpProvider', ($httpProvider) ->
$httpProvider.defaults.useXDomain = true
delete $httpProvider.defaults.headers.common['X-Requested-With']
]
Then I decided to install NelmioCorsBundle in my symfony api but I didn't see any change.
Finally, I notice a call works
$http.({
method: 'GET',
url: 'http://api.me.dev/api/articles',
})
Here the call return a 401 response (good, i need to be logged)
$http.({
method: 'GET',
url: 'http://api.me.dev/public/api/users',
})
Here I have a call doesn't need authorization, it works.
I found only when I remove headers it works, and when I had any headers (content-type or authorization for example) an error occured.
Can anyone help me ? thanks !
Ok, my bad.
I said NelmioCors seems not working but i did something wrong.
I try again with nelmio cors bundle, using this configuration.
nelmio_cors:
paths:
'^/':
allow_origin: ['http://angular.me.dev']
allow_headers: ['Authorization', 'X-Requested-With', 'Content-Type', 'Accept', 'Origin', 'X-Custom-Auth']
allow_methods: ['POST', 'PUT', 'GET', 'DELETE', 'OPTIONS']
max_age: 3600
It's working !
NelmioCorsBundle resolve the problem.
https://github.com/nelmio/NelmioCorsBundle

Resources