Search code examples
c#asp.net-web-apiasp.net-identity

Get user ID for an external registered user


In our project we have a user management system build on the ASP.NET Identity framework. When a user registers by providing an email, username and password, everything works fine. We are able to get the users ID in the method in every controller that inherit "ApiController". However, now we are trying to implement external log in providers, and we are starting off with Facebook. The registration is going smooth, and the user is created in our database, just any other user, but without a PasswordHash of cause, and an access token is retured back to the client for further authorization.

All of that is working as it should, but when it comes to the part, where the programmer should be able to receive the users id with "User.Identity.GetUserId", we are having a little problem. The "User.Identity" is containing the right "userName" but the "GetUserId" is always returning "null".

The following is our registration method, and the generation of the access token

    [OverrideAuthentication]
    [AllowAnonymous]
    [HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
    [Route("RegisterExternal")]
    public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
    {
        try
        {
            if (!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }

            var verifiedAccessToken = await VerifyExternalAccessToken(model.Provider, model.AccessToken);
            if (verifiedAccessToken == null)
            {
                return BadRequest("Invalid Provider or External Access Token");
            }

            var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
            IdentityResult result = await UserManager.CreateAsync(user);
            if (!result.Succeeded)
            {
                return GetErrorResult(result);
            }

            var info = new ExternalLoginInfo()
            {
                DefaultUserName = model.UserName,
                Login = new UserLoginInfo(model.Provider, verifiedAccessToken.user_id)
            };
            var accessTokenResponse = GenerateLocalAccessTokenResponse(model.UserName, user.Id, model.Provider);

            return Ok(accessTokenResponse);
        }
        catch (Exception e)
        {
            return null;
        }
    }

    private JObject GenerateLocalAccessTokenResponse(string userName, string userid, string provider)
    {

        var tokenExpiration = TimeSpan.FromDays(1);

        ClaimsIdentity identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);

        identity.AddClaim(new Claim(ClaimTypes.Sid, userid));
        identity.AddClaim(new Claim(ClaimTypes.Name, userName));
        identity.AddClaim(new Claim("role", "user"));

        var props = new AuthenticationProperties()
        {
            IssuedUtc = DateTime.UtcNow,
            ExpiresUtc = DateTime.UtcNow.Add(tokenExpiration),
        };

        var ticket = new AuthenticationTicket(identity, props);

        var accessToken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);

        JObject tokenResponse = new JObject(
                                    new JProperty("userName", userName),
                                    new JProperty("access_token", accessToken),
                                    new JProperty("token_type", "bearer"),
                                    new JProperty("external_provider", provider),
                                    new JProperty("expires_in", tokenExpiration.TotalSeconds),
                                    new JProperty(".issued", ticket.Properties.IssuedUtc.ToString()),
                                    new JProperty(".expires", ticket.Properties.ExpiresUtc.ToString())
    );

        return tokenResponse;
    }

So all in all, every part of the registration is working as it should, we are just not able to receive the user id of the current user, when it uses an access token for a user created by an external provider.


Solution

  • Well, in case someone in the future needs the answer, it was because the "GetUserId" looked for the claim called "NameIdentifier", so changeing it, made it work.