Azure Search API throws CORS error even when CORS is enabled - api

I have an Azure search index called users that has CORS configured to * (for now) to allow all origins. When I make a GET request to it programmatically using fetch or axios, I get a CORS error:
Access to XMLHttpRequest at 'https://MY_SEARCH_SERVICE.search.windows.net/indexes/users/docs?api-version=2021-04-30-Preview&%24top=5&search=matt*&%24searchFields=name&%24select=id%2Cname%2Cemail&api-key=MY_API_KEY' from origin 'http://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource
However, if I put the same GET URL into a browser, it returns the list of expected results with no errors.
Here's my code (to run, create a Svelte app and put this in App.svelte or use the Svelte REPL. You must also have an Azure Search service set up, and you'll need to replace the placeholder variables MY_SEARCH_SERVICE and MY_API_KEY with your own, along with an index on which you want to try this):
<script lang="ts">
import { onMount } from "svelte";
const service = "https://MY_SEARCH_SERVICE.search.windows.net";
const index = "users";
const endpoint = `${service}/indexes/${index}/docs`;
const params = new URLSearchParams({
"api-version": "2021-04-30-Preview",
"api-key": "MY_API_KEY",
"$top": "5",
"$searchFields": "name,email",
"$select": "id,name,email"
});
const headers = new Headers({
"accept": "application/json"
});
onMount(async () => {
console.log(`${endpoint}?${params}`);
const response = await fetch(`${endpoint}?${params}`, {
headers: headers
});
console.log(await response.json());
});
</script>

Related

CORS header ‘Access-Control-Allow-Origin’ missing on response in addon but not on request

I am creating a Firefox extension which posts some data to a database.
I made all parts in a modular fashion and am now combining everything piece by piece.
As such I know that my code to POST data to the database works.
Now here is the part that stumps me :
When I then add this code to my firefox extension
I get the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:3003/timed_shot_create. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 400.
Now ofcourse CORS was nothing new and to be expected when dealing with Cross Origin Resource Sharing, it is even in the name.
But the reason why I am here is because this pertains only to the response of the POST request. The request itself is fine and allowed with the following piece of config in the server:
app.use(
cors({
//todo change to proper origin when live
origin: "moz-extension://d07f1e99-96a0-4934-8ff4-1ce222c06d0d",
method: ["GET", "POST"],
})
);
Which was later changed to:
app.use(
cors({
origin: "*",
method: ["GET", "POST"],
})
);
And then simplified even more to:
app.use(cors())
This is in Nodejs btw using cors middleware.
But none of this seems to work when it is used inside a firefox extension, as a local client page works as intended but as soon as I add this to a firefox extension I get a CORS error specifically pertaining to the reponse message.
The client side post (in the background script of the extension) is:
async function postTimedShot(post_options) {
const response = await fetch(post_endpoint, post_options);
//console.log(response);
const json_response = await response.json();
console.log(json_response);
}
let post_options = {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(response_data),
};
postTimedShot(post_options);
And the api looks like this:
app.post("/timed_shot_create", (req, res) => {
console.log("Received POST request");
const data = req.body;
console.log(data);
const timeStamp = data.time_stamp;
//TODO add screenshot and Description text maybe??
//const lastName = data.last_name
const queryString =
"INSERT INTO " + timed_shots_database + " (time_stamp) VALUES (?)";
getConnection().query(queryString, [timeStamp], (err, results, fields) => {
if (err) {
console.log("Failed to insert new user: " + err);
res.sendStatus(500);
return;
}
//Todo change this message when adding more data in body
//res.header("Access-Control-Allow-Origin", "moz-extension://d07f1e99-96a0-4934-8ff4-1ce222c06d0d");
res.json({
status: "Success!!!",
time_stamp: timeStamp,
});
console.log("Inserted a new user with id: ", results.insertId);
});
});
Furthermore, this extension is only for personal use and will work with a local server under my complete control so complications due to security or cloud usage that people want to mention are appreciated but not necessary (I think, I am a bit of novice).
I will be happy to clarify anything that is unclear, or change this post if necessary, but I think it is a unique question as far as I could see on SO. Additionally if I need to provide more of the codebase I will.
I will also update this post if I find out more about this problem.
Thank you for reading :3.
After reading about this post https://stackoverflow.com/a/53025865/5055963
on SO I found out that it had to do with the permissions in the manifest of the extension.
Adding this line: "://.localhost/*".
Solved the issue for me.

