0

I am developing an API in ASP.NET Core 8 using ASP.NET Core identity which uses 2FA with Authenticator app for users who have enabled it.

The problem is this. I have checked on the 2FA with Authenticator app implementation in Razor pages, and it creates a cookie by the name Identity.TwoFactorUserId and has value CfDJ8MEoYd_uBmxNsdLp... when the user logins with user name and password who has enabled 2FA. And this cookie is used to identify the user and validate the 2FA code from the Authenticator app

enter image description here

In my case I am using JWT for my API. So once a user who has enabled 2FA with Authenticator app logins with username and password, he will be prompted to enter the code from the authenticator app. But with my API, there is no way to identify the user when validating the 2FA code. How can i generate a code like above in the cookie which is like Identity.TwoFactorUserId and has value CfDJ8MEoYd_uBmxNsdLp... in my API? or is there any other better way so that once the user enters the username and passowrd, then i can send him the Identity.TwoFactorUserId like code so that the front end will again pass the same code with the 2FA code to identify the user?

7
  • "In my case i am using JWT for my AP" - Websites used by web-browsers can't use JWTs - they need to use normal browser cookies. If you have a web-service API that's used by non-human-driven clients then that's fine, but from a security perspective it's entirely separate from your web-application. Commented Mar 3, 2024 at 8:45
  • ...and I say "can't" with emphaiss, because using browser-based fetch() to authenticate using OAuth2/OIDC implicit flow (such that the JS code holds the access_token in-memory) is woefully insecure and prohibited in the next and upcoming revisions of OAuth and OIDC.. Commented Mar 3, 2024 at 8:46
  • "But with my API, there is no way to identify the user when validating the 2FA code." - You misunderstand the purpose of bearer-tokens: they're only issued after you authenticate the subject, and 2FA is part of authentication: it should not be possible to obtain a JWT bearer token for your system without having first authenticated through a browser-based flow (the only exception is non-human clients using client_credentials flow, but those won't be issued any tokens containing claims for a human user) so there's no problem there. Commented Mar 3, 2024 at 8:51
  • yes, im issuing the jwt after the 2fa verification. no issue with that. Commented Mar 3, 2024 at 10:35
  • So what's the problem then? You don't necessarily need to issue a cookie in-between the username+password step and the 2FA step: an <input type="hidden"> does the same job (and arguably more reliably too). Commented Mar 3, 2024 at 10:37

2 Answers 2

2

For temporary token you could generate random string with the expiration time. by using this token you can maintain the state between login and 2FA verification.

sample code:

2FA Initiation:

public IActionResult Login(LoginModel model)
{
    // ... Login code

    if (IsTwoFactorRequired(user))
    {
        var twoFactorToken = GenerateTwoFactorToken(user.Id);
        // Save the token somewhere e.g database, with expiration time
        StoreTwoFactorToken(twoFactorToken);

        // Return this token to the client
        return Ok(new { twoFactorToken });
    }

    // ... Generate JWT if not using 2FA
}

Generate a token for the user, could be a GUID, or an encrypted value that contains the user ID:

private string GenerateTwoFactorToken(string userId)
{
    return Convert.ToBase64String(RandomNumberGenerator.GetBytes(64));
}

2FA Verification:

public IActionResult VerifyTwoFactor(string twoFactorToken, string twoFactorCode)
{
    if (ValidateTwoFactorToken(twoFactorToken))
    {
        // Get the user based on the Token
        var userId = GetUserIdFromToken(twoFactorToken);

        if (ValidateTwoFactorCode(userId, twoFactorCode))
        {
            // Generate JWT and return to the client
            var token = GenerateJwtToken(userId);
            return Ok(new { token });
        }
    }

    return Unauthorized();
}

Validate the format and, optionally, the existence of the token in the database or cache:

private bool ValidateTwoFactorToken(string twoFactorToken)
{
    // Token validation code
}
Sign up to request clarification or add additional context in comments.

1 Comment

"You can't use cookie as apis are meant to be stateless." - Cookies have nothing to do with whether or not a web-service is stateless or not: a cookie is just a browser-managed state-blob, just like a bearer-token is for non-browser-based clients. I imagine you're thinking of server-side session-state (which is predicated on having some kind of lightweight, reference-based, session-cookie) - but that's not the same thing as saying using any cookies make a web-service stateful (because they don't).
0

I was having the same issue (ASP.NET Core WebApi with Angular)

I had two methods to authenticate the user

  • normal login: (email, password)
  • provider: (google)

I implemented a method to enable TFA

but when TFA is enabled, and need to enter the TFA code from Google Authenticator.

cannot get the user data await _signInManager.GetTwoFactorAuthenticationUserAsync(); (cannot validate TFA)

so, the solution when you login send { withCredentials: true } in your request options to let ASP add a cookie in your browser also when sending the request to validate TFA

do not forget to .AllowCredentials() in your cors

method to normal login: SignInResult result = await _signInManager.PasswordSignInAsync(user: user, password: _user.Password, isPersistent: true, lockoutOnFailure: true);

with provider: SignInResult signInResult = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: true);

1 Comment

is it possible to provide a sample repo on github if possible so i can have look at it please

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.