React-admin + api-platform - Content-Range - symfony

I have 2 applications, both run on the docker. First backend (symfony 5 + api platform) on port 8080, second frontend(react + react-admin) on port 3000.
I can see the table to items, but when I try to load items from backend, I see all time the same bug:
index.js:1 Error: The Content-Range header is missing in the HTTP Response. The simple REST data provider expects responses for lists of resources to contain this header with the total number of results to build the pagination. If you are using CORS, did you declare Content-Range in the Access-Control-Expose-Headers header?
frontend:
ReactDOM.render(
<Admin dataProvider={simpleRestProvider('http://localhost:8080/api')}>
<Resource name="pharmacies" list={PharmacyList} edit={PharmacyEdit} create={PharmacyCreate} icon={PharmacyIcon}/>
</Admin>,
document.getElementById('root')
);
I've had a problem with CORS, so I reconfigured the nelmio_cors.yaml:
defaults:
allow_credentials: false
allow_origin: [ ]
allow_headers: [ ]
allow_methods: [ ]
expose_headers: [ 'Content-Range' ]
max_age: 0
hosts: [ ]
origin_regex: false
forced_allow_origin_value: ~
paths:
'^/api/':
allow_origin: [ '*' ]
allow_headers: [ '*' ]
allow_methods: [ 'POST', 'PUT', 'GET', 'DELETE' ]
max_age: 3600
'^/':
origin_regex: true
allow_origin: [ '^http://localhost:[0-9]+' ]
allow_headers: [ '*' ]
allow_methods: [ 'POST', 'PUT', 'GET', 'DELETE' ]
max_age: 3600
hosts: [ '^api\.' ]
The response header:
Server: nginx/1.19.5
Content-Type: application/ld+json; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/7.4.13
Vary: Accept
X-Content-Type-Options: nosniff
X-Frame-Options: deny
Cache-Control: no-cache, private
Date: Sun, 21 Feb 2021 13:00:55 GMT
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Expose-Headers: content-range
Link: <http://localhost:8080/api/docs.jsonld>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"
ETag: "0eeb89535116e4257a2152e977020a7a"
X-Debug-Token: 0f9844
X-Debug-Token-Link: http://localhost:8080/_profiler/0f9844
X-Robots-Tag: noindex
Where is my mistake? What am I doing wrong? It's a problem with frontend app, symfony config(nelmo) or http server (nginx)? I read a lot of posts on SOF/github and other blogs. Nothing can help.
https://marmelab.com/react-admin/DataProviders.html - I tried to disable it in cors headers and force this header on nelmo/api-platform. It Access-Control-Expose-Headers: content-range doesn't help.

Related

Cors exception on api-platform cache, it works on the normal http requests

I wanted to create a custom component for my react-admin dashboard a simple select input following the example of https://marmelab.com/blog/2020/04/27/react-admin-tutorials-custom-forms-related-records.html but I got the following error unrelated to react-admin and more related to symfony and api-platform. Which is a cors error but the strange thing is the same url is working the first time while loading the data in a list but the second time it causes a cors exception.
Cors configuration:
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: ['Content-Disposition', 'Content-Length', 'Link']
max_age: 3600
paths:
'^/api/':
origin_regex: true
allow_origin: ['*']
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
allow_headers: ['*']
expose_headers: ['Content-Disposition', 'Content-Length', 'Link', 'Access-Control-Allow-Origin']
max_age: 3600
'^/uploads/':
origin_regex: true
allow_origin: ['*']
allow_methods: ['GET', 'OPTIONS', 'POST', 'PUT', 'PATCH', 'DELETE']
allow_headers: ['Content-Type', 'Authorization']
expose_headers: ['Content-Disposition', 'Content-Length', 'Link']
max_age: 3600
I think the problem has something to do with my api-platform config "cache_headers" but I can't find any other documentation or a related error with the same problem so this might even be a bug or might be my inexperience.
api-platform Config:
api_platform:
collection:
pagination:
client_items_per_page: true
items_per_page_parameter_name: itemsPerPage
eager_loading:
enabled: false
http_cache:
invalidation:
enabled: true
public: true
defaults:
cache_headers:
max_age: 0
shared_max_age: 3600
allow_origin: '*'
vary: ['Content-Type', 'Authorization', 'Origin', 'Access-Control-Allow-Origin']
mapping:
paths: ['%kernel.project_dir%/src/Entity']
# paths: ['%kernel.project_dir%/config/api_platform/resources']
patch_formats:
json: ['application/merge-patch+json']
swagger:
versions: [3]
api_keys:
apiKey:
name: Authorization
type: header
exception_to_status:
# The 4 following handlers are registered by default, keep those lines to prevent unexpected side effects
Symfony\Component\Serializer\Exception\ExceptionInterface: 400 # Use a raw status code (recommended)
ApiPlatform\Core\Exception\InvalidArgumentException: !php/const Symfony\Component\HttpFoundation\Response::HTTP_BAD_REQUEST
ApiPlatform\Core\Exception\FilterValidationException: 400
Doctrine\ORM\OptimisticLockException: 409
First request:
first Request
Second request:
second Request
First response:
first Response
Second response:
second Response

