I have inherited maintenance of a PHP website that is mysite.com and an ASP.NET website that is shop.mysite.com. The client wants a single sign-on for both sites. The solution I am pursuing is to create a function on the ASP.NET site that returns the necessary information to the PHP site.
The ASP.NET function is called "IsUserLoggedIn" that returns a JSON object with the username and an array of roles.
Here is a condensed version of that function:
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> IsUserLoggedIn()
{
try
{
if (HttpContext.Request.Headers["api-key"][0] != configuration["ApiKey"])
{
HttpContext.Response.StatusCode = 200;
return Json(new { authenticated = "no key", roleId = "" });
}
if (HttpContext.User.Identity.IsAuthenticated)
{
var user = await userOperations.GetUser.Execute(HttpContext.User);
var companyUser = await companyRepository.GetUser(user.Id, user.ActiveCompanyId);
var roles = new List<String>();
if (companyUser.Company.CustomerRoles != null)
{
roles.AddRange(companyUser.Company.CustomerRoles);
}
if (companyUser.UserCompanies != null)
{
foreach (var company in companyUser.UserCompanies)
{
if (company.CustomerRoles != null)
{
roles.AddRange(company.CustomerRoles);
}
}
}
HttpContext.Response.StatusCode = 200;
return Json(new { authenticated = "yes", User = user, roleId = roles });
}
else
{
HttpContext.Response.StatusCode = 200;
return Json(new { authenticated = "not auth", roleId = "" });
}
}
catch (AuthenticationException e)
{
HttpContext.Response.StatusCode = 200;
return Json(new { authenticated = "error", roleId = "", e });
}
}
When I am logged into shop.mysite.com and open another tab and go to shop.mysite.com/User/IsUserLoggedIn (with the api-key in the request header), it returns a JSON object as expected:
{
"authenticated": "yes",
"user": {
"id": 17085,
"username": "cdavis",
"verified": true,
"activeCompanyId": "TEST001"
},
"roleId": [
"NGFE"
]
}
However, when I try to get the data using fetch in JavaScript, it returns a JSON object showing there is no user authorized. Here is my JavaScript code running in mysite.com:
async function checkUserLoggedIn() {
try {
const response = await fetch('https://' + custom_script_vars.api_url + '/User/IsUserLoggedIn', {
method: 'GET',
headers: {
'api-key': custom_script_vars.api_key,
},
credentials: 'include',
});
console.log('Response status:', response.status);
if (response.ok) {
const jsonData = await response.json();
console.log('User logged in:', jsonData);
const phpEndpoint = custom_script_vars.theme_directory + '/set-session.php';
// Use AJAX or another fetch to pass the JSON data to your PHP method
await fetch(phpEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ companyResourcesSessionUserLoggedIn: jsonData }),
});
console.log('User logged in:', jsonData);
} else {
console.error('Failed to check user login status:', response.status);
}
} catch (error) {
console.error('Error during user login check:', error);
}
}
The JSON object returned by the JavaScript fetch:
{
"authenticated": "not auth",
"roleId": ""
}
Am I just trying to do something that is not allowed? I have tried it in both Chrome and Edge with the same behavior in each.
I assume that fetch in JavaScript is not just like "opening a tab in the background". I'd love any alternatives if you have done something similar.
It was the
SameSite=Laxthat was preventing the cookie from being read. I added code in my ASP.NET project to change the cookie toSameSite=None.Added to my Configure method (after
app.UseAuthentication()):This article was very helpful in diagnosing my issue: https://andrewlock.net/making-authenticated-cross-origin-requests-with-aspnetcore-identity/