Azure App Service Authentication - 302 when trying to GET /.auth/me - reactjs

I have a reactjs web app which is hosted on Azure App Services, using App Service Authentication.
My app authenticates properly and from inside the app I'm attempting to GET /.auth/me so that I can read the access tokens to use for some future API requests but am receiving a 302 in response. The response redirects to login.microsoft.com even though the first request (to load the app) has already been authenticated.
const headers = {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json',
'credentials': 'include'
};
return (dispatch) => {
const requestOptions = {
method: 'GET',
headers: headers,
};
return fetch("/.auth/me", requestOptions)
.then(parseResponseAndHandleErrors)
.catch(error => {
console.error(error)
});
}
I think I must be missing a cookie or a header in the GET but the docs don't give much information: https://learn.microsoft.com/en-us/azure/app-service/app-service-authentication-how-to#retrieve-tokens-in-app-code
From your client code (such as a mobile app or in-browser JavaScript), send an HTTP GET request to /.auth/me. The returned JSON has the provider-specific tokens.
I have tried setting 'credentials': 'same-origin' but that didn't make any difference.

I managed to figure this out after looking in to more detail at the 'credentials' option of the fetch() API.
'credentials' : 'same-origin' should not be included in the headers, but rather as a seperate request option:
const headers = {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
};
return (dispatch) => {
const requestOptions = {
method: 'GET',
headers: headers,
'credentials': 'same-origin' //credentials go here!!!
};
return fetch("/.auth/me", requestOptions)
......
}

Related

React Remix not sending cookies to remote server

I am trying to set up authentication with Remix as my pure frontend and a django backend.
When the user signs in successfully, the backend sends a cookie with the response and this is set in the browser redirect with remix
const signIn = async (credentials: LoginCreds) => {
try {
const response = await fetch(generateFullBackendUrl('/auth/signin'), {
method: 'POST',
body: JSON.stringify(credentials),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
credentials: 'include'
});
return response;
} catch (e) {
console.log(e);
}
}
const response = await authService.signIn({
email,
password
})
const cookies = response?.headers.get('set-cookie');
if(cookies){
return redirect('profile', {
headers: {
'Set-Cookie': cookies
}
});
However when I try to make subsequent fetch calls in my loader the cookies are not sent to the backend as I would expect the browser would
await fetch(generateFullBackendUrl('api/users/me'), {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
credentials: 'include'
})
Front end is running on port 3000
Backend running on port 4000
Im wondering why the fetch request in the loader does not send the cookies with the request
You need to read the cookie header from the loader request and pass it to your fetch headers.
There’s no way Fetch can automatically know what headers to send when used server side.
There is a quick workaround but not so elegant solution:
in your loader use this:
export const loader: LoaderFunction = async({request}) => {
const response = await fetch(`/api/books?${new URLSearchParams({
limit: '10',
page: '1',
})}`, {
headers: {
'Cookie': request.headers.get('Cookie') || ''
}
});
console.log(response)
if(response.ok) return await response.json();
}

Fetch isn't setting cookies

I have a reactjs frontend running on root /.
On the same domain and server there is an Wordpress instance running under the default Wordpress slugs (/wp-admin, /wp-json, etc.). I already authenticate users via JWT over the WP API.
The problem is i need to get the Wordpress default auth cookies so users can switch between Wordpress and reactjs pages without logging in twice.
I started to add a second fetch on login which calls the /login.php route and posts login credentials as form-data. In Postman i get the body, headers and the auth cookies i need:
If i fetch this inside my react frontend i don't get the cookies, also the are not set and available under document.cookie or at the dev tools.
This is my fetch function in react which is returning the Dashboard Page as Response Data and a Status Code 200:
async handleCookies() {
const formData = new FormData()
formData.append('log', this.state.mail)
formData.append('pwd', this.state.password)
await fetch('XXX.XXX.XXX.XXX/wp-login.php', {
method: 'POST',
body: formData,
credentials: 'include',
headers: { 'Content-type': 'application/x-www-form-urlencoded', Cache: 'no-cache' },
})
.then(response => response)
.then(cookies => {
alert(cookies)
})
.catch(err => console.log(err))
}
Expectation: I expect to receive the cookies.
It turned out that i didn't passed the credentials in the right way. Now everything is working.
await fetch('XXX.XXX.XXX.XXX/wp-login.php', {
method: 'POST',
body: `log=${encodeURIComponent(EMAIL)}&pwd=${encodeURIComponent(PASSWORD)}`,
credentials: 'include',
headers: { 'Content-type': 'application/x-www-form-urlencoded', Cache: 'no-cache' },
})

Problems using uri on axios

I currently work with an api rest where I pass the controller parameters, version and action via URI. However, when I execute a request with URI with more than 19 characters, it gives this CORS error:
Access to XMLHttpRequest at 'http://my-api-host/toll/vehicle/v1/list' from origin 'http://localhost: 3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
In authentication the request works even with URI having more than 19 characters. However, any other request with a different URI that has more than 19 characters gives this same error. I use my application's API and the request works normally.
I'm using axios in Reactjs.
The api is already configuring to accept the content-type I am using (application / json) and is also already accepting requests from different sources.
My request code:
request(uri, params = {}){
return new Promise((resolve, reject) => {
axios
.post('http://my-api-host' + uri, JSON.stringify(params), {
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
if (response.data.success) {
resolve(response.data);
} else {
reject(response.data);
}
});
});
};
Has anyone been through this and could help? thanks in advance
Did you use Fetch instead?
async function postData(url = '', params = {}) {
// Default options are marked with *
const response = await fetch(url, {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
mode: 'cors', // no-cors, *cors, same-origin
headers: {
'Content-Type': 'application/json'
},
qs: JSON.stringify(params) // query string data
});
return response.json(); // parses JSON response into native JavaScript objects
}
postData('http://my-api-host', params)
.then(data => {
console.log(data);
});

API request working in Postman but not in fetch() method of React Native app

I am trying to do a fetch() method in my React Native app:
return fetch(url, {
method: method,
headers: {
'Accept': 'application/json',
...headers
},
body: body
})
Here url is <IP address>:<port>/api/token
method is 'POST'
headers is {Content-Type: "application/x-www-form-urlencoded"}
and body is
grant_type=password&username=<username>&password=<password>&pushtoken=&primaryhost=<primary host IP>&primaryport=<primary host port>&secondaryhost=<secondary host IP>&secondaryport=<secondary host port>&osscustomer=103&deviceid=<device ID>&version=1.0&osversion=9&deviceversion=1.0
When I use these values in a Postman request, it works fine, but when I run the fetch() method in my React Native app, it gives the error e = TypeError: Network request failed at XMLHttpRequest.xhr.onerror.
Does anyone know why this might be?
change 'Accept' to Accept without single quites.
In the latest android versions http requests are not allowed by default. Take a look at this post for further information about allowing http request:How to allow all Network connection types HTTP and HTTPS in Android (9) Pie?
Use the following format:
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
}),
});
Better to use axios for http/https requests:axios package
It's working fine for me. Try this it may help
const formData = new FormData();
formData.append('email', 'test#gmail.com');
formData.append('password', '123456');
fetch("https://test.com/api/login", {
method: 'post',
body: formData
})
.then(res => res.json())
.then(
(result) => {
console.log(result);
}).catch(err => {
console.log(err);
})