Why am I getting 3 "Cross-Origin Request Blocked" messages

I have a Svelte application and I am trying to render data from the API but I keep on getting 3 error messages.
The code works properly on node but not on Svelte.
Below is the Svelte code:
<script lang="ts">
import { onMount } from "svelte";
let word = [];
onMount(async () => {
const response = await fetch(
"https://random-words5.p.rapidapi.com/getMultipleRandom?count=1&wordLength=5",
{
method: "GET",
headers: {
"X-RapidAPI-Key": "KEY",
"X-RapidAPI-Host": "random-words5.p.rapidapi.com",
},
}
);
word = await response.json();
console.log(word);
});
</script>
<p>{word}</p>
And below are the error messages:
ross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://random-words5.p.rapidapi.com/getMultipleRandom?count=1&wordLength=5. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘https://localhost:5173’).
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://random-words5.p.rapidapi.com/getMultipleRandom?count=1&wordLength=5. (Reason: CORS request did not succeed). Status code: (null).
Uncaught (in promise) TypeError: NetworkError when attempting to fetch resource.
How do I get my code to render out the data from the API in Svelte?
The CORS issue occurs when you try to fetch a resource from a local environment, this is the case when you run your app in dev mode.
I use the CORS Unblock extension to fix the issue, give it a try.

How can I download a file from frontend with Authorization Header

Here is my backend code. It has 2 protected routes. Authorization Header is needed (Bearer token).
These routes allows you to download your photo and your cv.
I have no issue with my backend. It is working with postman and mobile applications. I think there is a limitation for frontend.
I do NOT want
I don't want to use fetch to download these files as blob. Because it doesn't allow to browser to show its progress bar.
I don't want to change my authentication method from Bearer token to cookie. I can already do this with cookie.
I wonder why Bearer token is more popular than cookie If I have to use cookie to make this happen.
Backend
// other imports .....
const path = require('path');
const fs = require('fs');
const express = require('express');
const app = express();
app.use((req, res, next) => {
try {
const token = req.get('Authorization');
if(!token) {
throw new Error('401');
}
const userId = getIdFromToken(token);
if(!userId) {
throw new Error('401');
}
res.locals.userId = userId;
next();
} catch (error) {
next(error);
}
})
app.get('/api/me/photo', (req, res) => {
const userId = res.locals.userId;
const imagePath = path.resolve(process.env.DISC_PATH, 'images', `${userId}.png`);
res.attachment('me.png');
res.set('Content-Type', 'image/png');
const stream = fs.createReadStream(imagePath);
res.pipe(stream);
})
app.get('/api/me/cv', (req, res) => {
const userId = res.locals.userId;
const pdfPath = path.resolve(process.env.DISC_PATH, 'cv', `${userId}.png`);
res.attachment('my-cv.pdf');
res.set('Content-Type', 'application/pdf');
const stream = fs.createReadStream(pdfPath);
res.pipe(stream);
})
...
// error handling, etc...
Frontend
<html>
<body>
<!-- How can I send the Authorization header here -->
<img src="/api/me/photo" />
<!-- How can I send the Authorization header here -->
Download My CV
<!-- How can I send the Authorization header here -->
<button id="btn"> Download My CV (V2) </button>
<script>
const btn = document.getElementById('btn');
btn.addEventListener('click', () => {
// How can I send the Authorization header here
window.open('/api/me/cv');
});
</script>
</body>
</html>
I wonder why Bearer token is more popular than cookie If I have to use cookie to make this happen.
One advantage of an Authorization: Bearer header over cookie-based authentication is precisely that the browser does not automatically include the header in a request to the given URL. So you cannot be tricked into clicking on a link that would trigger an authenticated request that you did not intend.
In other words: With Authorization: Bearer as authentication mechanism you are safe from "cross-site request forgery" (CSRF) attacks.
Backends that use cookie-based authentication have to implement extra countermeasures against CSRF.
For your problem, this means that the two don't go together. If you want the convenience of a "normal" browser request (with its progress bar), you expose the user to CSRF, unless you take said countermeasures. (This may not be a serious threat if the request only downloads something. But an attacker could at least measure the running time of the CV download request and deduce something from that.)
Possible workaround:
Implement an API (authenticated with Authorization: Bearer header) that generates a download URL which includes a short-lived token, and have the browser download the desired document with a normal request to that URL. The second request is technically unauthenticated, but the token makes the URL unguessable.
If the token is a JWT, you need not even store it on your server but can simply write the username and expiry time in it and sign it with the server's private key. If you prefer you can also put the token in a cookie rather than in the URL.

