I have a nextjs webapp with serverless functions that run behind ssl certificates, I want to treat the nextjs webapp as an interface to a hasura graphql query and subscription API that is not running with ssl.
I figure nextjs serverless functions would be a good way to go, I have already used it to forward requests like so: http.get('http://yoururl.com', response => response.pipe(res)).
However I can't work out a way to do this for post/subscriptions, there's a http.request function but that doesn't support body params and I'm even less sure about forwarding websocket connections.
I tried to just forward the request as a fetch but had issues with the header mismatching:
export default async (req: NextApiRequest, res: NextApiResponse) => {
return fetch({
method: 'POST',
url: 'http://myurl.com/v1/graphql',
headers: req.headers,
body: req.body
})
}
Related
when I run the following code from the client side in javascript as the coinbase cloud documentation says https://docs.cloud.coinbase.com/exchange/reference/exchangerestapi_getcoinbaseaccounts
const options = {
method: 'GET',
headers: {
Accept: 'application/json',
'cb-access-key': 'Apikey',
'cb-access-passphrase': 'Mypassphrase',
'cb-access-sign': cb_access_sign,
'cb-access-timestamp': cb_access_timestamp
}
};
fetch('https://api.exchange.coinbase.com/coinbase-accounts', options)
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.error(err));
when I do it with axios the same thing happens
the following error appears in console: "Access to fetch at 'https://api.exchange.coinbase.com/coinbase-accounts' from origin 'http://localhost:3000' has been blocked by CORS policy: Request header field cb-access-passphrase is not allowed by Access-Control-Allow-Headers in preflight response."
what am I doing wrong?
You can't do this in the browser, you need to do it from the web server. You can either display the data when the page loads or use vue/react and write your own interaction with the webserver.
edit: doing this in the browser makes your keys visible...
Coinbase API has misconfigured CORS (or intentionally require you to make API calls from a server). Regardless, this makes it very hard to test in a dev environment. This can be solved using a proxy. This can be configured using cors-anywhere which changes the api call flow from:
Client (localhost:3000) <-> Coinbase API (api.exchange.coinbase.com)
to
Client (localhost:3000) <-> Proxy Server (www.your-proxy-server.com) <-> Coinbase API (api.exchange.coinbase.com)
In summary, coinbase will only see a request coming from your proxy server and does not care/know where the proxy server sends back the data. Cors-anywhere will also include the headers and data along with the request.
Do not use public cor-anywhere servers unless you are quickly testing something. It is best to set up your own.
Using Firebase
I used cors-server to set mine up using firebase functions. You want your Firebase functions to look like the following:
const {onRequest} = require("firebase-functions/v2/https");
const corsAnywhere = require('cors-anywhere');
const cors = require("cors")({origin:true})
const corsServer = corsAnywhere.createServer({
originWhitelist: [
'http://localhost:3000',
],
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: ['cookie', 'cookie2'],
});
exports.proxy = onRequest((request, response) => {
cors(request,response,() =>{
corsServer.emit('request', request, response);
})
});
and an example of a request in your client code
return(
axios({
url: `https://proxy-your-function-id.a.run.app/https://api.exchange.coinbase.com/profiles`,
headers: await getHeaders(options),
method: 'GET',
data: options.body
}).then((response)=>{
return(response)
}).catch((err)=>{
return(err.response)
})
)
Edit: It should also be noted that Coinbase is getting rid of Coinbase Pro and its API end of 2022. Coinbase exchange and its API will still be available at https://api.exchange.coinbase.com however Pro users will be merged into Advanced Trading on their main platform which uses oAuth to link the API (or standard keys for personal projects).
I'm trying to work on a Nuxt SSR frontend that uses a Django backend with Session Authentication.
I would like to have some SSR pages as well as client rendered pages in my frontend, so i'm using Universal mode.
The problem is that i did not find a working approach to check if a user is authenticated before loading a page, so i can't restrict pages to anonymous users. In order to check if a user is authenticated, Django will check if the request's headers contain a cookie, and according to that return if the user is authenticated or not.
Here is what i tried:
1) Middleware
export default async function ({context, redirect}) {
axios.defaults.withCredentials = true;
return axios({
method: 'get',
url: 'http://127.0.0.1:8000/checkAuth',
withCredentials: true,
}).then(function (response) {
//Redirect if user is authenticated
}).catch(function (error) {
console.log(error)
});
}
Here i'm sending a request to my backend to check if the user is authenticated. The problem is that the middleware is executed from server side, which means there will never be any cookie in the request, even if the user is authenticated. This means that every time i refresh the page, according to the middleware the user is always anonymous, even when the user is authenticated.
2) Plugin
export default function (context, inject) {
if (process.client){
console.log('client')
return axios({
method: 'get',
url: 'http://127.0.0.1:8000/checkAuth',
withCredentials: true,
}).then(function (response) {
//IF AUTHENTICATED, REDIRECT
context.redirect('/')
}).catch(function (error) {
console.log(error)
});
} else {
console.log('server')
}
}
Here i'm trying the same but with a plugin, and i'm "forcing" the plugin to check if the user is authenticated on the backend only when the plugin executes from client side. This works, cookies are sent in the headers and Django receives the cookie, but the problem with this solution is that Nuxt doesn't allow redirecting to other pages from a plugin (https://github.com/nuxt/nuxt.js/issues/4491).
3) Using beforeMount() in Vue
I tried to do that using beforeMount() from my Vue pages, but the problem is that since it will execute AFTER idration, the page will be loaded and after 1/2 seconds the redirect happens, which is kind of ugly.
Is it possible that there isn't a way to do this? Any kind of advice is appreciated
EDIT: the problem is not that i don't know how to code this, the problem is that when Nuxt sends a request to my backend from the server side middleware, the request will not contain any cookie, and because of this my Django backend cannot check the session cookie, which means that the backend cannot check whether or not the user is authenticated. The same code works when the middleware is executed from client side (if i navigate directly to the page instead of refreshing), because the request will contain the cookies.
I'm trying to understand if this is normal or not, but this could be an issue with Nuxt.
I know this a year old question and it was probably about nuxt 2, now nuxt 3 is out and running and I found my self with the same problem and here is how I solved it, just in case someone stumble here just like I did.
With Nuxt 3 server side you can use useFetch with the options headers: useRequestHeaders(['cookie'])
const { data, error, pending, refresh } = await useFetch(api.auth,
{
credentials: "include",
headers: useRequestHeaders(['cookie'])
}
);
There are a few issues you need to be aware of:
_ The cache, if you perform the same request with the same parameters it will return the same cached response (it won't even call the end point API). Try to use the key option with different values or the returned refresh method and check the doc "Data fetching" for more info.
_ The cookies, any cookie generate server side won't be shared with the client side, this means if the API generate a new token or session cookie on server side the browser won't receive those cookies and may generate new ones, this may get you in some 400 - bad request if you use session with CSRF, check this issue for more info.
I do have a working middleware with this
export default ({ redirect, store }) => {
if (store?.$auth?.$state?.loggedIn) {
redirect('https://secure.url')
} else {
redirect('https://login.please')
}
})
I have a user authentication server setup using Express and Node.js in my localhost Port 3333 and I am trying to connect to the endpoint in Next.js port 3000 using isomorphic-unfetch for the fetch. I am getting a CORS 401 error, I have done a fair bit of research already but just wanted to know whether it was possible connecting to a Express server on localhosts? I have tried adding "Access-Control-Allow-Origin": "*", "Content-Type": "multipart/form-data" to a header object. The express server has cors setup already.
This function below is called on click of a button.
onLoginClick = async () => {
let header = new Headers({
"Access-Control-Allow-Origin": "*",
"Content-Type": "multipart/form-data"
});
const res = await fetch("http://localhost:3333", {
method: "POST",
header,
body: JSON.stringify({
username: "USER",
password: "PASSWORD"
})
});
}
Error message -
http://localhost:3333/ 401 (Unauthorized)
Response {type: "cors", url: "http://localhost:3333/", redirected: false, status: 401, ok: false, …}
First of all, CORS is configured on the server side. You configure your server to allow calls from specific origins.
In your code, onLoginClick is a client-side code, it runs on the browser, client cannot decide which origin the server should allowed to, that would defeat the purpose of having CORS.
Usually you don't need to change the cors configuration in a Next.js app, because you would be calling the API from the same origin that hosted the client side app.
By default, Next.js only support same-origin for API Routes, if you need to customize it, you can use micro-cors.
I had a small node server and I use the framework fastify.
In one of my routes, I want to get the data from a third party API.
I tried the following snippet:
fastify.route({
method: 'GET',
url: 'https://demo.api.com/api/v2/project/',
handler: async function ({ params, body}, reply) {
if (!body) return reply.send({ sucess: false })
console.log('testing')
console.log(body)
return reply.send({ sucess: true })
}
})
Unfortunately, I cannot call the URL by get because GET url's can only start with '/'.
How do i call a third pary api via fastify? do i need a extention?
If you need to define a route (like http://localhost:3000/) that proxies another server you need to use fastify-http-proxy.
Or if you need to call another endpoint and manage the response, there is the fastify.inject() utility but it is designed for testing.
Anyway, I think the best approach is to use some HTTP client like got
const got = require('got') // npm install got
fastify.get('/my-endpoint', async function (request, reply) {
const response = await got('sindresorhus.com')
console.log(response.body)
// DO SOMETHING WITH BODY
return { sucess: true }
})
Proxy your http requests to another server, with fastify hooks.
here is the example in fastify-http-proxy
server.register(require('fastify-http-proxy'), {
upstream: 'http://my-api.example.com',
prefix: '/api', // optional
http2: false // optional
})
https://github.com/fastify/fastify-http-proxy/blob/master/example.js
I am using the below code to get the customer details from shopify. I have redirected my domain to the other domain from the shopify admin.
function setEmailWithLoggedInUser(callback) {
$.ajax({
url: 'https://new-website-shopify.myshopify.com/admin/customers/'+__st.cid+'.json',
crossDomain: true,
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", "Basic XXXXXXXXXXXX")
}, success: function(data){
console.log(data);
if(callback)
callback();
}
})
I have done a lot of work around but unable to find the solution.
I am getting this error:
Failed to load resource: the server responded with a status of 404
(Not Found)
XMLHttpRequest cannot load
https://new-website-shopify.myshopify.com/admin/customers/7094124372.json.
Response to preflight request doesn't pass access control check:
No 'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://www.beirutshopping.com' is therefore not
allowed access. The response had HTTP status code 404.
I will save you some headaches with this answer. You cannot call /admin from the front-end of a store, as that exposes your access token to the public. Instead, if you want to access the API from the front-end, use the App Proxy pattern, allowing you to securely make Ajax calls to accomplish your goals.
As it is, you are almost certain to fail, and any success you hack into existence will quickly expose your shop to horrors. Like being replaced with sad pandas, or otherwise being reckd.
var cors = require('cors');
router.use(cors({
origin: '*'
}));
//var config = require('../config/config.json');
//testing /* GET home page. */
router.get('/', function (req, res, next) {
res.setHeader("Content-Type", "application/liquid");
res.setHeader("Access-Control-Allow-Origin", "*");
res.render('index', {
title: 'Store Locator'
});
});