I am using AXIOS from within my app to access the shopify admin api. I am updating a customer with metafields (which, as I understand it, the storefront API does not support with graphql). I am receiving a preflight options error when I do a PUT. The error is a 404. The item I am trying to hit does in fact exist so I am wondering if shopify is mishandling the request or if I am missing something in my configuration.
Note: I am successfully able to do the same request through Postman. Postman is not doing an options preflight as far as I know.
My code:
axios({
method: 'PUT',
url: `https://${SHOPIFY_SHOP}/admin/customers/${decodedId}.json`,
auth: {
username: SHOPIFY_BASIC_AUTH_USERNAME,
password: SHOPIFY_BASIC_AUTH_SECRET,
},
data: {
customer: {
id: decodedId,
metafields: [
{
namespace: 'custom_fields',
key: 'organization',
value: org,
value_type: 'string',
},
{
namespace: 'custom_fields',
key: 'token_pro',
value: isPro,
value_type: 'integer',
},
],
},
},
}).then((data) => {
debugger
}).catch(( error ) => {
debugger
});
The errors
OPTIONS https://SHOP_NAME.myshopify.com/admin/customers/776734343229.json 404 (Not Found)
Failed to load https://SHOP_NAME.myshopify.com/admin/customers/776734343229.json: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:3000' is therefore not allowed access.
Note that the customer does in fact exist at the time of this axios call.
Related
I am currently a CORS issue in my NextJs App. When I run the app on let's say on localhost:3030, and I make an API call to http://some-api.com, I get the following error:
Access to XMLHttpRequest at 'http://some-api.com' from origin 'http://localhost:3030' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header has a value 'http://localhost:3000' that is not equal to the supplied origin.
I added the following lines to the next.config.js.
process.env.NEXT_PUBLIC_SOME_HOST=http://some-api.com
async rewrites() {
return [
{
source: '/api/:path*',
destination: process.env.NEXT_PUBLIC_SOME_HOST + '/:path*'
}
]
},
//avoiding CORS error, more here: https://vercel.com/support/articles/how-to-enable-cors
async headers() {
return [
{
// matching all API routes
source: "/api/:path*",
headers: [
{ key: "Access-Control-Allow-Credentials", value: "true" },
{ key: "Access-Control-Allow-Origin", value: process.env.NEXT_PUBLIC_SOME_HOST},
{ key: "Access-Control-Allow-Methods", value: "GET,OPTIONS,PATCH,DELETE,POST,PUT" },
{ key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" },
]
}
]
},
But it still does not work.
I also attached of the response header on the OPTIONS call.
I can see that the access-control-allow-origin is set to http:localhost:3000 I think if I override that value to localhost:3030 it would work but I am not sure how to do that.
I am pretty new to NextJs, so some help would be greatly appreciated.
Updating the CorsFilter on the Back end API to allow response to http://localhost:3030 solved the problem.
My back end API is written in Spring Boot.
So I added the following:
httpServletResponse.setHeader("Access-Control-Allow-Origin", "http://localhost:3030");
Note: It also possible to allow all with "*"
I am getting mad because as a lodded-in wordpress admin, on the front-end (not in the admin portal), I cannot make post/put requests.
A simple GET AJAX request works perfectly without any type of credentials:
axios.get(this.page.url + "/wp-json/wp/v2/posts").then((resp) => {
console.log(resp.data);
});
BUT, when I try to make post requests I always get 401 error if I do not include the nonce.
If I include the nonce, I get 403. Tried with both AXIOS and JQUERY:
// Axios:
axios.defaults.withCredentials = true;
axios.defaults.headers.post["X-WP-Nonce"] = MYSCRIPT.nonce; // for POST request
axios
.post(this.page.url + "/wp-json/wp/v2/posts", {
title: "title",
content: "content",
status: "publish",
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
// JQUERY
$.ajax({
url: this.page.url + "/wp-json/wp/v2/posts",
type: "post",
data: {
title: "title",
content: "content",
status: "publish",
},
headers: {
"X-WP-Nonce": MYSCRIPT.nonce, //If your header name has spaces or any other char not appropriate
},
dataType: "json",
success: function (data) {
console.info(data);
},
});
The nonce is simply generated with:
<script>
<?php echo 'const MYSCRIPT = ' . json_encode(
array('nonce' => wp_create_nonce('wp-rest'))
); ?>
</script>
I know this is not good practice, and I will include it properly as soon as I get it to work.
The nonce is perfectly retrieved by Javascript, but I get 403 from wordpress...
No idea on how to proceed!
The action specified in wp_create_nonce should be wp_rest (underscore), not wp-rest (hyphen).
https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/
For developers making manual Ajax requests, the nonce will need to be passed with each request. The API uses nonces with the action set to wp_rest
Replace wp-rest with wp_rest and it should work properly.
I want to post multiple logs to DataDog from a JS function, using a single HTTP request. Looking at the v2 docs for DataDog's 'send logs' POST endpoint, it sounds like this is possible:
For a single log request, the API ... For a multi-logs request, the API ...
But it's not clear to me from the docs how to actually send a 'multi-logs' request. I've tried the following:
const dataDogEndpoint = 'https://http-intake.logs.datadoghq.com/api/v2/logs';
const body = {
ddtags: 'env:production,status:info',
hostname: 'my-host',
message: ['My first production log.', 'My second production log.'],
service: 'my-service'
};
const response = await fetch(dataDogEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'DD-API-KEY': apiKey
},
body: JSON.stringify(body)
});
Perhaps unsurprisingly, this appears in DataDog as a single log with the following content:
[My first production log., My second production log.]
How can I achieve this?
Got it - this can be achieved by adding multiple log objects to the body like so:
const dataDogEndpoint = 'https://http-intake.logs.datadoghq.com/api/v2/logs';
const body = [{
ddtags: 'env:production,status:info',
hostname: 'my-host',
message: 'My first production log.',
service: 'my-service'
},{
ddtags: 'env:production,status:info',
hostname: 'my-host',
message: 'My second production log.',
service: 'my-service'
}];
const response = await fetch(dataDogEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'DD-API-KEY': apiKey
},
body: JSON.stringify(body)
});
(You'll probably want a loop instead of instantiating each log object separately.)
I've build a login screen for a headless WordPress project.
I have used Nuxt.js for the front-end and WordPress, with JWT Auth (for token authentication), for the back-end.
Now my login is working. I successfully get the login data I want, but the redirect after this is not working. It also doesn't store the authentication data in the Nuxt.js $auth API.
I'm wondering what I need to do to make this work.
Below my code:
Login page
nuxt.config.js
auth: {
strategies: {
local: {
endpoints: {
login: {
url: 'https://clientsite.test/wp-json/jwt-auth/v1/token',
method: 'post',
propertyName: 'token'
},
user: {
url: 'https://clientsite.test/wp-json/wp/v2/users/me/',
method: 'post',
propertyName: false
},
},
tokenRequired: true,
tokenType: 'JWT',
globalToken: true,
redirect: {
login: '/login',
home: '/home',
logout: '/logout'
}
},
},
},
As you can see in the image above, the credentials are valid and I get the data I want. It just does not store the data and redirect me after this.
What am I doing wrong?
Thanks in advance!
I am building an app for the web hosted on Firebase where I am trying to allow unauthenticated users to upload an image to Storage (after passing a reCAPTCHA).
To do this I have a React website and a Firebase function that validates the reCAPTCHA and then generates a signed URL for the client-side code to upload the image to the default bucket. I have deployed the Function to the cloud because there is no Storage emulator I can use for local development but my React app is being served locally.
The code below omits the usual boilerplate.
Firebase Function Code:
const id = uuidv4()
const bucket = storage.bucket("project-id.appspot.com");
const file = bucket.file(id)
const expires_at = Date.now() + 300000;
const config = {
action: 'write',
version: 'v2',
expires: expires_at,
contentType: 'application/octet-stream'
};
file.getSignedUrl(config, (err, url) => {
if (err) {
console.error(err);
res.status(500).end();
return;
}
res.send(url);
});
This returns a URL to the client of the form: https://storage.googleapis.com/project-id.appspot.com/db9a5cc5-6540-4f40-933f-cfdb287b15a9?GoogleAccessId=project-id%40appspot.gserviceaccount.com&Expires=1594719835&Signature=<signature here>
Client-side Code:
Once this is received on the client-side I try to upload the file to that URL using the PUT method:
// signed_url is the url returned from the first API call to the function above.
// image_file is the file data I get from using react-dropzone.
axios({
method: 'put',
url: signed_url,
data: image_file,
headers: {'Content-Type':'application/octet-stream'}
}).then(res => {
console.log("success");
console.log(res);
}).catch((error) => {
console.log(error);
});
This is where I get a CORS error of the form: Access to XMLHttpRequest at 'https://storage.googleapis.com/project-id.appspot.com/db9a5cc5-6540-4f40-933f-cfdb287b15a9?GoogleAccessId=project-id%40appspot.gserviceaccount.com&Expires=1594719835&Signature=<signature here>' from origin 'http://localhost:3000' 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.
I used cURL to see if the CORS headers in the response were being set and they were not. I then used gsutil cors set config.json gs://project-id.appspot.com to set the CORS permissions on the default bucket. Here is the format of the configuration:
[
{
"origin": ["*"],
"responseHeader": [
"Origin",
"Accept",
"x-goog-resumable",
"Content-Type",
"Access-Control-Allow-Origin",
"Access-Control-Allow-Headers",
"Authorization",
"X-Requested-With"
],
"method": ["GET, POST, PUT, PATCH, POST, DELETE, OPTIONS"],
"maxAgeSeconds": 3600
}
]
I checked the service account to make sure they had the Service Account Token Creator permission and Storage Object Creator permissions set and they did.
I followed the steps at https://cloud.google.com/functions/docs/writing/http#gcloud and I have tried every combination of content-type headers and tried v2 and v4 of getSignedURL version, as well as following any other suggestions I could find online, but to no avail.