I have a react native app that posts and gets data from a remote server. In post, i need to include csrf token to avoid token mismatch errors. This is the backend laravel method
//Android Login
public function androidLogin(){
return response()->json([
'name' => 'Android Login',
'route' => 'androidLogin'
]);
}
This is the react native code(i have stripped out error catching code).
async handleSubmit(){
var me = this.state.message;
console.log('this connected',me);
let response = await fetch('http://not-brusselus.be/androidLogin', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN':'csrf_field()'
},
body: JSON.stringify({
session:{
email: 'chesterfield#gmail.com',
password: '123456',
}
})
});
//let res = await response.text();
if (true) {
console.log(response);
} else {
//Handle error
//let error = res;
//throw error;
}
}
The response shows laravel's token mismatch page. How can i send the csrf token successfully?.
Hang the CSRF token off of the window as defined in your main laravel layout file:
window.Laravel = {
csrfToken: '{{csrf_token()}}'
}
Then just use that in your javascript requests:
...window.Laravel.csrfToken
Edit
To the downvoter: This is literally how Laravel does it out of the box and recommends you do it as well.
Related
I make several requests from a React Native app to an API. Every request works fine both on iOS and Android except the DELETE method that does not work on Android. The call is correctly made, it goes through the API and the objects are deleted. But instead of getting the response, the call falls under the catch statement with [TypeError: Network request failed]. This does not happen in iOS.
Some people with the same problem were missing 'Content-Type': 'application/json' on the request headers which is not my case.
This is happening both locally, in testing and production stages (using an ip instead of localhost will do nothing).
The request is also successfully performed in Postman.
What can it be?
React Native 0.63.5
export const deleteApi = async (api: string, body?: any) => {
const userResponse = await getUserCredentials();
const authState = await getAuthState();
let response = await fetch(api, {
method: 'DELETE',
headers: await getHeaders(userResponse, authState),
body: JSON.stringify(body)
});
if (response.status === UNAUTHENTICATED_CODE)
response = await interceptor(response, userResponse, {
api: api,
method: 'DELETE',
body: body
});
return response;
};
leaveClass = async (
uuid: string,
onSuccess: () => void,
onFailure: (error: string) => void,
) => {
this.setLoading(true);
try {
const api = LEAVE_CLASS_API_PREFIX + uuid + LEAVE_CLASS_API_SUFFIX;
const response = await deleteApi(api);
if (response.status === SUCCESS_STATUS_CODE) {
onSuccess();
}
else {
const jsonResponse = await response.json();
if (jsonResponse.detail) onFailure(jsonResponse.detail);
else onFailure(translations.SOMETHING_WENT_WRONG);
}
} catch (error) {
console.log('leaveClass error: ', error);
}
this.setLoading(false);
};
You can use a network plugin for Flipper (https://fbflipper.com/docs/setup/plugins/network/), copy your request from it as a curl, and try to perform it from your terminal or postman. If it has the same error, the problem is not in React Native.
I have a server that running with asp.net. I follow a tutorial from the web that enable my server to issue a token Auth0 2 to the client that request it and created web api so that my android emulator able to retrieve some data from the server. I set my token expired date to 365 days. I try to request a token from Postman by providing grant_type, username and password and as expected server return me a token and I use the Get method from Postman to fetch some data from an API endpoint and submit the token in the header, as expected the server successfully return me the data without any problem. The Postman able to fetch data from the server by using a token issue from yesterday so I assume the token implementation is correct.
Server:
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(365),
Provider = new SimpleAuthorizationServerProvider()
};
// Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
app.UseOAuthBearerTokens(OAuthServerOptions);
Android react native :
Login to get an access token from the server
var formBody="grant_type=password&username="+userEmail+"&password="+userPassword;
fetch('http://aaa.aaaa.com/token', {
method: 'POST',
body: formBody,
headers: {
//Header Defination
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
},
})
.then((response) => response.json())
.then((responseJson) => {
//Hide Loader
setLoading(false);
console.log(responseJson);
// If server response message same as Data Matched
//if (responseJson.status == 1)
if (responseJson.access_token)
{
global.token=responseJson.access_token;
AsyncStorage.setItem('access_token', responseJson.access_token);
//console.log(responseJson.data[0].user_id);
//navigation.replace('DrawerNavigationRoutes');
navigation.navigate('NavigatorHome');
} else {
//AsyncStorage.setItem('user_id', 'test1');
//navigation.navigate('NavigatorHome');
//setErrortext('Please check your email id or password');
console.log('Please check your email id or password');
}
})
.catch((error) => {
//Hide Loader
setLoading(false);
console.error(error);
});
Fetch Data from API endpoint
var accessToken=global.token;
var formBody="";
formBody = JSON.stringify({
'module': 'order',
'action': 'get',
'value':route.params.orderID
})
fetch('http://aaa.aaaa.com/api/Orders?ID='+formBody, {
method: 'Get',
headers: {
//Header Defination
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken,
},
})
.then((response) => response.json())
.then((responseJson) => {
//Hide Loader
//setLoading(false);
console.log(responseJson);
// If server response message same as Data Matched
//if (responseJson.status == 1)
})
.catch((error) => {
//Hide Loader
//setLoading(false);
console.error(error);
});
After that I try to run with android emulator. First I use the fetch method by providing grant_type, username and password, as expected the server return me a token and I store it with AsyncStorage. Then I try to fetch some data by providing the token I requested previously and server able to return me the data without any problem. But if I leave my emulator like for 15min or 30min, now when I try to fetch data from the server it fail. What I do is I try to request a new token by sending grant_type, username and password again and the new token work as expected.
This is weird! I have double check my access token setting at the server which is 365 days and Postman able to Get data without any problem by using the token that issue yesterday, why did the token that issued to my emulator expired within 15 or 30 min? Hope some body can point out my problem. Thanks in advance!
Oh my bad! the Postman is fetching data from my localhost server and react native is fetching data from the prod server. [here] (asp.net identity expire bearer token after 20 min)
When i send a normal get request to my deployed nodejs webserver it tell me there is no cookies sent in the header while i ve already write it in the headers of my api service
my service
constructor(private http: HttpClient, private global: Global) { }
verifAuth() {
return new Promise((resolve, reject) => {
this.http.get(`${this.global.url}verif`, this.global.header)
.toPromise()
.then(res => { resolve(res); })
.catch(err => { reject(err); console.log('err', err) });
});
my declared default header
#Injectable({
providedIn: 'root'
})
export class Global {
url: String; header;
constructor() {
this.url = "https://fmm.etudiant.xyz/";
this.header = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'cookies': `xt=${appSetting.getString('xt')}`,
}),
withCredentials: true
};
}
}
and when i debug the request i found this
request header
i expect that the token must be parsed and get the result of user but the backend server tell that there is no cookies while it work fine with an other website
Sending Cookie in Http request is not yet supported, there is a open feature request at Github.
I am using http calls to call a cloud function.
I have a URL in the form
url: 'https://api.shipengine.com/v1/labels/rates/rateid,
Now I need to pass values dynamically in rated whenever the function call happens.
How to pass the value into that URL.
I am attaching my cloud function too.
exports.shipmentlabelwithreturnid = functions.https.onRequest((req, res) => {
var request = require("request");
var rateid = req.body.RateId;
console.log(rateid);
var options = { method: 'POST',
url: 'https://api.shipengine.com/v1/labels/rates/'+ rateid,
headers:
{ 'content-type': 'application/json',
accept: 'application/json'
}
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
});
You should use promises, in your Cloud Function, to handle asynchronous tasks. By default request does not return promises, so you need to use an interface wrapper for request, like request-promise which "returns a regular Promises/A+ compliant promise", as follows:
....
const rp = require('request-promise');
exports.shipmentlabelwithreturnid = functions.https.onRequest((req, res) => {
var rateid = req.body.RateId;
console.log(rateid);
var options = { method: 'POST',
uri: 'https://api.shipengine.com/v1/labels/rates/'+ rateid,
headers:
{ 'content-type': 'application/json',
accept: 'application/json'
}
};
rp(options)
.then(response => {
console.log('Get response: ' + response.statusCode);
res.send('Success');
})
.catch(err => {
// API call failed...
res.status(500).send('Error': err);
});
});
Also, it is important to note that you need to be on the "Flame" or "Blaze" pricing plan.
As a matter of fact, the free "Spark" plan "allows outbound network requests only to Google-owned services". See https://firebase.google.com/pricing/ (hover your mouse n the question mark situated after the "Cloud Functions" title)
Since https://api.shipengine.com is not a Google-owned service, you need to switch to the "Flame" or "Blaze" plan.
On the fact that you have to use promises to handle asynchronous tasks, I suggest that you watch these videos from the Firebase team: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=28s and https://www.youtube.com/watch?v=652XeeKNHSk which explain this key concept.
I'm working on a React Native app. We recently made a change to an API call, where it can respond with 500 and an error message detailing the problem so it can be presented to the user. The API response looks like:
{
"error": ["Renter contact info for User 1 missing"]
}
On the client, we're using the standard fetch() method to asynchronously make our request, and resolving the Promise in order to pull the response object out. When I log the response after a call that should trigger a 500, the object looks like:
{type: "default", status: 500, ok: false, statusText: undefined, headers: Headers…}
Here's our internal request() method we use for all API calls:
export function request(endpoint:string, parameters:Object, method:string = HTTP.get, timeout:number = 3000):Promise{
return new Promise(async (resolve, reject) => {
const payload = {
method,
headers: {
'Accept': CONTENT_TYPE,
'Content-Type': CONTENT_TYPE,
'Authorization': `Basic ${base64.encode(Config.API_TOKEN)}`,
'Auth-Token': await Agents.authToken,
},
body: JSON.stringify(parameters),
}
fetch(apiUrl(endpoint), payload)
.then(response => {
if(!response.ok) {
// ******************
// this is where the 500 error state is caught, but my response object doesn't contain the message sent from the server.
reject(response)
// ******************
}
return response
})
.then(resolve)
.catch(reject)
})
}
How can I ensure the response object contains the error message from the server so I can properly display it to my user?
fetch(apiUrl(endpoint), payload)
.then(response => {
if(!response.ok) {
response.json().then(function(data) {
console.log(data);// your error response
},function(error) {
//json error
});
reject(response)
// ******************
}
return response
})
response is a ReadableStream object. You need to use .json() to parse