The Setup / Environment
Client: (React.js, vs code, axios)
POST request to backend server to set auth cookie. On every refresh Ill verify the cookie by a GET request to the auth backend server. Every axios call is done with the "withCredentials:true" property set.
Backend (.net 6 - miminal API app written in c# and visual studio 2022.)
Set the cookie to "httpOnly", "sameSite=none" and "secure".
What Works
I have tested the flow on Windows 10, 11 + Mac computer and here everythink works fine. The cookie is set and I can login to my app. The setCookie header is present here.
The problem
When I try to login from my iPhone with the latest IOS 15.4 it is not working (though it should be supported according to this https://caniuse.com/same-site-cookie-attribute).
The cookie is not set and the "getcookie" request returns null and Ill return Unauthorized.
Code:
Frontend (React js):
//run "npx create-react-app iphone-cors-test-app" and add a useEffect hook in App component //like this.
useEffect(() => {
var urlToBackendService= "https://829f-217-211-155-130.eu.ngrok.io";
axios({
url: baseURL + '/setcookie',
method: 'post',
withCredentials: true,
data: {
Email: 'ineedhelp@please.com',
Password: 'loveu'
}
}).then(() => {
axios({
url: baseURL + '/getcookie',
method: 'get',
withCredentials: true
}).then((resp) => {
var cookieValue = resp.data;
console.clear();
console.log(`cookie value: ${cookieValue}`);
alert(`cookie value: ${cookieValue}`);
})
});
Backend (c# .net 6, visual studio 2022):
//.net core web api template > minimal api (no controllers) enable https.
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("https://nameofmyreactapp.azurewebsites.net")
.WithHeaders("accept", "content-type", "origin")
.WithMethods("GET", "POST", "OPTIONS")
.AllowCredentials();
});
});
builder.Services.AddHttpContextAccessor();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseCors();
app.MapPost("/setcookie", async ([FromServices] IHttpContextAccessor httpContextAccessor, LogonRequest logonRequest) =>
{
return await Task.Run<IResult>(() =>
{
//login user and get an accesstoken. set accesstoken to a httpOnly cookie.
var accessToken = "newly generated jwt access token";
httpContextAccessor.HttpContext!.Response.Cookies.Append(key: "accesstoken", accessToken, new CookieOptions
{
HttpOnly = true,
/*This should work with an iPhone with ios 15.4 (https://caniuse.com/same-site-cookie-attribute).*/
SameSite = SameSiteMode.None,
Secure = true
});
return Results.Ok();
});
});
app.MapGet("/getcookie", async ([FromServices] IHttpContextAccessor httpContextAccessor) =>
{
return await Task.Run<IResult>(() =>
{
var accesstoken = httpContextAccessor.HttpContext!.Request.Cookies["accesstoken"];
return string.IsNullOrEmpty(accesstoken)
? Results.Unauthorized()
: Results.Ok(accesstoken);
}
);
});
app.Run();
public record LogonRequest(string Username, string Password);
Screenshots:
setCookie request.
getCookie request.
Please help me.
UPDATE If you want to test this with your phone I use ngrok. Sign up and follow directions. Download ngrok.exe and go to that folder in your terminal. Then start your backend localhost and type "ngrok http + your localhost address".
Example:
"ngrok http https://localhost:7200"
Then hit enter and you will get a public url to your localhost.
Replace the client axios url (urlToBackendService) with this new public url and publish your react app to to cloud (or create another ngrok user and do the same think for the client) or if you have browserstack account or if you have another idé how to test this.