firebase auth rest api not returning the full body response in arduino ide - c

i've been stuck in a problem with firebase auth rest api in arduino ide, the following code returns code 200
String url = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" + String(apiKey);
http.setTimeout(5000);
http.begin(url);
http.addHeader("Content-Type", "application/json");
String dataSent = "{\"email\":\"" + String(email) + "\",\"password\":\"" + String(pswd) + "\",\"returSecureToken\":\"true\"}";
int status = http.POST(dataSent);
Serial.println(status);
if (status <= 0)
{
Serial.printf("HTTP error: %s\n",
http.errorToString(status).c_str());
return false;
}
// Read the response.
String payload = http.getString();
Serial.println(payload);
but when i look in my serial monitor the response looks like this:
{
kind: "the kind of response",
localId: "someId",
email: "myEmail",
displayName: "myDisplayName",
idToken: "someIdToken",
registered: "someBoolean",
}
witch aparently is ok but when i try the same http request in postman the response includes also refreshToken and expiresIn
with even more investigation i found that localId from postman is about 980 characters while the localId from my arduino code is only about 680
im trying (and failing) to use the localId to authenticate a request with the firestore api and i think this difference in lenght is what's been buggingme.
could that really be the problem ?

method: "POST",
body: JSON.stringify({
email: enteredEmail,
password: enteredPassword,
returnSecureToken: true,
}),
headers: {
"Content-Type": "application/json",
},
})
NB: Make sure {returnSecureToken: true} is part of your request body

Related

Access a remote api from frontend react.js without any server side code

I am trying to access remote url from fetch/axios post api in react.js. Here is my code in react-
const requestOptions = {
method: 'POST',
crossDomain: true,
mode: 'cors', // no-cors, *cors, same-origin
credentials: 'same-origin', // include, *same-origin, omit
headers:{'Content-Type': 'application/x-www-form-urlencoded',
"Access-Control-Allow-Origin": "*",
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'GET,POST,OPTIONS,DELETE,PUT'},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer',
body:new URLSearchParams({
'store_id':'storeid',
'store_passwd':'storepass',
'total_amount':100,
'currency':'BDT',
'tran_id':'NF04',
'success_url':"https://tigrow.herokuapp.com",
'fail_url':"https://tigrow.herokuapp.com",
'cancel_url':"https://tigrow.herokuapp.com",
'cus_name':"nizam",
'cus_email':"test#test.com",
'cus_add1':"customer address",
'cus_add2':"customer address",
'cus_city':"Dhaka",
'cus_state':"Dhaka2",
'cus_postcode':"Dhaka",
'cus_country':"Bangladesh",
'cus_phone':"01700000000",
'cus_fax':"01700000000",
'ship_name':"Sha",
'ship_add1':"dhaka",
'ship_add2':"dhaka1",
'ship_city':"Dhaka1",
'ship_state':"Dhaka2",
'ship_postcode':"1000",
'ship_country':"Bangladesh",
'multi_card_name':"mastercard,visacard,amexcard",
'value_a':"ref001_A",
'value_b':"ref002_B",
'value_c':"ref003_C",
'value_d':"ref004_D",
'shipping_method':"No",
'product_name':"Test",
'product_category':"Test Category",
'product_profile':"general"
})
};
fetch(url, requestOptions)
.then(response =>console.log(response))
.then(data => console.log(data));
I want to get data from rempte api in react only, not any server side code. Here my content-type is application/x-www-form-urlencoded. How can I solve this problem only using react.js?
My remote API strictly mentioned that no call from client side code. Developer must need to call the API from server side and after completing the call developer should return the string url, not any json data. I followed the way and done the code in python and got the result. However my frontend was react. Here is the code snippet-
def sslcommerz_payment_gateway(request):
gateway_auth_details = PaymentGatewaySettings.objects.all().first()
settings = {'store_id':gateway_auth_details.store_id,
'store_pass': gateway_auth_details.store_pass,
'issandbox': True} #gateway_auth_details.store_pass, 'issandbox': False}
print(request.POST)
sslcommez = SSLCOMMERZ(settings)
post_body = {}
post_body['total_amount'] =request.POST.get('total_amount')
post_body['currency'] = request.POST.get('currency')
post_body['tran_id'] =unique_transaction_id_generator()
post_body['success_url'] = 'http://127.0.0.1:8000/api/payment/success/'
post_body['fail_url'] = 'http://127.0.0.1:8000/api/payment/faild/'
post_body['cancel_url'] = request.POST.get('cancel_url')
post_body['emi_option'] = 0
post_body['cus_name'] = request.POST.get('cus_name')
post_body['cus_email'] =request.POST.get("cus_email")
post_body['cus_phone'] = request.POST.get("cus_phone")
post_body['cus_add1'] = request.POST.get("cus_add1")
post_body['cus_city'] = request.POST.get("cus_city")
post_body['cus_state'] =request.POST.get("cus_state")
post_body['cus_postcode'] =request.POST.get("cus_postcode")
post_body['cus_country'] = request.POST.get("cus_country")
post_body['shipping_method'] ="NO"#request.POST.get("shipping_method")
post_body['multi_card_name'] = "mastercard,visacard,amexcard,mobilebank,internetbank,othercard"
post_body['num_of_item'] = request.POST.get("num_of_item")
post_body['product_name'] = request.POST.get("product_name")
post_body['product_category'] = request.POST.get("product_category")
post_body['product_profile'] = "Art(Hard Copy/Soft Copy)"
response = sslcommez.createSession(post_body)
print(response)
return 'https://sandbox.sslcommerz.com/gwprocess/v4/gw.php?Q=pay&SESSIONKEY=' + response["sessionkey"]
Finally I got the API response and returned a url.

