I am using next-auth to authenticate users. When I navigate to api routes that don't exist on my NextJS server, I get a 404 response and an error page. I would like to emulate this behaviour when an unauthenticated user navigates to one of my api routes. My current test route looks something like this:
// api/test.js
import { getSession } from 'next-auth/client'
export default async (req, res) => {
const session = await getSession({ req });
if (session) {
// Signed in
res.json(JSON.stringify(session, null, 2));
} else {
// Not Signed in
res.status(404);
}
res.end();
}
Unfortunately, this results in a blank page. Ideally, I would like if an unauthenticated user could not tell the difference between a page that doesn't exist and a blocked api route. I also noticed that when I curl a non-existing route, e.g. curl -i http://localhost:3000/api, I get the following response (as well as all of the html for the error page):
HTTP/1.1 404 Not Found
Cache-Control: no-store, must-revalidate
X-Powered-By: Next.js
Content-Type: text/html; charset=utf-8
Content-Length: 2427
Vary: Accept-Encoding
Date: Thu, 20 May 2021 10:45:45 GMT
Connection: keep-alive
Keep-Alive: timeout=5
When I run curl -i http://localhost:3000/api/test to hit the above code I get the following response:
HTTP/1.1 404 Not Found
Date: Thu, 20 May 2021 10:44:57 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Transfer-Encoding: chunked
How do I modify the response when the user is not authenticated to look (and return the same headers) as the default NextJS 404 error response?
Related
I am working on a code to allow your microservice to retrieve your network’sEdge Cloud Engine linkLocal clustering information as in the mimik's page but after making the HTTP call from curl i am getting the following issue.
starter-microservice\build>curl -i -H "Authorization: Bearer "
http://localhost:8083/localDevices
HTTP/1.1 404 Not Found
Cache-Control: no-cache, no-store, must-revalidate, private, max-age=0
Pragma: no-cache
Expires: 0
Content-Type: text/plain; charset=utf-8
Date: Thu, 14 Jan 2021 07:36:33 GMT
Connection: close
Error 404: Not Found
Not Found
Is the microservice you are trying to call developed by you or is it the starter-microservice found here on mimik github ?
If its your own microservice then you need to call the right endpoint. One of the reasons you're getting 404 is because the endpoint cannot be found. You also need to provide the JWT token you received during edge association using OAuth Tool. You have to put the token right after the words 'Authorization: Bearer YOUR-JWT-TOKEN' in your curl command.
Please follow these tutorials in the order they appear:
https://developer.mimik.com/development-setup/
Once you've finished this please copy the "edge Access Token” this is the
JWT token mentioned earlier.
If you have your own microservice you would like to deploy then you need to follow the instructions here: https://developer.mimik.com/deploying-edge-microservice/ if not then clone this repo from mimik Github and follow the instructions in the README.md
My aim is to run my Quasar app to other devices connected to the Local Area Network. I managed to run them as expected although, when I was logging in to the website, I am having this error POST http://10.0.0.20:8080/MyComposer/?submitId=3 404 (Not Found) despite working
fine on my localhost before. Why is it not reading the Classes in my index.php at the backend folder properly?
P.S. I don't know if this could solve my problem but when I used phpinfo() to debug, I noticed that the REQUEST_METHOD there is GET instead of POST. Is it possible to swap them? I'll try whatever you guys give me.
Console
General
Request URL: http://10.0.0.20:8080/MyComposer/?submitId=3
Request Method: POST
Status Code: 404 Not Found
Remote Address: 10.0.0.20:8080
Referrer Policy: no-referrer-when-downgrade
Response Headers
Connection: keep-alive
Content-Length: 151
Content-Security-Policy: default-src 'none'
Content-Type: text/html; charset=utf-8
Date: Tue, 28 Jul 2020 12:18:12 GMT
Vary: Accept-Encoding
X-Content-Type-Options: nosniff
X-Powered-By: Express
Request Headers
Accept: application/json, text/plain,
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,es;q=0.8
Connection: keep-alive
Content-Length: 49
Content-Type: application/json
Host: 10.0.0.20:8080
Origin: http://10.0.0.20:8080
Referer: http://10.0.0.20:8080/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36
Headers.php
<?php
header('Access-Control-Allow-Origin: http://10.0.0.20:8080/'); //OR EITHER http://10.0.0.20:8080/ OR .$_SERVER['HTTP_ORIGIN']
header('Access-Control-Allow-Credentials: true');
header('Access-Control-Allow-Max-Age: 3600');
if (strtoupper($_SERVER['REQUEST_METHOD']) === 'OPTIONS') {
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD']))
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS");
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
exit(0);
}
store.js
actions: {
LOGIN (context, payload) {
return new Promise((resolve, reject) => {
axios
.post('/MyComposer/', payload, {
headers: { 'Content-Type': 'application/json' },
params: {
submitId: 3
}
})
index.php
<?php
require 'Classes/Headers.php';
require 'vendor/autoload.php';
echo 'Hello!';
phpinfo();
use Classes\SubjectClass;
use Classes\TestClass;
use Classes\AnswerClass;
use Classes\LoginClass;
use Classes\RegisterClass;
use Classes\TeacherClass;
use Classes\StudentClass;
use Classes\AccountClass;
use Classes\AccessClass;
use Classes\SchoolClass;
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$addsubject = new SubjectClass();
$addsubject->addSubject();
$addtest = new TestClass();
$addtest->addTest();
$submitTest = new AnswerClass();
$submitTest->submitTest();
$submitLoginData = new LoginClass();
$submitLoginData->submitLoginData();
$addAccountData = new RegisterClass();
$addAccountData->addAccountData();
$addSchool = new SchoolClass();
$addSchool->addSchool();
}
The problem was caused not by a coding error but due to two webservers being installed on the affected system, a XAMPP installation running on the default port 80 and a Node.Js server running on port 8080.
To diagnose the problem we first copypasted the URL being used in the script into a browser window which gave the same 404 HTTP error. This excluded the option that the axios.post() method caused the behavior.
Next the basic HTTP port assignment was tested. Calling the address http://10.0.0.20 (user's IP inside the local network) gave the correct XAMPP homepage. When checking the httpd.conf and in it the Listen setting (which should have been Listen 8080) we saw the Apache was using the default HTTP port isntead. Changing it to 8080 (as was used in the script) and restarting Apache resulted in the server not starting with the error:
Problem detected! Port 8080 in use by "C:\Program
Files\nodejs\node.exe" with PID 3808! Apache WILL NOT start without
the configured ports free! You need to uninstall/disable/reconfigure
the blocking application or reconfigure Apache and the Control Panel
to listen on a different port.
It was now sure that messed up ports were the cause of the problem. Removing the :8080 from the scripts made sure the requests were sent to the right server.
I have an Angular app running which uses an external api to get countries ISOs.
This API uses https and it's giving me an error.
The thing is: when I use a proxy in my angular local environment, mapping /iso-api/ to the real url it works ok.
"/iso-api/*": {
"target": "https://www...",
"pathRewrite": { "^/iso-api": "" },
"secure": false,
"changeOrigin": true,
"logLevel": "debug"
}
But I want this to work in production, so I want to use the real url.
In my server I am returning the Access-Control-Allow-Origin: * header already.
I've tried to run the angular server with ssl (as the external api uses https), but I receive the same error.
I know a solution would be to implement the proxy in the server, but I believe this should not be done and there may be a way to retrieve this data from the frontend.
Help please.
Response
This is the network error in Chrome:
In Firefox, the request ends with 200 OK and returns data, but CORS error is thrown and I cannot access the data from the app: CORS header 'Access-Control-Allow-Origin' missing
General
Request URL: https://www...
Referrer Policy: no-referrer-when-downgrade
Request headers
:method: GET
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: es-ES,es;q=0.9,en;q=0.8
origin: http://localhost:4200
referer: http://localhost:4200/app/login
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
Response headers
accept-ranges: bytes
cache-control: max-age=0
content-encoding: gzip
content-language: en-US
content-length: 68356
content-type: application/json
date: Mon, 27 Apr 2020 14:49:30 GMT
expires: Mon, 27 Apr 2020 14:49:30 GMT
referrer-policy: strict-origin-when-cross-origin
server-timing: cdn-cache; desc=HIT
server-timing: edge; dur=1
server-timing: ACTT;dur=0,ACRTT;dur=88
set-cookie: ... expires=Mon, 27 Apr 2020 16:49:30 GMT; max-age=7200; path=/; domain=...; HttpOnly
set-cookie: ... Domain=...; Path=/; Expires=Mon, 27 Apr 2020 18:49:30 GMT; Max-Age=14400; HttpOnly
set-cookie: ... Domain=...; Path=/; Expires=Tue, 27 Apr 2021 14:49:30 GMT; Max-Age=31536000; Secure
status: 200
vary: Accept-Encoding
UPDATE
Angular service code
import { HttpClient } from '#angular/common/http';
...
constructor(
private _http: HttpClient,
private _errorUtil: ErrorUtilService,
private _converter: StoreConverter
) {}
...
getCountries(): Observable<CountryWithLanguages[]> {
return this._http.get<GetStoresResponse>(API.storeUrl).pipe(
catchError(this._errorUtil.handle),
map(result => result.stores),
switchMap(stores => stores),
filter(this._isActiveStore),
map(store => this._converter.toView(store)),
toArray()
);
}
To serve the app I use angular dev server, I do not add the 'Access-Control-Allow-Origin' header manually but, in the browser, I see that it is being added.
angular.json
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "push-web-app:build",
"proxyConfig": "src/proxy-local.conf.json"
},
}
You can't request a resource from another domain. This would be a security hole. You can read more here: Same-origin policy
Sending Access-Control-Allow-Origin: * from your server won't give you access to the aforementioned API. The provider of this API needs to give you permission to access the API, you can't give yourself this permission.
The error you posted states that the Access-Control-Allow-Origin header is missing. It means that the API isn't sending this header.
There might be two reasons why this API isn't sending Access-Control-Allow-Origin header.
A misconfiguration on the side of this API. In this case you have to ask the provider of this API to fix this issue.
The API provider is restricting access to the API on purpose. In this case you have to ask the provider of this API to give you access from your domain.
You can also proxy the request through your server. The core difference when using proxy is that your server reads the resource from the API and not the client browser. See David's response on how to configure proxy with nginx.
You cannot bypass CORS browser side. If you are not able to modify the server side, your only solution is to use a proxy.
For development purposes, you can use angular's built-in proxy server, but not for production.
Here is a basic nginx config to do this
server {
listen 80;
server_name yourdomain.com; #domain where your angular code is deployed
location /iso-api{
RewriteRule ^/iso-api/(.*)$ /$1 break;
proxy_pass https://thirdpartyapidomain.com; #url of the API you are trying to access
}
location
{
#Your normal angular location
#try_files ...
}
}
This will redirects requests like
http://yourdomain.com/iso-api/countriesList to https://thirdpartyapidomain.com/countriesList;
Since now client and server API calls are on the same domain, you should not have CORS issues
Use this site to resolve the CORS error:
https://cors-anywhere.herokuapp.com/
Use Exemple
https://cors-anywhere.herokuapp.com/https://freegeoip.app/json
this._http.get('https://cors-anywhere.herokuapp.com/https://freegeoip.app/json')
It's just a workaround but it works. Use it even just to understand if the error is related to CORS or something else.
Try the .get call with option withCredentials: true:
return this._http.get<GetStoresResponse>(API.storeUrl, { withCredentials: true }).pipe();
...and/or making sure your browsers are up to date.
I'm working on the React + Express + mongo project.
Everything works locally, but when I deployed project on heroku.com, a problem appeared with GET requests.
It returns 304 and instead of body JSON, i'm getting this error:
To run this application, you need to enable JavaScript.
Instead of json response, I'm getting HTML response with this information about JS. In body I should get normal data JSON that I display on the page.
I will write again, everything WORKS locally ( i get 200 and json response), I don't know what's going on with this heroku.
I thought that problem is 304 code, so I used middleware that disables cache (no-cache), the result is 200, but there is still no body.
REQUEST ON CHROME NETWORK
GENERAL:
Request URL: MYURL.com/...
Request Method: GET
Status Code: 200 OK
Remote Address: 34.255.19.16:443
Referrer Policy: no-referrer-when-downgrade
RESPONSE HEADERS::
Accept-Ranges: bytes
Access-Control-Allow-Origin: *
Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate
Connection: keep-alive
Content-Length: 2366
Content-Type: text/html; charset=UTF-8
Date: Fri, 01 Nov 2019 13:54:09 GMT
Etag: W/"93e-16e271de930"
Expires: 0
Last-Modified: Fri, 01 Nov 2019 13:18:22 GMT
Pragma: no-cache
Server: Cowboy
Surrogate-Control: no-store
Via: 1.1 vegur
X-Powered-By: Express
REQUEST HEADERS:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: pl-PL,pl;q=0.9,en-US;q=0.8,en;q=0.7
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYTZkNjZhYTExYWI5MTM3MDU1MTY2OCIsIm5hbWUiOiJGaWxpcCIsImlhdCI6MTU3MjYxNjQ0MiwiZXhwIjoxNTcyNjIwMDQyfQ.c4uPda0njISa3VWNX0kK5cPRVW2X6A3wBNnt5hc5N-k
Connection: keep-alive
Content-Type: application/json
Cookie: AUTHORIZATION_JWT=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkYTZkNjZhYTExYWI5MTM3MDU1MTY2OCIsIm5hbWUiOiJGaWxpcCIsImlhdCI6MTU3MjYxNjQ0MiwiZXhwIjoxNTcyNjIwMDQyfQ.c4uPda0njISa3VWNX0kK5cPRVW2X6A3wBNnt5hc5N-k
Host: dashboard-pwa.herokuapp.com
Referer: https://dashboard-pwa.herokuapp.com/tickets/show/5dbb2310f67d543c84053a79
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36
I want to get 200 with JSON body response.
adam tropp thank you! It helped me a lot. It turns out that i had redirect to client index.html in wrong place, it should be placed after routes declaration, not before (just like I had before).
file server.js:
app.use('/api/user', require('./routes/user'));
// For any request that doesn't
// match one above, send back React's index.html file.
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname+'/client/build/index.html'));
});
Thanks, once again.
I have a local environment and I'm trying to login to a service. I'm using the 'request' library in the client and Express and express-session in the service.
I'm using Chrome and when I login to the service I get the following response headers:
FROM: http://app.dev:3000
TO: http://app.dev:4000/login/local
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: http://app.dev:3000
Vary: Origin, X-HTTP-Method-Override
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
Content-Length: 304
ETag: W/"130-fdQBs605dSVTeEqXEuXrvdcQTLk"
set-cookie: auth=TOKEN; Path=/; Expires=Sun, 25 Jun 2017 01:48:41 GMT
Date: Sat, 24 Jun 2017 13:48:41 GMT
Connection: keep-alive
When I login with Postman the cookie gets stored correctly. Subsequent requests through Postman include the cookie and everything is working fine.
But doing the same request with the npm request library it won't save the cookie and subsequent requests to the backend do not include cookies. Example request to the service after logging in. No cookie sent.
The request library documentation doesn't mention the withCredentials option but setting it to true fixes the issue. The cookie now gets saved and is being sent on subsequent requests.
const requestBase = request.defaults({
baseUrl: 'http://app.dev:4000/',
withCredentials: true,
});