MVC 5 OWIN login with claims and AntiforgeryToken. Do I miss a ClaimsIdentity provider?

25,806

Solution 1

Your claim identity does not have ClaimTypes.NameIdentifier, you should add more into claim array:

var claims = new List<Claim>
{
    new Claim(ClaimTypes.Name, "username"),
    new Claim(ClaimTypes.Email, "[email protected]"),
    new Claim(ClaimTypes.NameIdentifier, "userId"), //should be userid
};

To map the information to Claim for more corrective:

ClaimTypes.Name => map to username
ClaimTypes.NameIdentifier => map to user_id

Since username is unique also, so you are able to use username for anti-forgery token support.

Solution 2

In your Application_Start(), specify which Claim to use as the NameIdentifier:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        ...

        System.Web.Helpers.AntiForgeryConfig.UniqueClaimTypeIdentifier = 
            System.Security.Claims.ClaimTypes.NameIdentifier;

        ...
    }
}

See: http://brockallen.com/2012/07/08/mvc-4-antiforgerytoken-and-claims/

Solution 3

AntiForgeryConfig

One way to solve it is to set AntiForgeryConfig to use other ClaimType.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email;
}

Add NameIdentifier and IdentityProvider ClaimTypes

Alternatively, you can add NameIdentifier and IdentityProvider ClaimTypes to your claims.

List<Claim> _claims = new List<Claim>();
_claims.AddRange(new List<Claim>
{
    new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", _user.Email)),
    new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", _user.Email)
})

See: https://stack247.wordpress.com/2013/02/22/antiforgerytoken-a-claim-of-type-nameidentifier-or-identityprovider-was-not-present-on-provided-claimsidentity/

Solution 4

I used this on Global.asax.cs Application_Start() and solved the error:

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;

Solution 5

Your Global.asax.cs file should be like this:

namespace YOUR_PROJECT_NAME
{
    public class MvcApplication : System.Web.HttpApplication
    {
         protected void Application_Start()
         {
             AreaRegistration.RegisterAllAreas();
             RouteConfig.RegisterRoutes(RouteTable.Routes);
             AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
         }
    }
}

Means If its not like thta, You have to add this code to that:

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;

and Don't forget yo change "YOUR_PROJECT_NAME" with yours.

Share:
25,806

Related videos on Youtube

radbyx
Author by

radbyx

Backend developer at al dente. Former WebDeveloper at CapaSystems. I like to code in C#, MVC, JavaScript, Jquery, winforms, MSSQL, MySql ect. :) email: radbyx AT gmail DOT com

Updated on July 09, 2022

Comments

  • radbyx
    radbyx almost 2 years

    I'm trying to learn Claims for MVC 5 OWIN login. I try'ed to keep it as simple as possible. I started with the MVC template and inserted my claims code (see below). I get an error when I use the @Html.AntiForgeryToken() helper in the View.

    Error:

    A claim of type 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier' or  
    'http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovid    
    er' was not present on the provided ClaimsIdentity. 
    
    To enable anti-forgery token support with claims-based authentication, please verify that 
    the configured claims provider is providing both of these claims on the ClaimsIdentity 
    instances it generates. If the configured claims provider instead uses a different claim 
    type as a unique identifier, it can be configured by setting the static property 
    AntiForgeryConfig.UniqueClaimTypeIdentifier.
    
    Exception Details: System.InvalidOperationException: A claim of type
    'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier' or 
    'http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider' was 
    not present on the provided ClaimsIdentity. To enable anti-forgery token
    support with claims-based authentication, please verify that the configured claims provider 
    is providing both of these claims on the ClaimsIdentity instances it generates. 
    If the configured claims provider instead uses a different claim type as a unique 
    identifier, it can be configured by setting the static property 
    AntiForgeryConfig.UniqueClaimTypeIdentifier.
    
    Source Error:
    Line 4:      using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new 
    { id = "logoutForm", @class = "navbar-right" }))
    Line 5:      {
    Line 6:      @Html.AntiForgeryToken()
    

    POST Login action

    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }
    
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name, "Brock"),
            new Claim(ClaimTypes.Email, "[email protected]")
        };
        var id = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
    
        var ctx = Request.GetOwinContext();
        var authenticationManager = ctx.Authentication;
        authenticationManager.SignIn(id);
    
        return RedirectToAction("Welcome");
    }
    

    _LoginPartial.cshtml

    @using Microsoft.AspNet.Identity
    @if (Request.IsAuthenticated)
    {
        using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" }))
        {
        @Html.AntiForgeryToken()
    
        <ul class="nav navbar-nav navbar-right">
            <li>
                @Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
            </li>
            <li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
        </ul>
        }
    }
    

    I have tryed setting ClaimTypes.NameIdentifier (like in this SO answer)

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    
        AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
    }
    

    And then I "only?" get this error

    A claim of type 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier' was 
    not present on the provided ClaimsIdentity.
    

    I want to keep the antiforgeryToken because it can help against cross-site scripting.

  • radbyx
    radbyx almost 9 years
    I don't know what the mapping does. First I inserted the NameIdentifier too but got the same error. Then I tryed adding in Global.asax.cs without knowing what it does, but now it works. Maybe it's the same as your mapping? Global.asax.cs.: AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name; AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email; AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
  • OpTech Marketing
    OpTech Marketing about 6 years
    Thanks Travis, this fixed my issue right away.... Experienced it when applying Auto 0 to OWIN Asp.net
  • Manfred
    Manfred about 6 years
    The error message in the question mentions identityprovider which doesn't exist as a constant in ClaimTypes in ASP.NET MVC 4.6.1. Therefore it appears as if @travis-russi seems to fit better. In this answer new Claim(ClaimTypes.NameIdentifier, "userId') would suffice since AntiForgeryConfig.UniqueClaimTypeIdentifier is set to ClaimTypes.NameIdentifier.