I'm using IdentityServer4 as a centralized auth server. I have a mvc app that acts as a client and works as expected unless I open a modal. When the user presses the edit button,I load the data into the modal and send it to the update endpoint in mvc client itself. Ajax request looks like this:
$.ajax({
xhrFields: { withCredentials: true },
crossDomain:true,
url: url,
type: 'POST',
headers: {
//added these because working request included them
'Access-Control-Allow-Origin':'https://localhost:5001',
'Upgrade-Insecure-Requests': 1,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
},
data: data,
success: function (res) {
$(`#${id}-body`).html(res);
}
})
Here is the problem: If the token is expired, request sent from Ajax doesn't refresh it. connect/authorize endpoint gets called but it doesn't invoke the signin/oidc request as it normally does(eg. when refreshing the page or going to a view that isn't a modal.).
The difference I noticed between these 2 (normal views/views called from Ajax) is,that the response size of the connect/authorize call has a slightly longer state query parameter,call from Ajax also invokes a preflight request first(which is understandable,but shouldn't be MVC endpoints that call IdentityServer endpoints make Options request as well?) and headers are also different:
Request from Ajax
Host: localhost:5001
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36
Access-Control-Allow-Origin: https://localhost:5001
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Upgrade-Insecure-Requests: 1
Request-Id: |be8b9ea0bfef4656a45fceb5c1f35e18.e173569e490b443c
sec-ch-ua-platform: "Windows"
Request-Context: appId=cid-v1:b526a0aa-46b6-4b9f-abe4-27f22e832ca5
Origin: https://localhost:6001
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://localhost:6001/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Request from mvc itself(This one works fine):
Host: localhost:5001
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: navigate
Sec-Fetch-Dest: document
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="100", "Google Chrome";v="100"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Referer: https://localhost:6001/
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Here is the IdentityServer4 config:
services.AddIdentityServer(x =>
{
x.Authentication.CookieLifetime =
TimeSpan.FromMinutes(15);
x.UserInteraction.LoginUrl = LoginStr;
x.UserInteraction.LogoutUrl = LogoutStr;
})
.AddAspNetIdentity<AppUser>()
.AddIdentityServerConfiguration(env, Urls);
services.ConfigureApplicationCookie(x =>
{
x.LoginPath = LoginStr;
x.LogoutPath = LogoutStr;
x.AccessDeniedPath = AccessDeniedPath;
});
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder
.WithOrigins(
"https://localhost:5001",
"https://localhost:6001")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
MVC client config in IS4:
ClientId = "MVC Client",
ClientName = "MVC App Name",
AllowedGrantTypes = GrantTypes.Code,
ClientSecrets = { new Secret("super-secret-code".Sha256()) },
RedirectUris = { "https://localhost:6001/signin-oidc" },
PostLogoutRedirectUris = { "https://localhost:6001/signout-callback-oidc" },
RequirePkce = true,
RequireConsent = false,
AllowOfflineAccess = true,
AllowedScopes =
{
//removed for brevity
}
And client config on the MVC side:
x.SignInScheme = "Cookies";
x.Authority = IDProvider;
x.RequireHttpsMetadata = false;
x.ClientId = "MVC Client";
x.ClientSecret = "super-secret-code";
x.ResponseType = "code";
x.UsePkce = true;
x.SaveTokens = true;
x.GetClaimsFromUserInfoEndpoint = true;
//scope and claims removed for brevity
x.SignInScheme = "Cookies";
x.UseTokenLifetime = true;
So far, I have tried many things,such as messing with the cookie settings in both MVC and identityserver app,adding some more headers to the Ajax request etc. but to no avail.I probably can fix this via AuthenticationHandler,but would like to know if theres a simpler,cleaner way.