How can I associate an Alexa skill with a catalog?

I am trying to associate my Alexa skill with a catalog that I created by hitting the https://api.amazon.com/v0/catalogs endpoint with an Auth token that I had generated through a LWA profile.
This worked, and I created a catalog like so:
{
associatedSkillIds: [],
createdDate: '2022-01-22T20:50:37.318Z',
id: 'amzn1.ask-catalog.cat.[REDACTED]',
lastUpdatedDate: '2022-01-22T20:50:37.318Z',
title: 'TestCatalog',
type: 'AMAZON.AudioRecording',
usage: 'AlexaTest.Catalog.AudioRecording'
}
However, the next step, associating my Alexa skill with the Catalog is always returning 401 https://developer.amazon.com/en-US/docs/alexa/smapi/catalog-content-upload.html#associate-catalog-with-skill
This is my function to attempt to associate the skill with the catalog:
async associateSkillWithCatalog() {
console.log(`Associating skill...`);
const accessToken = await this.getRefreshToken(); // makes post to https://api.amazon.com/auth/o2/token
console.log(this.alexaEndpoint + this.skillAssoc(cat.id, skillId));
const response = await axios.put(
"https://api.amazonalexa.com/v0/skills/amzn1.ask.skill.[REDACTED]/catalogs/amzn1.ask-catalog.cat.[REDACTED]",
{
headers: {
'Content-type': 'application/json',
'Authorization': `Bearer ${accessToken}`
}
}
);
return response.data;
}
Always receiving back this Error: Request failed with status code 401\n at createError.
Why would I be receiving 401 Error here, despite other requests against this API not failing?
Thanks!

403 when upload file to S3 bucket using axios