React native fetch() 403 status

I have an API endpoint working good in postman with the bellow options
The above request can get 200 status and got a response. Now I am trying to implement the same API with React Native using fetch method.
fetch('https://example.com/api/user/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Token':'xxxxxx-xxxx-xxxx-xxxx-xxxxx'
},
body: {
"useremail": "testuser#example.com",
"userpassword": "123456"
},
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
}).catch((error) =>{
console.error(error);
});
The above code was not working and I am getting 403 status.
Have you tried this
The easy way to implement this is to use this attribute to your AndroidManifest.xml where you allow all http for all requests:
android:usesCleartextTraffic="true"
feel free for doubts
You are passing data without converting it to json will make problem here
fetch('https://example.com/api/user/login', {
method: 'POST',
credentials : 'include',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'token':'xxxxxx-xxxx-xxxx-xxxx-xxxxx',
},
body: JSON.stringify({ // convert object to json
"useremail": "testuser#example.com",
"userpassword": "123456"
}) ,
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
}).catch((error) =>{
console.error(error);
});
HTTP 403 is a standard HTTP status code communicated to clients by an HTTP server to indicate that access to the requested (valid) URL by the client is Forbidden for some reason. The server understood the request, but will not fulfill it due to client related issues.
so for first step in your postman use a fake user password to see if you get 403 again ,
if you got, that means you have problem in your sending your react native data.
so you should focus on your sending request code then,
According to docs
you can post like this
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
}),
});
be sure that you are sending your user pass correctly and not missing anything like misspellings
hope this helps you.

Resources