Cookie Authentication on controllers with Windows and Forms Login - c#

Haven't found any really helpful articles or SO questions regarding this problem.
I want to behave my API in the following way:
All controller actions should only be available for cookie authenticated users
There are 2 login actions for getting a cookie by form (username/pw) or sso with the windows user (this is rather easy to do)
My problems with this currently:
When the API returns 401 (the correct status code) for a controller action, the browser automatically defaults to re-triggering the request with a NTLM token. The user doesn't have a cookie and is still able to call the API action because the windows authentication scheme is still registered somehow
It works as I want it to when I decorate ALL of the API actions with:
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
In this case it seems that the Windows Authentication Scheme is never used but only cookies, which is what I want.
I want this to be the only allowed behavior though without having to decorate all of the actions explicitly and never allow Windows Authentication Scheme (apart from the windows login action)
I can also kind of getting it working when I make sure that the Cookie Authentication doesn't return 401 but returns 403, which doesn't make the browser to re-trigger the request with NTLM authentication. This is a workaround at best though.
The relevant parts of Startup.cs currently look like this:
services.AddAuthentication(opt =>
{
opt.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(ConfigureApplicationCookie);
Cookie config:
private static void ConfigureApplicationCookie(CookieAuthenticationOptions options)
{
options.Cookie.Name = Assembly.GetEntryAssembly().GetName().Name;
options.Cookie.HttpOnly = true;
options.Cookie.Expiration = TimeSpan.FromHours(1);
options.SlidingExpiration = true;
options.Events.OnRedirectToLogin = context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
};
options.Events.OnRedirectToAccessDenied = context =>
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
return Task.CompletedTask;
};
options.LogoutPath = null;
options.LoginPath = null;
}
IIS (and IIS express) is configured to use Anonymous and Windows Authentication.

Related

.Net SignalR use JWT Bearer Authentication when Cookie Authentication is also configured