I'm using axios to upload an audio file to AWS s3 bucket.
The workflow is: React => AWS API Gateway => Lambda.
Here is the backend Lambda code where generates the S3 presigned URL:
PutObjectRequest putObjectRequest = PutObjectRequest.builder()
.bucket(AUDIO_S3_BUCKET)
.key(objectKey)
.contentType("audio/mpeg")
.build();
PutObjectPresignRequest putObjectPresignRequest = PutObjectPresignRequest.builder()
.signatureDuration(Duration.ofMinutes(10))
.putObjectRequest(putObjectRequest)
.build();
PresignedPutObjectRequest presignedPutObjectRequest = s3Presigner.presignPutObject(putObjectPresignRequest);
AwsProxyResponse awsProxyResponse = new AwsProxyResponse();
awsProxyResponse.setStatusCode(HttpStatus.SC_OK);
awsProxyResponse.setBody(
GetS3PresignedUrlResponse.builder()
.s3PresignedUrl(presignedPutObjectRequest.url().toString())
.build().toString());
return awsProxyResponse;
Here is the java code to create the bucket:
private void setBucketCorsSettings(#NonNull final String bucketName) {
s3Client.putBucketCors(PutBucketCorsRequest.builder()
.bucket(bucketName)
.corsConfiguration(CORSConfiguration.builder()
.corsRules(CORSRule.builder()
.allowedHeaders("*")
.allowedMethods("GET", "PUT", "POST")
.allowedOrigins("*") // TODO: Replace with domain name
.exposeHeaders("ETag")
.maxAgeSeconds(3600)
.build())
.build())
.build());
log.info("Set bucket CORS settings successfully for bucketName={}.", bucketName);
}
In my frontend, here is the part that try to upload file:
const uploadFile = (s3PresignedUrl: string, file: File) => {
let formData = new FormData();
formData.append("file", file);
formData.append('Content-Type', file.type);
const config = {
headers: {
"Content-Type": 'multipart/form-data; boundary=---daba-boundary---'
//"Content-Type": file.type,
},
onUploadProgress: (progressEvent: { loaded: any; total: any; }) => {
const { loaded, total } = progressEvent;
let percent = Math.floor((loaded * 100) / total);
if (percent < 100) {
setUploadPercentage(percent);
}
},
cancelToken: new axios.CancelToken(
cancel => (cancelFileUpload.current = cancel)
)
};
axios(
{
method: 'post',
url: s3PresignedUrl,
data: formData,
headers: {
"Content-Type": 'multipart/form-data; boundary=---daba-boundary---'
}
}
)
.then(res => {
console.log(res);
setUploadPercentage(100);
setTimeout(() => {
setUploadPercentage(0);
}, 1000);
})
.catch(err => {
console.log(err);
if (axios.isCancel(err)) {
alert(err.message);
}
setUploadPercentage(0);
});
};
However, when try to upload the file, it return 403 error.
And if I use fetch instead of axios instead and it works, like this:
export async function putToS3(presignedUrl: string, fileObject: any) {
const requestOptions = {
method: "PUT",
headers: {
"Content-Type": fileObject.type,
},
body: fileObject,
};
//console.log(presignedUrl);
const response = await fetch(presignedUrl, requestOptions);
//console.log(response);
return await response;
}
putToS3(getPresignedUrlResponse['s3PresignedUrl'], values.selectdFile).then(
(putToS3Response) => {
console.log(putToS3Response);
Toast("Success!!", "File has been uploaded.", "success");
}
);
It seems to me that the only difference between these two is that: when using fetch the request's Content-Type header is Content-Type: audio/mpeg, but when using axios it is Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryClLJS3r5Xetv3rN7 .
How can I make it work with axios? I'm switching to axios for its ability to monitor request progress as I want to show an upload progress bar.
I followed this blog and not sure what I missed: https://bobbyhadz.com/blog/aws-s3-presigned-url-react
You are using POST in your axios. Should be PUT instead.
Also I think the content type has to match the one specified during requesting the pre-signed URL, which is audio/mpeg as you rightly pointed out.
Correspondingly, your data should be just file, instead of formData.
axios(
{
method: 'put',
url: s3PresignedUrl,
data: file,
headers: {
"Content-Type": 'audio/mpeg'
}
}
...
You didn't mark any answers as accepted so I guess you didn't solve it.
For any future viewers out there. The reason why you are getting 403 forbidden error is because your Content-Type in your server and client side are not matching. I'm assuming you set up the AWS policies correctly.
Your code in the backend should look like this:
const presignedPUTURL = s3.getSignedUrl("putObject", {
Bucket: "bucket-name",
Key: String(Date.now()),
Expires: 100,
ContentType: "image/png", // important
});
and in the front-end (assuming you are using axios):
const file = e.target.files[0]
const result = await axios.put(url, file, {
withCredentials: true,
headers: { "Content-Type": "image/png" },
});
In practical, you would normally have to send the file type to generate the pre-signed url in the POST body or whatever and then in axios you do file.type to get the file type of the uploaded file.
Check your Lambda execution role. It may be the culprit. Perhaps it does not grant enough permissions to allow PUTting files into your bucket.
URL signing is a delegation of power on behalf of the signer, which is restricted to a specified object, action... Signing does not magically grants full read/write permissions on S3, even on the specific object related to the presigned URL.
The "user" who generates the signature requires sufficient permissions to allow the actions you want to delegate through that presigned URL. In this case, this is the execution role of your Lambda function.
You can add the AmazonS3FullAccess managed policy to the execution role and see if it solves your situation. This change took me out of a blocked situation me after days of struggle. Afterwards, before going to production, restrict that rule to the specific bucket you want to allow uploads into (least privilege principle).
If you develop using SAM local emulation, those execution roles seem not to be taken into account as long as you run your functions locally; the signed links work in that context even without S3 permissions.

Token based authentication using Authentication header giving 403 forbidden error

I have the following code in my react app:
I am sending an update request to rest backed which requires a user to be authenticated to perform PUT/POST/DELETE requests.
const update = (e) => {
e.preventDefault()
const formData = new FormData(form.current);
console.log('Token ' + localStorage.getItem("token")) // valid token
const requestOptions = {
method: 'PUT',
headers : {
// 'Authorization': 'Basic ' + btoa('user:password') // basic authentication works
"Authorization": 'Token ' + localStorage.getItem("token"),
},
body: formData
};
fetch(url, requestOptions)
.then(async response => {
const data = await response.json();
if(!response.ok){
const error = (data && data.message ) || response.status;
return Promise.reject(error)
}
alert('member updated')
history.push("/members")
})
.catch(error => console.error('Some error ', error))
}
Unfortunately, I'm getting these in console logs:
PUT http://localhost:8000/uskindia/56/ 403 (Forbidden)
Some error 403
And this in backed logs:
Forbidden: /uskindia/56/
[... *:*:*] "PUT /uskindia/56/ HTTP/1.1" 403 58
Trying to solve this for the last 24 hours but not getting it right.
From various tries, it seems like:
backend DRF and django-rest-auth is not handling token properly
tried various user agents like curl, httpie and postman to view request and response closely
Even in backed put logs, but request.user == AnonymousUser with token based authorisation.
works well with basic authorizatin, scheme.
if you are using djangorestframework for backend you must send token with this format :
"Authorization": 'Bearer ' + localStorage.getItem("token"),
use Bearer instead of token.
There was a typo in settings.py
# Earlier
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASS': [
'rest_framework.authentication.TokenAuthentication',
],
# ....
}
# Changed to
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
# ...
}
Thanks to Blog by Vitor Freitas
which made it clear that, if response contains
WWW-Authenticaate:Token then it means Token authentication was working.
As this was missing in my case, so I started all over setting REST_FRAMEWORK settings from scratch and found the root cause of issue.