CouchDB request with JWT causes error "No DB shards could be opened"

I have a couchdb server, which at this moment is for development and it has just one node running in docker.
I would like to authenticate through JWT. I have build my token.
GET https://comp010:6984/_session
Accept: application/json
Content-Type: application/json; charset=utf-8
Authorization: Bearer <JWT token>
I get proper answer (or at least I think so):
{
"ok": true,
"userCtx": {
"name": "uaru",
"roles": "admin"
},
"info": {
"authentication_handlers": [
"jwt",
"cookie",
"default"
],
"authenticated": "jwt"
}
}
When I send request to get actual object from the database
GET https://comp010:6984/db_userspaces/xxxx3
Accept: application/json
Content-Type: application/json; charset=utf-8
I get "unauthorized" exception. This is ok, I did not authenticated this request. So I add the same authorization header:
GET https://comp010:6984/db_userspaces/xxxx3
Accept: application/json
Content-Type: application/json; charset=utf-8
Authorization: Bearer <JWT token>
And I get
{
"error": "internal_server_error",
"reason": "No DB shards could be opened.",
"ref": 179462285
}
But if I switch off the authorization ( [chttpd] require_valid_user = false), and send the same request without Authorization header,
GET https://comp010:6984/db_userspaces/xxxx3
Accept: application/json
Content-Type: application/json; charset=utf-8
I get proper response.
Server: CouchDB/3.2.1 (Erlang OTP/23)
X-Couch-Request-ID: 02c628ce15
X-CouchDB-Body-Time: 0
{
"_id": "xxxx3",
"_rev": "1-a11f390ffa77a03c557ffbbc7c5fda75",
"x": "1"
}
How JWT can relate to shards? I am puzzled and I cannot find anything related.
There are no errors with Fauxton.
Thank you in advance for any suggestions.
Here is the log when the request took place
couchdb-server_1 | [error] 2022-03-09T04:52:34.662593Z nonode#nohost <0.6234.1> 82a6b79f38 rexi_server: from: nonode#nohost(<0.6134.1>) mfa: fabric_rpc:open_shard/2 error:function_clause [{lists,usort,[<<"admin">>],[{file,"lists.erl"},{line,1063}]},{couch_db,check_security,3,[{file,"src/couch_db.erl"},{line,713}]},{couch_db,is_authorized,2,[{file,"src/couch_db.erl"},{line,705}]},{couch_db,is_member,1,[{file,"src/couch_db.erl"},{line,685}]},{couch_db,check_is_member,1,[{file,"src/couch_db.erl"},{line,671}]},{couch_db,open,2,[{file,"src/couch_db.erl"},{line,166}]},{mem3_util,get_or_create_db,2,[{file,"src/mem3_util.erl"},{line,549}]},{fabric_rpc,open_shard,2,[{file,"src/fabric_rpc.erl"},{line,307}]}]
couchdb-server_1 | [error] 2022-03-09T04:52:34.662982Z nonode#nohost <0.6236.1> 82a6b79f38 rexi_server: from: nonode#nohost(<0.6134.1>) mfa: fabric_rpc:open_shard/2 error:function_clause [{lists,usort,[<<"admin">>],[{file,"lists.erl"},{line,1063}]},{couch_db,check_security,3,[{file,"src/couch_db.erl"},{line,713}]},{couch_db,is_authorized,2,[{file,"src/couch_db.erl"},{line,705}]},{couch_db,is_member,1,[{file,"src/couch_db.erl"},{line,685}]},{couch_db,check_is_member,1,[{file,"src/couch_db.erl"},{line,671}]},{couch_db,open,2,[{file,"src/couch_db.erl"},{line,166}]},{mem3_util,get_or_create_db,2,[{file,"src/mem3_util.erl"},{line,549}]},{fabric_rpc,open_shard,2,[{file,"src/fabric_rpc.erl"},{line,307}]}]
couchdb-server_1 | [error] 2022-03-09T04:52:34.663440Z nonode#nohost <0.6134.1> 82a6b79f38 req_err(179462285) internal_server_error : No DB shards could be opened.
couchdb-server_1 | [<<"fabric_util:get_shard/4 L118">>,<<"fabric_util:get_shard/4 L132">>,<<"fabric:get_security/2 L183">>,<<"chttpd_auth_request:db_authorization_check/1 L112">>,<<"chttpd_auth_request:authorize_request/1 L19">>,<<"chttpd:handle_req_after_auth/2 L325">>,<<"chttpd:process_request/1 L310">>,<<"chttpd:handle_request_int/1 L249">>]
couchdb-server_1 | [notice] 2022-03-09T04:52:34.663753Z nonode#nohost <0.6134.1> 82a6b79f38 comp010:6984 ::ffff:150.26.121.46 uaru GET /db_userspaces/xxxx3 500 ok 2
In the payload to be turned into JWT, roles MUST BE an array.
{
:sub => username,
:'_couchdb.roles' => roles,
:exp => ...,
}
In my case, roles was not. But it means that should be error 400 Bad Request.
The whole problem has nothing to do with shards configuration, etc. The error message was misleading.
Thanks to people in CouchDb slack channel for guiding me in the right direction.

