{"id":51503,"date":"2020-02-03T08:00:52","date_gmt":"2020-02-03T07:00:52","guid":{"rendered":"https:\/\/code-maze.com\/?p=51503"},"modified":"2024-06-03T12:31:37","modified_gmt":"2024-06-03T10:31:37","slug":"authentication-aspnet-core-identity","status":"publish","type":"post","link":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/","title":{"rendered":"Authentication With ASP.NET Core Identity"},"content":{"rendered":"<p>Authentication is the process of confirming a user\u2019s identity. It is a set of actions, we use to verify the user\u2019s credentials against the ones in the database. For the user to be able to provide credentials, our application requires a Login page with a set of fields for our user to interact with.<\/p>\n<p>In this article, we are going to learn how to implement user authentication with ASP.NET Core Identity. So our main goal is going to be creating a login page and preparing a set of actions to validate input credentials.<\/p>\n<div style=\"padding: 20px; border-left: 5px color:#dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">To download the source code for the video, visit our <a href=\"https:\/\/www.patreon.com\/posts\/source-code-asp-105290322?src=AuthenticationIdentity\" target=\"_blank\" rel=\"nofollow noopener\">Patreon page<\/a> (YouTube Patron tier).<\/div>\n<p>To navigate through the entire series, visit the <a href=\"https:\/\/code-maze.com\/asp-net-core-identity-series\/\" target=\"_blank\" rel=\"noopener noreferrer\">ASP.NET Core Identity series<\/a> page.<\/p>\n<p>Let\u2019s start.<\/p>\n<hr \/>\r\n<p style=\"text-align: center;\"><strong>VIDEO<\/strong>: Web API Authentication With Identity And JWT.<\/p>\r\n<p style=\"text-align: center;\"><iframe width=\"560\" height=\"315\" src=https:\/\/www.youtube.com\/embed\/qPlqUQdf0fE?si=vg4SkFQv9dGjHXzO frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/p>\r\n<hr \/>\n<h2 id=\"preparation\">Preparing the Authentication Environment in our Project<\/h2>\n<p>The first thing, we are going to do is disable unauthorized users to access the <code>Employees<\/code> action. To do that, we have to add the <code>[Authorize]<\/code> attribute on top of that action:<\/p>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"c\" data-enlighter-highlight=\"1\" data-enlighter-title=\"\">[Authorize]\r\npublic async Task&lt;IActionResult&gt; Employees()\r\n{\r\n    var employees = await _context.Employees.ToListAsync();\r\n    return View(employees);\r\n}\r\n<\/pre><\/p>\n<p>Additionally, we have to add authentication middleware to the ASP.NET Core\u2019s pipeline right above the <code>app.UseAuthorization()<\/code> expression:<\/p>\n<p><code>app.UseAuthentication();<\/code><\/p>\n<p>If we run our application now and click on the <code>Employees<\/code> link, we are going to get a 404 not found response:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-51504\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/11-Login-page-not-found.png\" alt=\"Login not found in ASP.NET Core Identity Authentication\" width=\"727\" height=\"329\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/11-Login-page-not-found.png 727w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/11-Login-page-not-found-300x136.png 300w\" sizes=\"auto, (max-width: 727px) 100vw, 727px\" \/><\/p>\n<p>We get this because, by default, ASP.NET Core Identity tries to redirect an unauthorized user to the <code>\/Account\/Login<\/code> action, which doesn\u2019t exist at the moment. Additionally, you can see a <code>ReturnUrl<\/code> query string that provides a path to the required action before the user was redirected to the Login page. We are going to deal with it later in this post.<\/p>\n<p>Now, we are going to do a couple of things to fix this 404 error.<\/p>\n<p>First, let\u2019s create a <code>UserLoginModel<\/code> class in the <code>Models<\/code> folder:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class UserLoginModel\r\n{\r\n    [Required]\r\n    [EmailAddress]\r\n    public string Email { get; set; }\r\n\r\n    [Required]\r\n    [DataType(DataType.Password)]\r\n    public string Password { get; set; }\r\n\r\n    [Display(Name = \"Remember me?\")]\r\n    public bool RememberMe { get; set; }\r\n}\r\n<\/pre>\n<p>Next, let\u2019s add two new actions to the Account controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpGet]\r\npublic IActionResult Login()\r\n{\r\n    return View();\r\n}\r\n\r\n[HttpPost]\r\n[ValidateAntiForgeryToken]\r\npublic async Task&lt;IActionResult&gt; Login(UserLoginModel userModel)\r\n{\r\n    return View();\r\n}\r\n<\/pre>\n<p>We don\u2019t want to navigate to the Login page only by accessing the protected action, we want to have a separate link for that as well. So, let\u2019s modify the <code>_LoginPartial<\/code> view:<\/p>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xhtml\" data-enlighter-highlight=\"3-6\" data-enlighter-title=\"\">&lt;ul class=&quot;navbar-nav&quot;&gt;\r\n\r\n    &lt;li class=&quot;nav-item&quot;&gt;\r\n        &lt;a class=&quot;nav-link text-dark&quot; asp-controller=&quot;Account&quot;\r\n           asp-action=&quot;Login&quot;&gt;Login&lt;\/a&gt;\r\n    &lt;\/li&gt;\r\n    &lt;li class=&quot;nav-item&quot;&gt;\r\n        &lt;a class=&quot;nav-link text-dark&quot; asp-controller=&quot;Account&quot;\r\n           asp-action=&quot;Register&quot;&gt;Register&lt;\/a&gt;\r\n    &lt;\/li&gt;\r\n\r\n&lt;\/ul&gt;\r\n<\/pre><\/p>\n<p>Finally, let\u2019s create a Login view:<\/p>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xhtml\" data-enlighter-title=\"\">@model IdentityByExamples.Models.UserLoginModel\r\n\r\n&lt;h1&gt;Login&lt;\/h1&gt;\r\n\r\n&lt;div class=&quot;row&quot;&gt;\r\n    &lt;div class=&quot;col-md-4&quot;&gt;\r\n        &lt;form asp-action=&quot;Login&quot;&gt;\r\n            &lt;div asp-validation-summary=&quot;ModelOnly&quot; class=&quot;text-danger&quot;&gt;&lt;\/div&gt;\r\n            &lt;div class=&quot;form-group&quot;&gt;\r\n                &lt;label asp-for=&quot;Email&quot; class=&quot;control-label&quot;&gt;&lt;\/label&gt;\r\n                &lt;input asp-for=&quot;Email&quot; class=&quot;form-control&quot; \/&gt;\r\n                &lt;span asp-validation-for=&quot;Email&quot; class=&quot;text-danger&quot;&gt;&lt;\/span&gt;\r\n            &lt;\/div&gt;\r\n            &lt;div class=&quot;form-group&quot;&gt;\r\n                &lt;label asp-for=&quot;Password&quot; class=&quot;control-label&quot;&gt;&lt;\/label&gt;\r\n                &lt;input asp-for=&quot;Password&quot; class=&quot;form-control&quot; \/&gt;\r\n                &lt;span asp-validation-for=&quot;Password&quot; class=&quot;text-danger&quot;&gt;&lt;\/span&gt;\r\n            &lt;\/div&gt;\r\n            &lt;div class=&quot;form-group form-check&quot;&gt;\r\n                &lt;label class=&quot;form-check-label&quot;&gt;\r\n                    &lt;input class=&quot;form-check-input&quot; asp-for=&quot;RememberMe&quot; \/&gt; @Html.DisplayNameFor(model =&gt; model.RememberMe)\r\n                &lt;\/label&gt;\r\n            &lt;\/div&gt;\r\n            &lt;div class=&quot;form-group&quot;&gt;\r\n                &lt;input type=&quot;submit&quot; value=&quot;Log In&quot; class=&quot;btn btn-primary&quot; \/&gt;\r\n            &lt;\/div&gt;\r\n        &lt;\/form&gt;\r\n    &lt;\/div&gt;\r\n&lt;\/div&gt;\r\n\r\n@section Scripts {\r\n    @{await Html.RenderPartialAsync(&quot;_ValidationScriptsPartial&quot;);}\r\n}\r\n<\/pre><\/p>\n<p>Ok, let\u2019s test this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-51505\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/12-Login-links-tested.gif\" alt=\"Login links in Authentication\" width=\"806\" height=\"489\" \/><\/p>\n<p>Excellent, everything is prepared and we can continue.<\/p>\n<h2 id=\"authentication\">Implementing Authentication with ASP.NET Core Identity<\/h2>\n<p>After we click the submit button, the <code>UserLoginModel<\/code> will be sent to the POST Login action. So, we have to modify that action:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpPost]\r\n[ValidateAntiForgeryToken]\r\npublic async Task&lt;IActionResult&gt; Login(UserLoginModel userModel)\r\n{\r\n    if(!ModelState.IsValid)\r\n    {\r\n        return View(userModel);\r\n    }\r\n\r\n    var user = await _userManager.FindByEmailAsync(userModel.Email);\r\n    if(user != null &amp;&amp; \r\n        await _userManager.CheckPasswordAsync(user, userModel.Password))\r\n    {\r\n        var identity = new ClaimsIdentity(IdentityConstants.ApplicationScheme);\r\n        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));\r\n        identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));\r\n\r\n        await HttpContext.SignInAsync(IdentityConstants.ApplicationScheme,\r\n            new ClaimsPrincipal(identity));\r\n\r\n        return RedirectToAction(nameof(HomeController.Index), \"Home\");\r\n    }\r\n    else\r\n    {\r\n        ModelState.AddModelError(\"\", \"Invalid UserName or Password\");\r\n        return View();\r\n    }\r\n}\r\n<\/pre>\n<p>First, we check if the model is invalid and if it is, we just return a view with the model. After that, we use the <code>FindByEmailAsync<\/code> method from <code>UserManager<\/code> to return a user by email. If the user exists and the password matches the hashed password from the database, we create the <code>ClaimsIdentity<\/code> object with two claims inside (Id and UserName). Then, we sign in the user with the <code>SignInAsync<\/code> method by providing the scheme parameter and the claims principal. This will create the <code>Identity.Application<\/code> cookie in our browser. Finally, we redirect the user to the Index action.<\/p>\n<p>If the user doesn\u2019t exist in the database or the password doesn\u2019t match, we return a view with the appropriate message.<\/p>\n<p>Before we test this, let\u2019s add a small modification in the Employees view below the table. This way we can see our claims:<\/p>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xhtml\" data-enlighter-title=\"\">&lt;h2&gt;Claim details&lt;\/h2&gt;\r\n&lt;ul&gt;\r\n    @foreach (var claim in User.Claims)\r\n    {\r\n        &lt;li&gt;&lt;strong&gt;@claim.Type&lt;\/strong&gt;: @claim.Value&lt;\/li&gt;\r\n    }\r\n&lt;\/ul&gt;\r\n<\/pre><\/p>\n<p>Now, let\u2019s try to login with the invalid credentials:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-51506\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/13-Invalid-Credentials-Login.png\" alt=\"Invalid Credentials\" width=\"287\" height=\"380\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/13-Invalid-Credentials-Login.png 287w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/13-Invalid-Credentials-Login-227x300.png 227w\" sizes=\"auto, (max-width: 287px) 100vw, 287px\" \/><\/p>\n<p>If we use valid credentials, we are going to be redirected to the Index page with the <code>Identity.Application<\/code> cookie created:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-51507\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/14-Valid-Credentials-Login.png\" alt=\"Valid credentials - ASP.NET Core Identity Authentication\" width=\"990\" height=\"243\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/14-Valid-Credentials-Login.png 990w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/14-Valid-Credentials-Login-300x74.png 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/14-Valid-Credentials-Login-768x189.png 768w\" sizes=\"auto, (max-width: 990px) 100vw, 990px\" \/><\/p>\n<p>Now, we can visit the Employees page:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-51508\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/15-Claim-details.png\" alt=\"Authentication Claims\" width=\"699\" height=\"560\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/15-Claim-details.png 699w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/15-Claim-details-300x240.png 300w\" sizes=\"auto, (max-width: 699px) 100vw, 699px\" \/><\/p>\n<p>We can access it and we can see our claims.<\/p>\n<h2 id=\"return-url\">Implementing ReturnUrl in Authentication Process<\/h2>\n<p>As you could see in the first part of this article, if the user is not authorized and tries to access the protected action, they are going to be redirected to the Login page. The URL contains the <code>ReturnUrl<\/code> query parameter as well, which shows the source page the user came from. But in our case, we just navigate the user to the Home page. So, let\u2019s fix that.<\/p>\n<p>The first thing, we are going to do is to modify the GET Login action:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpGet]\r\npublic IActionResult Login(string returnUrl = null)\r\n{\r\n    ViewData[\"ReturnUrl\"] = returnUrl;\r\n    return View();\r\n}\r\n<\/pre>\n<p>Then, we have to modify the <code>Login.cshtml<\/code> file as well:<\/p>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xhtml\" data-enlighter-title=\"\">&lt;form asp-action=&quot;Login&quot; asp-route-returnUrl=&quot;@ViewData[&quot;ReturnUrl&quot;]&quot;&gt;<\/pre><\/p>\n<p>We have to modify the POST action too:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public async Task&lt;IActionResult&gt; Login(UserLoginModel userModel, string returnUrl = null)<\/pre>\n<p>Also, in the same method, instead of the <code>ReturnToAction<\/code> method, we are going to call a custom one:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">return RedirectToLocal(returnUrl);<\/pre>\n<p>And of course, let\u2019s create that method in the Account controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">private IActionResult RedirectToLocal(string returnUrl)\r\n{\r\n    if (Url.IsLocalUrl(returnUrl))\r\n        return Redirect(returnUrl);\r\n    else\r\n        return RedirectToAction(nameof(HomeController.Index), \"Home\");\r\n    \r\n}\r\n<\/pre>\n<p>So we just check if the returnUrl is a local URL and if it is we redirect the user to that address, otherwise, we redirect the user to the Home page.<\/p>\n<p>Let\u2019s see how it works:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-51509\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/16-Return-Url-implemented.gif\" alt=\"Return Url implemented\" width=\"963\" height=\"489\" \/><\/p>\n<p>And we can see it works as expected.<\/p>\n<p>One additional thing. Our Login action is on the <code>\/Account\/Login<\/code> route, and that\u2019s the default route ASP.NET Core Identity is going to look for. But for a different path, for example: <code>\/Authentication\/Login<\/code>, we have to configure application cookie in the <code>ConfigureServices<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">services.ConfigureApplicationCookie(o =&gt; o.LoginPath = \"\/Authentication\/Login\");<\/pre>\n<p>Now, we can proceed.<\/p>\n<h2 id=\"automating\">Automating Authentication Process<\/h2>\n<p>If you want to take complete control over the authentication logic, the approach we have used is a great choice. But, we can speed up the process by using the <code>SignInManger&lt;TUser&gt;<\/code> class. This class provides the API for user sign in with a lot of helper methods.<\/p>\n<p>So, let\u2019s inject it first in the Account controller:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">private readonly IMapper _mapper;\r\nprivate readonly UserManager&lt;User&gt; _userManager;\r\nprivate readonly SignInManager&lt;User&gt; _signInManager;\r\n\r\npublic AccountController(IMapper mapper, UserManager&lt;User&gt; userManager, SignInManager&lt;User&gt; signInManager)\r\n{\r\n    _mapper = mapper;\r\n    _userManager = userManager;\r\n    _signInManager = signInManager;\r\n}\r\n<\/pre>\n<p>And, let\u2019s use it in the Login action:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpPost]\r\n[ValidateAntiForgeryToken]\r\npublic async Task&lt;IActionResult&gt; Login(UserLoginModel userModel, string returnUrl = null)\r\n{\r\n    if (!ModelState.IsValid)\r\n    {\r\n        return View(userModel);\r\n    }\r\n\r\n    var result = await _signInManager.PasswordSignInAsync(userModel.Email, userModel.Password, userModel.RememberMe, false);\r\n    if (result.Succeeded)\r\n    {\r\n        return RedirectToLocal(returnUrl);\r\n    }\r\n    else\r\n    {\r\n        ModelState.AddModelError(\"\", \"Invalid UserName or Password\");\r\n        return View();\r\n    }\r\n}\r\n<\/pre>\n<p>We use the <code>PasswordSignInAsync<\/code> method that accepts four parameters: Username, Password, Persist Cookie, and LockOut on Failure. For now, we don\u2019t require a lockout feature, so we set it to false. This method does all the magic we had to do by ourselves in the previous implementation. Additionally, it returns a result with four properties:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-51510\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/17-signIn-result.png\" alt=\"SignIn results in Authentication\" width=\"227\" height=\"223\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/17-signIn-result.png 227w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/17-signIn-result-75x75.png 75w\" sizes=\"auto, (max-width: 227px) 100vw, 227px\" \/><\/p>\n<p>As you can see, we use the <code>Succeeded<\/code> property to verify that our action completed successfully.<\/p>\n<p>Now if we login successfully to our application, we can see the cookie created with our claims:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-51511\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/18-PasswordSignInAsync-success.png\" alt=\"PasswordSignInAsync success\" width=\"1154\" height=\"524\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/18-PasswordSignInAsync-success.png 1154w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/18-PasswordSignInAsync-success-300x136.png 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/18-PasswordSignInAsync-success-1024x465.png 1024w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/18-PasswordSignInAsync-success-768x349.png 768w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/18-PasswordSignInAsync-success-1080x490.png 1080w\" sizes=\"auto, (max-width: 1154px) 100vw, 1154px\" \/><\/p>\n<p>We can see additional claims as well, like security stamp, role, and amr(Authentication Method Reference).<\/p>\n<h2 id=\"custom-claims\">Adding Custom Claims in the Authentication Process<\/h2>\n<p>In the previous list of claims, we can\u2019t see our custom properties from the User class. Of course, if we want to add those, there is a way to do that.<\/p>\n<p>Let\u2019s create a new Factory folder and a new class inside:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class CustomClaimsFactory : UserClaimsPrincipalFactory&lt;User&gt;\r\n{\r\n    public CustomClaimsFactory(UserManager&lt;User&gt; userManager, IOptions&lt;IdentityOptions&gt; optionsAccessor)\r\n        : base(userManager, optionsAccessor)\r\n    {\r\n    }\r\n}\r\n<\/pre>\n<p>Our custom class has to implement the <code>UserClaimsPrincipalFactory&lt;TUser&gt;<\/code> class and to send a <code>userManager<\/code> and <code>optionsAccessor<\/code> objects to it. Now, we have to override the <code>GenerateClaimsAsync<\/code> method in this class to add our additional claims:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">protected override async Task&lt;ClaimsIdentity&gt; GenerateClaimsAsync(User user)\r\n{\r\n    var identity = await base.GenerateClaimsAsync(user);\r\n    identity.AddClaim(new Claim(\"firstname\", user.FirstName));\r\n    identity.AddClaim(new Claim(\"lastname\", user.LastName));\r\n\r\n    return identity;\r\n} \r\n<\/pre>\n<p>The final thing we have to do is to register this class in the service collection:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">services.AddScoped&lt;IUserClaimsPrincipalFactory&lt;User&gt;, CustomClaimsFactory&gt;();<\/pre>\n<p>After we test this:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-51512\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/19-additional-claims.png\" alt=\"Additional claims\" width=\"918\" height=\"201\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/19-additional-claims.png 918w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/19-additional-claims-300x66.png 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/19-additional-claims-768x168.png 768w\" sizes=\"auto, (max-width: 918px) 100vw, 918px\" \/><\/p>\n<p>We can see our additional claims.<\/p>\n<p>Awesome.<\/p>\n<h3>Update<\/h3>\n<p>After the <code>CustomClaimsFactory<\/code> class implementation, we can&#8217;t see the role claim anymore on the page. If we want to add it, we have to modify the <code>GenerateClaimsAsync<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"7-11\">protected override async Task&lt;ClaimsIdentity&gt; GenerateClaimsAsync(User user)\r\n{\r\n    var identity = await base.GenerateClaimsAsync(user);\r\n    identity.AddClaim(new Claim(\"firstname\", user.FirstName));\r\n    identity.AddClaim(new Claim(\"lastname\", user.LastName));\r\n\r\n    var roles = await UserManager.GetRolesAsync(user);\r\n    foreach (var role in roles)\r\n    {\r\n        identity.AddClaim(new Claim(ClaimTypes.Role, role));\r\n    }\r\n            \r\n    return identity;\r\n}<\/pre>\n<p>With this in place, we can see the role claim once again as part of our token.<\/p>\n<h2 id=\"logout\">Logout Implementation<\/h2>\n<p>The Logout implementation is pretty simple though. But before we do that, let\u2019s modify the <code>_LoginPartial<\/code> view:<\/p>\n<p><pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xhtml\" data-enlighter-highlight=\"1-3,6-18\" data-enlighter-title=\"\">@using Microsoft.AspNetCore.Identity\r\n@inject SignInManager&lt;User&gt; SignInManager\r\n@inject UserManager&lt;User&gt; UserManager\r\n\r\n&lt;ul class=&quot;navbar-nav&quot;&gt;\r\n    @if (SignInManager.IsSignedIn(User))\r\n    {\r\n        &lt;li class=&quot;nav-item&quot;&gt;\r\n            &lt;a class=&quot;nav-link text-dark&quot; asp-controller=&quot;Home&quot; asp-action=&quot;Index&quot; \r\n                title=&quot;Welcome&quot;&gt;Welcome @User.Identity.Name!&lt;\/a&gt;\r\n        &lt;\/li&gt;\r\n        &lt;li class=&quot;nav-item&quot;&gt;\r\n            &lt;form class=&quot;form-inline&quot; asp-controller=&quot;Account&quot; asp-action=&quot;Logout&quot;&gt;\r\n                &lt;button type=&quot;submit&quot; class=&quot;nav-link btn btn-link text-info&quot;&gt;Logout&lt;\/button&gt;\r\n            &lt;\/form&gt;\r\n        &lt;\/li&gt;\r\n    }\r\n    else\r\n    {\r\n        &lt;li class=&quot;nav-item&quot;&gt;\r\n            &lt;a class=&quot;nav-link text-dark&quot; asp-controller=&quot;Account&quot;\r\n                   asp-action=&quot;Login&quot;&gt;Login&lt;\/a&gt;\r\n        &lt;\/li&gt;\r\n        &lt;li class=&quot;nav-item&quot;&gt;\r\n            &lt;a class=&quot;nav-link text-dark&quot; asp-controller=&quot;Account&quot;\r\n               asp-action=&quot;Register&quot;&gt;Register&lt;\/a&gt;\r\n        &lt;\/li&gt;\r\n    }\r\n&lt;\/ul&gt;\r\n<\/pre><\/p>\n<p>Here, we inject the <code>SignInManager<\/code> and <code>UserManager<\/code> classes by using the <a href=\"https:\/\/code-maze.com\/dependency-injection-aspnetcore-mvc\/#DIIntoViews\" target=\"_blank\" rel=\"noopener noreferrer\">View Dependency Injection Technique<\/a> and then just check if our user is signed in. If it is, we show a welcome message and the Logout button.<\/p>\n<p>Now, let\u2019s implement the Logout action:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">[HttpPost]\r\n[ValidateAntiForgeryToken]\r\npublic async Task&lt;IActionResult&gt; Logout()\r\n{\r\n    await _signInManager.SignOutAsync();\r\n\r\n    return RedirectToAction(nameof(HomeController.Index), \"Home\");\r\n}\r\n<\/pre>\n<p>Once we start the application, log in successfully and click the Logout link, we are going to be logged out and the cookie will be removed.<\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>So, to sum it up, we have learned:<\/p>\n<ul>\n<li>How to execute the authentication process<\/li>\n<li>How to use different UserManager helper methods that help in a process<\/li>\n<li>The way to implement ReturnUrl logic<\/li>\n<li>And how to add additional claims to the user<\/li>\n<\/ul>\n<p>In the next article, we are going to talk about <a href=\"https:\/\/code-maze.com\/password-reset-aspnet-core-identity\/\" target=\"_blank\" rel=\"noopener noreferrer\">Reset Password (Forgot Password) functionality<\/a> with ASP.NET Core Identity.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Authentication is the process of confirming a user\u2019s identity. It is a set of actions, we use to verify the user\u2019s credentials against the ones in the database. For the user to be able to provide credentials, our application requires a Login page with a set of fields for our user to interact with. In [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":51514,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[12],"tags":[629,73,636,414],"class_list":["post-51503","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-csharp","tag-asp-net-core-identity","tag-authentication","tag-claimsidentiy-application","tag-identity","et-has-post-format-content","et_post_format-et-post-format-standard"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Authentication With ASP.NET Core Identity - Code Maze<\/title>\n<meta name=\"description\" content=\"In this article, we are going to learn about the Authentication process with ASP.NET Core Identity, Logout process and adding additional Claims.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Authentication With ASP.NET Core Identity - Code Maze\" \/>\n<meta property=\"og:description\" content=\"In this article, we are going to learn about the Authentication process with ASP.NET Core Identity, Logout process and adding additional Claims.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/\" \/>\n<meta property=\"og:site_name\" content=\"Code Maze\" \/>\n<meta property=\"article:published_time\" content=\"2020-02-03T07:00:52+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-06-03T10:31:37+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/Authentication.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"620\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Marinko Spasojevi\u0107\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/CodeMazeBlog\" \/>\n<meta name=\"twitter:site\" content=\"@CodeMazeBlog\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Marinko Spasojevi\u0107\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/\"},\"author\":{\"name\":\"Marinko Spasojevi\u0107\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533\"},\"headline\":\"Authentication With ASP.NET Core Identity\",\"datePublished\":\"2020-02-03T07:00:52+00:00\",\"dateModified\":\"2024-06-03T10:31:37+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/\"},\"wordCount\":1294,\"commentCount\":37,\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/Authentication.png\",\"keywords\":[\"Asp.NET Core Identity\",\"authentication\",\"ClaimsIdentiy.Application\",\"identity\"],\"articleSection\":[\"C#\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/\",\"url\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/\",\"name\":\"Authentication With ASP.NET Core Identity - Code Maze\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/Authentication.png\",\"datePublished\":\"2020-02-03T07:00:52+00:00\",\"dateModified\":\"2024-06-03T10:31:37+00:00\",\"description\":\"In this article, we are going to learn about the Authentication process with ASP.NET Core Identity, Logout process and adding additional Claims.\",\"breadcrumb\":{\"@id\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#primaryimage\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/Authentication.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/Authentication.png\",\"width\":1100,\"height\":620,\"caption\":\"Authentication with ASP.NET Core Identity\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/code-maze.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Authentication With ASP.NET Core Identity\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/code-maze.com\/#website\",\"url\":\"https:\/\/code-maze.com\/\",\"name\":\"Code Maze\",\"description\":\"Learn. Code. Succeed.\",\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/code-maze.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/code-maze.com\/#organization\",\"name\":\"Code Maze\",\"url\":\"https:\/\/code-maze.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"width\":3511,\"height\":3510,\"caption\":\"Code Maze\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/CodeMazeBlog\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533\",\"name\":\"Marinko Spasojevi\u0107\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg\",\"caption\":\"Marinko Spasojevi\u0107\"},\"description\":\"Hi, my name is Marinko Spasojevic. Currently, I work as a full-time .NET developer and my passion is web application development. Just getting something to work is not enough for me. To make it just how I like it, it must be readable, reusable, and easy to maintain. Prior to being an author on the CodeMaze blog, I had been working as a professor of Computer Science for several years. So, sharing knowledge while working as a full-time developer comes naturally to me.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/marinko-spasojevic\/\",\"https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog\"],\"url\":\"https:\/\/code-maze.com\/author\/marinko\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Authentication With ASP.NET Core Identity - Code Maze","description":"In this article, we are going to learn about the Authentication process with ASP.NET Core Identity, Logout process and adding additional Claims.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/","og_locale":"en_US","og_type":"article","og_title":"Authentication With ASP.NET Core Identity - Code Maze","og_description":"In this article, we are going to learn about the Authentication process with ASP.NET Core Identity, Logout process and adding additional Claims.","og_url":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/","og_site_name":"Code Maze","article_published_time":"2020-02-03T07:00:52+00:00","article_modified_time":"2024-06-03T10:31:37+00:00","og_image":[{"width":1100,"height":620,"url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/Authentication.png","type":"image\/png"}],"author":"Marinko Spasojevi\u0107","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/CodeMazeBlog","twitter_site":"@CodeMazeBlog","twitter_misc":{"Written by":"Marinko Spasojevi\u0107","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#article","isPartOf":{"@id":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/"},"author":{"name":"Marinko Spasojevi\u0107","@id":"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533"},"headline":"Authentication With ASP.NET Core Identity","datePublished":"2020-02-03T07:00:52+00:00","dateModified":"2024-06-03T10:31:37+00:00","mainEntityOfPage":{"@id":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/"},"wordCount":1294,"commentCount":37,"publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"image":{"@id":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/Authentication.png","keywords":["Asp.NET Core Identity","authentication","ClaimsIdentiy.Application","identity"],"articleSection":["C#"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/","url":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/","name":"Authentication With ASP.NET Core Identity - Code Maze","isPartOf":{"@id":"https:\/\/code-maze.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#primaryimage"},"image":{"@id":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/Authentication.png","datePublished":"2020-02-03T07:00:52+00:00","dateModified":"2024-06-03T10:31:37+00:00","description":"In this article, we are going to learn about the Authentication process with ASP.NET Core Identity, Logout process and adding additional Claims.","breadcrumb":{"@id":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/code-maze.com\/authentication-aspnet-core-identity\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#primaryimage","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/Authentication.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/02\/Authentication.png","width":1100,"height":620,"caption":"Authentication with ASP.NET Core Identity"},{"@type":"BreadcrumbList","@id":"https:\/\/code-maze.com\/authentication-aspnet-core-identity\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/code-maze.com\/"},{"@type":"ListItem","position":2,"name":"Authentication With ASP.NET Core Identity"}]},{"@type":"WebSite","@id":"https:\/\/code-maze.com\/#website","url":"https:\/\/code-maze.com\/","name":"Code Maze","description":"Learn. Code. Succeed.","publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/code-maze.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/code-maze.com\/#organization","name":"Code Maze","url":"https:\/\/code-maze.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","width":3511,"height":3510,"caption":"Code Maze"},"image":{"@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/CodeMazeBlog"]},{"@type":"Person","@id":"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533","name":"Marinko Spasojevi\u0107","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/person\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg","caption":"Marinko Spasojevi\u0107"},"description":"Hi, my name is Marinko Spasojevic. Currently, I work as a full-time .NET developer and my passion is web application development. Just getting something to work is not enough for me. To make it just how I like it, it must be readable, reusable, and easy to maintain. Prior to being an author on the CodeMaze blog, I had been working as a professor of Computer Science for several years. So, sharing knowledge while working as a full-time developer comes naturally to me.","sameAs":["https:\/\/www.linkedin.com\/in\/marinko-spasojevic\/","https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog"],"url":"https:\/\/code-maze.com\/author\/marinko\/"}]}},"_links":{"self":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/51503","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/comments?post=51503"}],"version-history":[{"count":6,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/51503\/revisions"}],"predecessor-version":[{"id":117040,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/51503\/revisions\/117040"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media\/51514"}],"wp:attachment":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media?parent=51503"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/categories?post=51503"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/tags?post=51503"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}