I have implemented authentication in my ASP.NET core, with AWS Cognito.
I encountered a problem in which after I sign out I can still access areas with [Authorize].
I have read similar problems and from what I understood, when the signout method is called: HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
the cognito is being signed out but the app is not. One of the solutions would be deleting the cookies, which I did, but still didn't help. Also clearing the session, but that didn't work either.
My app settings:
"Authentication": {
"Cognito": {
"ClientId": "myid",
"MetadataAddress": "https://cognito-idp.us-west-1.amazonaws.com/us-west-2_tBadwTi4x/.well-known/openid-configuration",
"ResponseType": "code",
"SaveToken": true,
"AppSignOutUrl": "/Home",
"CognitoDomain": "https://mydomain-auth.auth.us-west-1.amazoncognito.com"
}
}
My program.cs:
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddAuthentication(item =>
{
item.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
item.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.Cookie.Name = "Cookie";
options.Cookie.Path = "/";
})
.AddOpenIdConnect(options =>
{
options.ResponseType = builder.Configuration["Authentication:Cognito:ResponseType"];
options.MetadataAddress = builder.Configuration["Authentication:Cognito:MetadataAddress"];
options.ClientId = builder.Configuration["Authentication:Cognito:ClientId"];
options.Events = new OpenIdConnectEvents()
{
// This method enables logout from Amazon Cognito, and it is invoked before redirecting to the identity provider to sign out
OnRedirectToIdentityProviderForSignOut = OnRedirectToIdentityProviderForSignOut
};
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("email");
options.SaveTokens = Convert.ToBoolean(builder.Configuration["Authentication:Cognito:SaveToken"]);
});
// State Session
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(100);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.UseAuthorization();
app.UseRouting();
app.UseSession();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{**path}");
app.Run();
// This method performs a Cognito sign-out, and then redirects user back to the application
Task OnRedirectToIdentityProviderForSignOut(RedirectContext context)
{
context.ProtocolMessage.Scope = "openid";
context.ProtocolMessage.ResponseType = "code";
var cognitoDomain = builder.Configuration["Authentication:Cognito:CognitoDomain"];
var clientId = builder.Configuration["Authentication:Cognito:ClientId"];
var logoutUrl = $"{context.Request.Scheme}://{context.Request.Host}{builder.Configuration["Authentication:Cognito:AppSignOutUrl"]}";
context.ProtocolMessage.IssuerAddress = $"{cognitoDomain}/logout?client_id={clientId}&logout_uri={logoutUrl}";
// delete cookies
context.Properties.Items.Remove(CookieAuthenticationDefaults.AuthenticationScheme);
// close openid session
context.Properties.Items.Remove(OpenIdConnectDefaults.AuthenticationScheme);
return Task.CompletedTask;
}
My Controller and antion for sign out:
public class AccountController : Controller
{
public IActionResult Login()
{
return View();
}
public async Task SignOut()
{
// Note: To sign out the current user and delete their cookie, call SignOutAsync
// 1. Initiate signout for cookie based authentication scheme
await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
// 2. Initiate signout for OpenID authentication scheme
await HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme);
Response.Cookies.Delete("Cookie");
HttpContext.Session.Clear();
}
In my _layout, I have a a dropdown button which has a Signout option:
...
@if (User.Identity.IsAuthenticated)
{
....
<li class="nav-item dropdown show">
<a class="nav-item nav-link text-dark dropdown-toggle" href="#" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-haspopup="true">
Profile
</a>
<div class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownMenuLink">
<a class="dropdown-item text-black" asp-controller="Projects" asp-action="Projects">Projects</a>
<a class="dropdown-item text-black" asp-controller="Client" asp-action="MainPage">Account settings</a>
<a class="dropdown-item text-black" asp-controller="Client" asp-action="Plan">Current Plan</a>
<a class="dropdown-item text-black" asp-controller="Account" asp-action="SignOut">Sign out</a>
</div>
</li>
}
</ul>
</div>
</div>
...
Everything works like it should except that after signin out I can still access every item protected with [Authorize]. I force the removal of the cookies and I clear the session but that is not changing the outcome.
Anyone faced the same problem and figured out what the problem was?
According to AWS documentation I seem to be doing everything correctly.
Thanks for your help.
For me, it seems that the logout is not happening from Cognito side. Ideally, when you do a logout, it should also clear the signed-in user's cookies from the Cognito domain.
After logout, when you try to access a page with [Authorize]
attribute, you are redirected to Cognito as Application cookies are not present. On Cognito domain, logout may not have happened properly earlier, and your cookies might already present there. That's why, you are not asked for login again and directly redirected to the requested page in your application.
To test this, you should observe the cookies (in 2 cases) by opening the Cognito URL https://<custom domain name>.auth.<your region>.amazoncognito.com
in browser.
If logout happens from Cognito properly, then you will find few cookies deleted, and are no longer present.
It may also happen that the Cognito domain that you are using in appsettings.json
is not correct. You can verify by constructing the logout URL manually and hitting that from the browser.
https://<custom domain name>.auth.<your region>.amazoncognito.com/logout?client_id={clientId}&logout_uri={logoutUrl}
If you do not get proper response, then this might be the actual issue.