Jeff B
Jeff B

Reputation: 1060

IDS4 - Redirect Loop When Logging In (Manual Navigation Works and Localhost Works)

Some info first:


  1. I go to an endpoint on the Application that requires the user to be logged in (Home/Claim).
  2. It correctly redirects to the login screen.
  3. Username and Password are entered, it then correctly redirects back to the Application's OIDC endpoint with the set cookie headers.
  4. It then redirects to the original Home/Claim endpoint. It does not have the cookies in the request.
  5. It then redirects back to the login screen, sees the user is logged in and returns back to the initial Application's OIDC endpoint - putting the app into a loop.

Curious enough, if I stop the browser from loading the page then manually navigate back to the Application's Home/Claim endpoint, it works!? The c1 and c2 cookies are correctly in the header and the user is authenticated correctly. It does not redirect back to login.

This is what the redirect pattern looks like (Claim is the endpoint I am trying to access): enter image description here

callback?client_id is on the Login's domain signin0oidc is on the Application's domain Claim is on the Application's domain

This is the initial Request Header on the first call when redirecting back to the Home/Claim endpoint (It is worth noting that on Localhost the cookies in the second image are set when it does its redirect to Home/Claim. It sets them the first time whereas on dev it is not): enter image description here

When I manually navigate to the Home/Claim endpoint (after the above steps) this is what the Request Header looks like (notice the cookie is there): enter image description here


Some final notes:



The Fix: The marked answer fixed the issue. Specifically I just used this code from the article linked (putting it in the startup.cs of any clients wishing to use Identity Server).

app.Use(async (ctx, next) => {
  if (ctx.Request.Path == "/signout-oidc" &&
    !ctx.Request.Query["skip"].Any()) {
    var location = ctx.Request.Path +
      ctx.Request.QueryString + "&skip=1";
    ctx.Response.StatusCode = 200;
    var html = $ @ " <
      html > < head >
      <
      meta http - equiv = 'refresh'
    content = '0;url={location}' / >
      <
      /head></html > ";
    await ctx.Response.WriteAsync(html);
    return;
  }

  await next();

  if (ctx.Request.Path == "/signin-oidc" &&
    ctx.Response.StatusCode == 302) {
    var location = ctx.Response.Headers["location"];
    ctx.Response.StatusCode = 200;
    var html = $ @ " <
      html > < head >
      <
      meta http - equiv = 'refresh'
    content = '0;url={location}' / >
      <
      /head></html > ";
    await ctx.Response.WriteAsync(html);
  }
});

Upvotes: 1

Views: 1630

Answers (1)

Alpha75
Alpha75

Reputation: 2280

What value of SameSite do you use for your Cookie?

Remember that a Strict value of SameSite tells the browser that it should not include cookies in case of a redirect from other domain.

However, the cookie is there, so if you access any url in your application (it is no longer a redirect), the cookie is included. Just go to the address bar and hit Intro with the same url. If the cookie is sent it will mean that this is surely your problem.

If this is your problem, set your Cookie whit SameSite = Lax. Lax allows the cookie to be sent on cross redirections.

You can learn more about this issue and try other solution proposed from Brockallen blog: Same-site cookies, ASP.NET Core, and external authentication providers. This solution maintains the Strict attribute in your Cookie.

Upvotes: 1

Related Questions