I have a ASP.NET 5 WebApp that is part of a bigger system and uses Cookie Authentication for Browser requests.
I want to add the ability to request data and perform specific actions on certain Windows services that are also part of the overall system and are executed on a couple of seperate PCs. I want to use SignalR for this.
Then Windows-Services are running as a dedicated service identity that is part of our ActiveDirectory. Since the services shall not store their user credentials in code or local configuration files, they are requesting an authentication token for the web application from an API that works with Windows Authentication.
Then, when establishing the SignalR connection with the web app, the services will use the token received from the API to authenticate against the web app. This is working in general.
The Authentication configuration of the web app is:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.LoginPath = "/Login";
options.ExpireTimeSpan = TimeSpan.FromMinutes(12);
options.SlidingExpiration = true;
})
.AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, opt =>
{
// Configuration details excluded
// ...
opt.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
// ...
}
};
According to Microsoft Documentation this should be a vaild authentication configuration.
In services.AddAuthorization(...) method I've added a policy specific for Bearer scheme:
options.AddPolicy("SignalRService", policy =>
{
policy.RequireRole("SignalRService");
policy.AuthenticationSchemes.Add(JwtBearerDefaults.AuthenticationScheme);
});
And then there is a SignalR Hub Method secured with this policy:
[Authorize(Policy = "SignalRService")]
public async Task RegisterService(string clientIdString) { /*...*/ }
And finally the hub connection in the windows service is created as follows:
connection = new HubConnectionBuilder()
.WithUrl(hubAddress, options =>
{
options.AccessTokenProvider = () => Task.FromResult(authToken);
})
.WithAutomaticReconnect()
.Build();
Establishing the connection works:
await connection.StartAsync();
But when I try to call the hub method from the windows service like await connection.InvokeAsync("RegisterService", clientId); I receive a HubException with the message:
Failed to invoke 'RegisterService' because user is unauthorized
I have also created an API Controller on the web app for testing purposes and secured it with the same policy:
[HttpGet]
[Authorize(Policy = "SignalRService")]
public IActionResult Get()
{
return Ok(User.Identity.Name);
}
When I call this API endpoint with the same token i would user for SignalR Hub call, I get the identity set on the token returned as expected. I also verified that the configured OnMessageReceived event handler is executed in this scenario, while it isn't when I use SignalR connection.
When I set JwtBearerDefaults.AuthenticationScheme as the default scheme in Startup.cs instead of CookieAuthenticationDefaults.AuthenticationScheme it works also with the SignalR Hub, but then my standard Cookie based user authenticaton breaks.
I expect that there is some additonal configuration necessary to tell the web app to explicitely use the Bearer scheme when a Hub method is called, but I could not find anything so far.
After desperately trying for another hour, I found out that the specific bearer authentication worked with Cookie authentication as the default, when I put the Authorize(Policy = "SignalRService") directly on the class instead of on the method.
Since my hub should also be accessible for browser connections using cookies, I finally ended up with:
[Authorize(AuthenticationSchemes = "Bearer,Cookies")]
public class SignalRServiceHub : Hub
{
[Authorize(Policy = "SignalRService")]
public async Task RegisterService(string clientIdString)
{
// ...
}
[Authorize(Policy = "Root")]
public async Task RegisterMonitoringClient()
{
// ...
}
I'm not exactly sure why specifying the Schemes on class level is necessary in this case while it isn't for ApiController implementations

Microsoft Identity Web: Change Redirect Uri

I am using .net 5, Identity Web Ui to access Microsoft Graph. Where can I configure my Redirect URI?
I need to specify the full Uri, since the generated one from callbackUri is incorrect due to being behind a Load Balancer with SSL offload.
Here is my current ConfigureServices section
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
I was facing a similar problem with a WebApp exposed only behind a front door, the WebApp had to call a custom downstream WebApi.
My service configuration that worked on my localhost dev machine:
// AzureAdB2C
services
.AddMicrosoftIdentityWebAppAuthentication(
Configuration,
"AzureAdB2C", subscribeToOpenIdConnectMiddlewareDiagnosticsEvents: true)
.EnableTokenAcquisitionToCallDownstreamApi(p =>
{
p.RedirectUri = redUri; // NOT WORKING, WHY?
p.EnablePiiLogging = true;
},
[... an array with my needed scopes]
)
.AddInMemoryTokenCaches();
I tried the AddDownstreamWebApi but did not manage to make it work so I just fetched the needed token with ITokenAcquisition and added it to an HttpClient to make my request.
Then I needed AzureAd/B2C login redirect to the uri with the front door url:
https://example.org/signin-oidc and things broke. I solved it like this:
First of all you have to add this url to your App registration in the azure portal, very important is case sensitive it cares about trailing slashes and I suspect having many urls that point to the very same controller and the order of these have some impact, I just removed everything and kept the bare minimum.
Then in the configure services method:
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.SaveTokens = true; // this saves the token for the downstream api
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = async ctxt =>
{
// Invoked before redirecting to the identity provider to authenticate. This can be used to set ProtocolMessage.State
// that will be persisted through the authentication process. The ProtocolMessage can also be used to add or customize
// parameters sent to the identity provider.
ctxt.ProtocolMessage.RedirectUri = "https://example.org/signin-oidc";
await Task.Yield();
}
};
});
With that the redirect worked, but I entered a loop between the protected page and the AzureB2C login.
After a succesful login and a correct redirect to the signin-oidc controller (created by the Identity.Web package) I was correctly redirected again to the page that started all this authorization thing, but there it did not find the authorization. So I added/modded also this:
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
options.Secure = CookieSecurePolicy.Always;
});
With this the authorization worked, but I was not able to get the token to call the downstream API, before this redirect thing ITokenAcquisition worked, but now when trying to get the token it throws an exception.
So in my controller/service to get the token I modified and used:
var accessToken = await _contextAccessor.HttpContext
.GetTokenAsync(OpenIdConnectDefaults.AuthenticationScheme, "access_token");
So now with the token I add it to my HttpRequestMessage like this:
request.Headers.Add("Authorization", $"Bearer {accessToken}");
I lived on StackOverflow and microsoft docs for 3 days, I am not sure this is all "recommended" but this worked for me.
I had the same problem running an asp.net application under Google Cloud Run, which terminates the TLS connection. I was getting the error:
AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application.
Using fiddler, I examined the request to login.microsoftonline.com and found that the query parameter redirect_uri exactly matched the url I'd configured in the application in Azure except that it started http rather than https.
I initially tried the other answers involving handling the OpenIdConnectEvents event and updating the redirect uri. This fixed the redirect_url parameter in the call to login.microsoftonline.com and it then worked until I added in the graph api. Then I found my site's signin-oidc page would give its own error about the redirect uri not matching. This would then cause it to go into a loop between my site and login.microsoftonline.com repeatedly trying to authenticate until eventually I'd get a login failure.
On further research ASP.net provides middleware to properly handle this scenario. Your SSL load balancer should add the standard header X-Forwarded-Proto with value HTTPS to the request. It should also send the X-Forwarded-For header with the originating IP address which could be useful for debugging, geoip etc.
In your ASP.net application, to configure the middleware:
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});
Then enable the middleware:
app.UseForwardedHeaders();
Importantly, you must include this before the calls to app.UseAuthentication/app.UseAuthorization that depends on it.
Source: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-5.0
If your load balancer doesn't add the X-Forwarded-Proto header and can't be configured to do so then the document above outlines other options.
I was facing with similar issue for 3 days. The below code helped me to get out of the issue.
string[] initialScopes = Configuration.GetValue<string>("CallApi:ScopeForAccessToken")?.Split(' ');
services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAd")
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddInMemoryTokenCaches();
services.AddControllers();
services.AddRazorPages().AddMvcOptions(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();
services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.SaveTokens = true; // this saves the token for the downstream api
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = async ctxt =>
{
ctxt.ProtocolMessage.RedirectUri = "https://example.org/signin-oidc";
await Task.Yield();
}
};
});

