6

I'm following along the bitoftech tutorial about creating Identity and role based claims with JWT. My application user is a custom User table with int PK.

Currently, the GenerateUserIdentityAsync method just returns a weird UserId not found error. here's my code:

ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT");

and the implementation in User entity:

public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User, int> manager, string authenticationType)
{
    //error on this line: CreateIdentityAsync throws error
    var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
    return userIdentity;
}

My UserManager class is defined like so:

public class AppUserManager : UserManager<User, int>

Weirdly enough, when I debug, the instance this in GenerateIdentityAsync does have a UserId property, but the base only has an id and I wonder if that is where it's erroring out? (it doesnt sound right)

I was looking at the source code (line 80) but I can't figure out where the exception is being thrown.

The exact exception being thrown is:

 UserId not found. 
 Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: 
    System.InvalidOperationException: 
    UserId not found.

And stack trace isn't all that helpful (to me)

How do I find out why / where the UserId is not available?


Mode details:

My GrantResourceOwnerCredentials():

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
    context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] {"*"});

    var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
    User user = await userManager.FindAsync(context.UserName, context.Password);

    if (user == null) // this is NOT null
    {
        context.SetError("invalid_grant", "The username or password is incorrect");
        return;
    }

    // this line fails
    ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, "JWT"); 
    var ticket = new AuthenticationTicket(oAuthIdentity, null);
    context.Validated(ticket);
}

And the ApplicationUser (which, in my case, is just User)

public partial class User : IdentityUser<int, CustomUserLogin, CustomUserRole, CustomUserClaim>
{  
    public int UserId { get; set; }
    public string Fullname { get; set; }
    public string Address { get; set; }
    public string ContactNumber { get; set; }
}
1
  • Verify in your aspnet db if you have the correct column names (UserId instead of Id or vice versa). Also one possibility is of column type mismatch (uniqueidentifiers as against nvarchar(256)). Commented Jan 26, 2016 at 15:26

6 Answers 6

6
+100

As you found out while debugging IdentityUser has an Id which in your case would represent the User's Id.

You need to remove the UserId from your User class, use the base Id from IdentityUser and rename the UserId column in your custom User table to Id.

Any properties you have in your User class needs to also have a matching column in your user table in the database. If not then you will get the same error for properties that do not match.

That would mean Fullname, Address and ContactNumber must have matching column names in the AspNetUsers table or else you will get the same error for those properties as well.

Sign up to request clarification or add additional context in comments.

8 Comments

hi, made these changes in mine, but still hitting the same error; I'm now question if UserId is what I think it is, there is no inner exception, only stack trace but that's not of much help unfortunately. Your code above pulls user twice, which is not a problem if it worked, I could refactor later, but it's still throwing the exact same exception
@LocustHorde, I went back to the drawing board and rechecked your problem. Using the additional information you provided I was able to recreate the same exception, Including the inner exception. UserId needs to be a valid column in the AspNetUsers Table. I think a previous commenter also indicated this as well.
Excellent! After your comment I noticed there were two UserId as well as Id columns in by table, and in my seed method I was just populating UserId, and the Id was zero. When I tried to login, for whatever reason the method kept throwing UserId is not found. Once I manually changed the zero to an integer, it started working okay! So I guess I have to remove Id and somehow tell Identity to use UserId instead...
Whoops, just saw your edit, let me follow that up, thanks!
@LocustHorde that would be correct. I'll check that as well and update my answer. Are you doing code first or connecting to an existing table?
|
3

You have both UserId and Id properties in your User class - Id is inherited from IdentityUser. The problem is that you probably configured UserId to be the primary key for User.

The exception you get is thrown in ClaimsIdentityFactory.CreateAsync method, on line 97 UserManager.GetSecurityStampAsync. As you can see, user.Id used for retrieving a security stamp.

If you look inside UserManager.GetSecurityStampAsync you will see that the exception you get is thrown exactly here:

public virtual async Task<string> GetSecurityStampAsync(TKey userId)
{
    ThrowIfDisposed();
    var securityStore = GetSecurityStore();
    var user = await FindByIdAsync(userId).WithCurrentCulture();
    if (user == null)
    {
        throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.UserIdNotFound,
            userId));
    }
    return await securityStore.GetSecurityStampAsync(user).WithCurrentCulture();
}

Thus, remove UserId property from User class and start using Id (inherited from IdentityUser) instead.

Comments

3

I faced exact same issue. After much of a head ache I could sort out the real problem. When you change data type of the Id property of User class to string, a Guid().ToString() is assigned to the Id property in the constructor and the same value is saved to the database and Identity retrieves the user details using that value.

However, if you changed the data type of the Id property to int and did not provide a value for that property in the constructor, the Identity still tries to retrieve the User details by using the default int value (0) this causes throws the message "System.InvalidOperationException: UserId not found".

I solved this by retrieving the value from the database by command.ExecuteScalar() and assign the value to user.Id. Hope this will help some one facing similar problem.

4 Comments

Hi @vkuttyp, what constructor are you talking about? Thanks.
can you share a bit more details? where did you exactly set that user.Id ? thanks
Hi @chemitaxis, the constructor I mentioned is the IdentityUser class constructor.
Hi. The actual issue that I faced was not related to the question. My issue was coming from creating new user. So what I did was after inserting new user to the database retrieved the primary key from database and updated that to the user object.
2

What does your ApplicationUser class look like? What does this method look like in your application?

public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context){}

Taiseer's comments about GrantResourceOwnerCredentials are:

"we are building an identity for the logged in user, this identity will contain all the roles and claims for the authenticated user"

I had to add the ClaimTypes.NameIdentifier to the ClaimsIdentity to resolve a similar issue. Here is the important part of my GrantResourceOwnerCredentials method:

ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);

if (user == null)
{
    context.SetError("invalid_grant", "The user name or password is incorrect.");
    return;
}

var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()));

3 Comments

Hi, added both code blocks above; you're not using JWT?
I tried it with DefaultAuthenticationTypes.ApplicationCookie and still the same error, I guess I can rule out JWT interfering with it at least for now
Correct, I was not using JWT.
1

In my case, this error happened because I added another SignInManager inside the method Login in the Account Controller (following an example of adding a role). It was executing SignInManager.PasswordSignInAsync and SignInManager.SignInAsync in the same method and this calls GenerateUserIdentityAsync(...) in ApplicationUser twice, for which the first one succeeded and the second one gave me the exception "UserId" Not Found.

Comments

-1

Server=xxxx;Initial Catalog=xxxx;;User ID=xxxx_user;Password=xxxx; where user id has a space in it as opposed to Server=xxxx;Initial Catalog=xxxx;;UserID=xxxx_user;Password=xxxx; WRONG!!!!!!! See https://www.connectionstrings.com/sql-azure/ for confirmation.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.