Get shopify admin endpoint in axios in vue

How do you do this?
Use Admin API from Frontend(Headless Commerce) to get products from Shopify
<template>
<div>{{ data }}</div>
</template>
<script>
import axios from 'axios';
export default {
name: 'ShopifyResult',
data () {
return {
data: null
}
},
mounted () {
const url = 'https://a-shopify-store.myshopify.com/admin/api/2021-10/checkouts.json';
axios({
method:'get',
url,
headers: {
"Content-Type": "application/json",
"X-Shopify-Access-Token": 'API_ADMIN_ACCESS_TOKEN_HERE',
},
}).then((result) => {
console.log(result.data)
}).catch(error => {
console.log(error)
});
}
}
</script>
This is what I get:
Access to XMLHttpRequest at
'https://a-shopify-store.myshopify.com/admin/api/2021-10/checkouts.json'
from origin 'http://localhost:8080' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. ShopifyResult.vue?4048:27 AxiosError
Why is CORS involved? I have a all the appropriate keys. How do you do this?
I also found
https://community.shopify.com/c/technical-q-a/vue-axios-get-requests-how-to-secure-apikey-and-apipass/td-p/689016
no answers.....
https://community.shopify.com/c/shopify-apis-and-sdks/using-apis-from-a-different-origin-domain/td-p/502781
Think of it this way:
Storefront API is a public API and the token for it is meant to be
used on the client side.
Admin API is a private API and the token is not meant to be shared
publicly. If you share this token to everyone by making requests from
the browser, they can potentially access private information about
your store, financial information, CUSTOMER information etc.
This could lead to both inconvenience to your customers as they would
be subject to fraud as well as you could run into legal issues if
someone decides to sue you because of it.
Hence, Shopify throws a CORS error when detecting that you use a
browser to send a request to a private API. While the CORS error might
not be the most appropriate response here, it is valid for them to
deny your request.
Hope that clarifies the issue for others encountering this error.

How to retrieve form-data values in Express js?

I created a form data in Postman and send a http post request. but when I send the request, it shows there is no form data in the destination!
here is my codes in backend :
app.js file:
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
var routesImagesApi = require('./api/routes/imagesrouters');
app.use('/api/images', routesImagesApi);
api/routes/imagesrouters.js file:
var router = express.Router();
var ctrlAuth = require('../controllers/images');
router.post('/imageUpload', ctrlAuth.imageUpload);
controllers/images.js file:
module.exports.imageUpload = function (req, res) {
res.status(200);
res.json({"Returned data":req.body});
}
I created a request in postman with two key-value form-data body.
here is my request:
POST > http://localhost:3000/api/images/imageUpload
and form-data body key-values are these :
key:name , value:Sarah
key:family , value:Thomas
Below image is Postman screenshot :
I expected postman show me the form-data key values but as you can see it shows nothing!
{
"Returned data": {}
}
Do you have any idea?
Please use the multer package or you could write a custom handler for making express handle multi part form data i.e "files/imgs..etc "
multer package
and
writing your own custom handler
p.s this could be a duplicate issue