How to configure the OAuth callback to a different domain in ASP.NET Core authentication

I am Authenticating against an OAuth endpoint where I can only configure 1 callback domain. (and localhost is whitelisted).
I have my web app running in Azure (myapp.azurewebsites.net) and have it available with two custom domains (myapp.cc and myapp.eu). When I use the default setup, the CallbackPath can only be a relative path (to the current domain)
The code documentation of CallbackPath indicates it's relative to the application's base path:
/// <summary>
/// The request path within the application's base path where the user-agent will be returned.
/// The middleware will process this request when it arrives.
/// </summary>
public PathString CallbackPath { get; set; }
I want to make sure the CallBack happens to the (only) domain that I whitelisted on the OAuth backend. I know I can implement everything manually, but I was hoping there would be an easy way to work around this design and still benefit from the baked in Authentication options.
So even if a user is logging on on the myapp.cc or the myapp.eu or the myapp.azurewebsites.net , it should redirect to myapp.azurewebsites.net/ (which is whitelisted on my Auth service)
A part of my Startup.cs file is pasted below:
services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = "MyService";
})
.AddCookie()
.AddOAuth("MyService", "MyService",
options =>
{
options.ClientId = settings.ClientId;
options.ClientSecret = settings.ClientOauthSecret;
options.CallbackPath = "/relativeonlypath";
options.SaveTokens = true;
options.SignInScheme = IdentityConstants.ExternalScheme;
/// ... removed for brevity
}
);
Any idea on how to implement this?
Thank you
I'm not sure it's possible, because to verify that the user is redirected to your application as part of a "genuine" authentication flow, the ASP.NET OAuth handler performs the following steps:
Before redirecting the user to the OAuth service, ASP.NET Core generates a "correlation" cookie that is tied to the current domain; and
When the user is redirected to the app, the handler looks for this cookie and validates its content.
So if the correlation cookie is generated in step #1 for one domain, let's say myapp.cc, and the user is redirected to another domain, myapp.azurewebsites.net, ASP.NET Core might not be able to read it because the browser will not have included it in the redirection request.
Note
As seen in the first comments, the original thought was to leverage the SameSiteproperty of the correlation cookie to have it sent by the browser to the second domain.
This was all wrong, apologies!
I now think that you have 2 different options:
Redirect every request from myapp.cc and myapp.eu to myapp.azurewebsites.net, so that when the authentication flow happens, we're already on the right domain; or
Redirect the user to the myapp.azurewebsites.net domain before redirecting them to the OAuth server.
I won't go into the first solution, as there's plenty of ways to achieve this.
Here's some code that I haven't tested that could work for the second solution:
services
.AddAuthentication(options =>
{
options.DefaultChallengeScheme = "MyService";
})
.AddCookie()
.AddOAuth("MyService", options =>
{
options.Events.OnRedirectToAuthorizationEndpoint = context =>
{
var currentRequestUri = new Uri(context.Request.GetDisplayUrl());
// 1. If we're not on the correct domain, redirect the user to the same page, but on the expected domain.
// The assumption is that the authentication flow will also kick in on the other domain (see 2).
if (currentRequestUri.Host != "myapp.azurewebsites.net")
{
var applicationRedirectUri = new UriBuilder(currentRequestUri)
{
Host = "myapp.azurewebsites.net"
}.Uri.ToString();
context.Response.Redirect(applicationRedirectUri);
return Task.CompletedTask;
}
// 2. If we reach here, it means we're on the right domain, so we can redirect to the OAuth server.
context.Response.Redirect(context.RedirectUri);
return Task.CompletedTask;
};
});