Apollo REST Data Source and Imgur API - Keep getting 400 Bad Request using form data

I am trying to implement apollo-datasource-rest to handle image uploading by URL via Imgur's API (documentation here: https://apidocs.imgur.com/)
I initially was getting a 400 error which read We don't support that file type!, and determined that it was due to apollo-datasource-rest automatically setting the Content-Type to application/json. After fixing that issue using the form-data npm package, here's what my code looks like:
class ImgurAPI extends RESTDataSource {
constructor() {
super();
this.baseURL = "https://api.imgur.com/3/";
}
willSendRequest(request) {
request.headers.set("Content-Type", "multipart/form-data");
request.headers.set(
"Authorization",
`Client-ID ${process.env.IMGUR_CLIENT_ID}`
);
console.log(request);
}
async uploadImageFromUrl(url) {
const formData = new FormData();
formData.append("image", url);
return this.post("upload", formData);
}
}
I now no longer get the We don't support that file type! error, but I still get a 400 response with a status text of just Bad Request. The console.log() from the previous code snippet prints this:
{
method: 'POST',
path: 'upload',
body: FormData {
_overheadLength: 104,
_valueLength: 80,
_valuesToMeasure: [],
writable: false,
readable: true,
dataSize: 0,
maxDataSize: 2097152,
pauseStreams: true,
_released: false,
_streams: [
'----------------------------594660553626244976225816\r\n' +
'Content-Disposition: form-data; name="image"\r\n' +
'\r\n',
'https://upload.wikimedia.org/wikipedia/commons/a/a0/Sunflower_as_gif_websafe.gif',
[Function: bound ]
],
_currentStream: null,
_insideLoop: false,
_pendingNext: false,
_boundary: '--------------------------594660553626244976225816'
},
params: URLSearchParams {},
headers: Headers {
[Symbol(map)]: [Object: null prototype] {
'Content-Type': [Array],
Authorization: [Array]
}
}
}
What am I missing here? The API seems to be accepting my form data so I would think that maybe there's some issue with one of the other headers, but in Postman it looks like there's only a few required headers, most of which are calculated (e.g. Content-Length) and so I assume apollo-datasource-rest must be handling that.
After doing some more research into multipart/form-data, I found that the boundary parameter is mandatory, and must be added to the Content-Type value in the request for the server to be able to parse the payload. Furthermore I am unable to manually set it as a parameter in the request (at least not in a way that actually works). Postman normally calculates this field when the request is sent, but apollo-datasource-rest doesn't automatically handle that.
Changing the Content-Type to application/x-www-form-urlencoded and using a url encoded string instead of form-data fixed the issue.
Here's the updated code:
willSendRequest(request) {
request.headers.set("Content-Type", `application/x-www-form-urlencoded`);
request.headers.set(
"Authorization",
`Client-ID ${process.env.IMGUR_CLIENT_ID}`
);
console.log(request);
}
async uploadImageFromUrl(url) {
const formData = `image=${url}&album=${process.env.IMGUR_ALBUM_DELETE_HASH}&type=url`;
return this.post("upload", formData);
}

Resources