Google OAuth2 endpoint always says invalid client ID

When making requests to the Google OAuth2 API according to their documentation/guide, I keep getting 401 Unauthorized responses from https://accounts.google.com/oauth2/v4/token even though I swear I'm giving all the required fields:
POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
User-Agent: curl/7.47.0
Accept: */*
Content-Length: 311
Content-Type: application/x-www-form-urlencoded
client_id=REDACTED
&client_secret=REDACTED
&code=REDACTED
&grant_type=authorization_code
&redirect_uri=https%3A%2F%2Flocalhost%2Fsso%3Fredirect%3D%252F
Response:
HTTP/1.1 401 Unauthorized
Content-Type: application/json; charset=utf-8
Vary: X-Origin
Vary: Referer
Date: Wed, 03 Jul 2019 16:14:15 GMT
Server: scaffolding on HTTPServer2
Cache-Control: private
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
X-Content-Type-Options: nosniff
Alt-Svc: quic=":443"; ma=2592000; v="46,43,39"
Accept-Ranges: none
Vary: Origin,Accept-Encoding
Transfer-Encoding: chunked
{
"error": "invalid_client",
"error_description": "Unauthorized"
}
I've checked and triple-checked my client_id, client_secret, authorized hosts and redirect_uri, and looked through similar problems on stack overflow, but nothing seems to work... why is this happening to me :(
It's because Google's guide/documentation are lying to you. That's not the right endpoint, and instead of saying so, it's giving you that extremely unhelpful error message. Hopefully, they'll be made aware of this SO post/answer and fix it. To find out the actual URL to use to obtain an authorization token, you can click on the "Download JSON" button on your credentials' view page on console.developers.google.com, instead of just copy/pasting the client_id and client_secret. Then you'll get something that looks like this:
{
"web": {
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"client_id": "REDACTED",
"client_secret": "REDACTED",
"javascript_origins": [
"https://localhost"
],
"project_id": "REDACTED",
"redirect_uris": [
"https://localhost/sso?redirect=%2F"
],
"token_uri": "https://oauth2.googleapis.com/token"
}
}
and there you have it. The REAL token URI.

Symfony3 fosrest api method options not allowed

I've got an api build in Symfony 3 with the FOSrestBundle and NelmioCORSBundle.
In my controller i have an method postSaveLotteryAction() which fosrest converts to the route /lotteries/saves/lotteries
Now my ReactJS application uses Axios to make a xhr (ajax) request to the api (that is hosted on a diffrent domain) and because of CORS it first sends out a OPTIONS request.
My apache server is configured correctly with the correct headers as shown below.
The message shown by Symfony is 405 method not allowed. But everything points to the OPTIONS method is allowed.
Access-Control-Allow-Headers: x-requested-with, Content-Type, origin, authorization, accept, client-security-token
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT
Access-Control-Allow-Origin: *
Access-Control-Max-Age: 1000
Allow:
Connection: Keep-Alive
Content-Length: 250
Content-Type: text/html; charset=iso-8859-1
Date: Wed, 11 Apr 2018 07:03:30 GMT
Keep-Alive: timeout=2, max=100
Server: Apache/2
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: nl-NL,nl;q=0.9,en-US;q=0.8,en;q=0.7
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: api.naamloting.nl
Origin: http://beta.naamloting.nl
This is my bin/console d:r output where i've added in the route.yml the GET, OPTIONS, POST methods.
get_lottery GET|POST|OPTIONS ANY ANY /lotteries/{uuid}
get_lottery_stats GET|POST|OPTIONS ANY ANY /lottery/stats
post_lottery_save_lottery GET|POST|OPTIONS ANY ANY /lotteries/saves/lotteries
get_lottery_image GET|POST|OPTIONS ANY ANY /lotteries/{nameOfWinner}/image
get_lottery_ticket GET|POST|OPTIONS ANY ANY /lotteries/{nameOfWinner}/ticket
Also here is my config.yml (partially) so it's clearer to see what maybe causes it.
# Nelmio CORS
nelmio_cors:
defaults:
allow_origin: ['*']
allow_methods: ["POST", "PUT", "GET", "DELETE", "OPTIONS"]
allow_headers: ["content-type"]
max_age: 3600
paths:
'^/lottery': ~
'^/lotteries': ~
# FOS REST Bundle
fos_rest:
body_listener: true
param_fetcher_listener: true
view:
view_response_listener: 'force'
formats:
jsonp: true
json: true
xml: false
rss: false
mime_types:
json: ['application/json', 'application/x-json']
jpg: 'image/jpeg'
png: 'image/png'
jsonp_handler: ~
routing_loader:
default_format: json
include_format: false
format_listener:
rules:
- { path: ^/, priorities: [ json, jsonp ], fallback_format: ~, prefer_extension: true }
exception:
enabled: true
exception_controller: 'fos_rest.exception.controller:showAction'
SOLVED
Looking at the error page it seems to me that Symfony was not the problem and i was correct.
Apache was the troublemaker that didn't allow the OPTIONS method so it always returned an 405 not allowed.
I added the method type and the request is handled correctly.
It seems that sometimes there could be happening a "preflight" OPTIONS request with the real required method in the HEADER.
I see that you allow "PUT" method in nelmio, but not in routes. Try allowing PUT in routes and see if that fixes the problem.
More info:
https://www.html5rocks.com/en/tutorials/cors/

How to set Cache-Control to no-cache in Symfony - FOSHttpCacheBundle

Problem: Hitting back button in browser renders the cached version of the secure page even after logout.
I'm trying to solve this using FOSHttpCacheBundle. Here is my config:
fos_http_cache:
cache_control:
defaults:
overwrite: true
rules:
-
match:
path: ^/
headers:
cache_control: { no_cache: true }
While it is setting the Cache-Control:no-cache, private but there is no Pragma: no-cache and Expires: -1 headers defined which according to docs should be defined.
Here's my Response Headers:
Cache-Control:no-cache, private
Connection:Keep-Alive
Content-Type:text/html; charset=UTF-8
Date:Tue, 03 May 2016 09:03:49 GMT
Keep-Alive:timeout=5, max=95
Server:Apache/2.4.9 (Win64) PHP/5.5.12
Transfer-Encoding:chunked
X-Cache-Debug:1
X-Debug-Token:050e09
X-Debug-Token-Link:/app_dev.php/_profiler/050e09
X-Powered-By:PHP/5.5.12
Someone please explain what am I missing!!
Thanks

Resources