ASP.Net Core MVC/API/SignalR - Change authentication schemes (Cookie & JWT)

I've a .Net Core 2.2 web application MVC in which I've added API controllers and SignalR hubs. On the other side, I've a mobile app that calls the hub methods. Before calling hubs from the app, I am authenticating my users through an API call - getting back a JWT Token - and using this token for future requests, this way I can use Context.User.Identity.Name in my hub methods:
public static async Task<string> GetValidToken(string userName, string password)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_API_BASE_URI);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
LoginViewModel loginVM = new LoginViewModel() { Email = userName, Password = password, RememberMe = false };
var formContent = Newtonsoft.Json.JsonConvert.SerializeObject(loginVM);
var content = new StringContent(formContent, Encoding.UTF8, "application/json");
HttpResponseMessage responseMessage;
try
{
responseMessage = await client.PostAsync("/api/user/authenticate", content);
var responseJson = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false); ;
var jObject = JObject.Parse(responseJson);
_TOKEN = jObject.GetValue("token").ToString();
return _TOKEN;
}catch
[...]
Then using the token:
_connection = new HubConnectionBuilder().WithUrl(ApiCommunication._API_BASE_URI + "/network", options =>
{
options.AccessTokenProvider = () => Task.FromResult(token);
}).Build();
So far so good. It's working as expected on my mobile app. But in order to make it work I had to set this piece of code on server side (Startup.cs):
services.AddAuthentication(options =>
{
options .DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options .DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
...
This prevents me for using cookie authentication anymore and therefore the mvc web app is no more working as expected as it's not able to get the current authenticated user amongs requests.
Removing the lines:
options .DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options .DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
makes the web app working correctly but not the mobile app anymore (hub calls fail due to Context.User.Identity.Name equals to null).
I've been searching all around about how to handle different schemes (in my case cookie + jwt) and from my understanding, this is by design not possible anymore.
Is there any possible workaround to use double scheme or am I missing something?
I thought maybe I shoud host 2 separate projects instead and use one with Cookie authentication and the other one with JWT?
Thanks in advance.
There are multiple ways to solve the issue you encounter, but first let's go through why it's not currently working.
What DefaultAuthenticateScheme means
When you set a value to the DefaultAuthenticateScheme property of AuthenticationOptions, you instruct the authentication middleware to try and authenticate every single HTTP request against that specific scheme. I'm going to assume that you're using ASP.NET Identity for cookie-based authentication, and when you call AddIdentity, it registers the cookie authentication scheme as the default one for authentication purposes; you can see this in the source code on GitHub.
However, it doesn't mean you can't use any other authentication scheme in your application.
The authorization system default policy
If all the protected endpoints of your application are meant to be accessible to clients authenticated with cookies or JWTs, one option is to use the authorization system default policy. That special policy is used when you use "empty" instances of the AuthorizeAttribute class — either as an attribute to decorate controllers/actions, or globally at the app level with a new AuthorizeFilter(new AuthorizeAttribute()).
The default policy is set to only require an authenticated user, but doesn't define which authentication schemes need to be "tried" to authenticate the request. The result is that it relies on the authentication process already having been performed. It explains the behavior you're experiencing where only one of the 2 schemes works at a time.
We can change the default policy with a bit of code:
services.AddAuthorization(options =>
{
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("<your-cookie-authentication-scheme", "your-jwt-authentication-scheme")
.Build();
})
Specific authorization policies
If you find yourself in a situation where you require some endpoints to only be accessible to clients authenticated with cookies and others with JWTs, you can take advantage of authorization policies.
They work exactly like the default policy, expect you get to pick on an endpoint basis which one applies. You can add policies like so:
services.AddAuthorization(options =>
{
options.AddPolicy("Cookies", new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("<your-cookie-authentication-scheme")
.Build());
options.AddPolicy("JWT", new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("<your-jwt-authentication-scheme")
.Build());
})
You can then refer to these policies in appropriate endpoints by decorating them with [Authorize(Policy = "<policy-name>")]. As a side note, if the only differentiator between your policies is the authentication scheme, it's possible to achieve the same result without creating policies, and referring to the appropriate authentication scheme(s) in [Authorize] attributes with the AuthenticationSchemes property.
Policies are valuable when you have more complex rules, like that specific claim needs this specific value, for example.
I hope this helps, let me know how you go! 👍

Why having cookies on token based authentication using Identity Server and asp.net core 2

I am creating a sample application to just to understand how identity server 4 authentication works with Asp.net core 2. I have noticed some cookies are generated for different levels as it can be seen in the attached screenshot. My problems is why these cookies are generated?
Below statement, I take it from the Identity Server document. When identity server is configuring
IdentityServer internally calls both AddAuthentication and AddCookie with a custom scheme (via the constant IdentityServerConstants.DefaultCookieAuthenticationScheme),
Here why it calls AddCookies method on identity server itself?
Also when I configure Asp.net core web client to use Identity server authentication it also call AddCookie() method. When I try to comment it It will give me an error. I am bit of unclear what is happening here.
Identity Server Configurations
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddToDoUserStore()
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients());
services.AddAuthentication("MyCookie")
.AddCookie("MyCookie", options =>
{
options.ExpireTimeSpan = new System.TimeSpan(0, 0, 15);
});
Web Client Configuration
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
options.Authority = "https://localhost:44377/";
options.RequireHttpsMetadata = true;
options.ClientId = "ToDoTaskManagmentClient";
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("address");
options.Scope.Add("roles");
options.Scope.Add("usertodoapi");
options.Scope.Add("countries");
options.Scope.Add("subscriptionlevel");
options.Scope.Add("offline_access");
options.ResponseType = "code id_token";
options.SaveTokens = true;
options.ClientSecret = "secret";
options.GetClaimsFromUserInfoEndpoint = true;
options.ClaimActions.Clear();
options.ClaimActions.MapJsonKey("given_name", "given_name");
options.ClaimActions.MapJsonKey("family_name", "family_name");
options.ClaimActions.MapJsonKey("role", "role");
options.ClaimActions.MapJsonKey("country", "country");
options.ClaimActions.MapJsonKey("subscriptionlevel", "subscriptionlevel");
options.Events = new OpenIdConnectEvents()
{
OnTokenValidated = e =>
{
var identity = e.Principal;
var subjectClaim = identity.Claims.FirstOrDefault(z => z.Type == "sub");
var expClaims = identity.Claims.FirstOrDefault(z => z.Type == "exp");
var newClaimsIdentity = new ClaimsIdentity(e.Scheme.Name);
newClaimsIdentity.AddClaim(subjectClaim);
newClaimsIdentity.AddClaim(expClaims);
e.Principal = new ClaimsPrincipal(newClaimsIdentity);
return Task.FromResult(0);
},
OnUserInformationReceived = e =>
{
e.User.Remove("address");
return Task.FromResult(0);
}
};
});
Your Identity Server application needs an authentication cookie (and session ID cookie) so that the front channel endpoints (authorize, consent, check_session_iframe and possibly others) know if the user is authenticated or not and the current state of the session. Without this it would have no idea who was calling it. IDS4 will automatically redirect to the login URL of the default scheme if it detects that the incoming request is not authenticated - you are then free to implement any authentication flow you like.
Your client applications may or may not need cookies depending on the architecture. A traditional server side WebForms or MVC-style app will need one but a pure JS client using a library like oidc-client-js will not and can talk to the back-end purely using the access token obtained from your identity server.
IdentityServer doesn't do any of this. All it does is handle the low-level authentication/authorization and return a claims principal. Your application that's using IdentityServer is the one that would set the cookie.
What you're doing here is essentially having the same app host both IdentityServer and a cookie auth-based frontend. The cookie portion is for the traditional login flow UI, so that the app can recognize whether the user is authenticated and redirect to a login form or to an account page or back to the originating app, if or when they are authenticated.
That piece could be completely spun-off into a totally different app, and then your IdentityServer app would no longer need the cookie auth config.

Categories