mvdan / bitw

Minimalist BitWarden client

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

2FA login doesn't work with captchas

kkga opened this issue · comments

Getting the following after typing in my password. I have only OTP in the 2FA settings, if that's relevant.

error: could not login via password: Bad Request: {"error":"invalid_grant","error_description":"Auth-Email header invalid."}

Interesting, I haven't seen this one before. I just re-ran the test suite, which includes doing a two-factor auth against bitwarden.com, and it failed in exactly the same way:

$ source secrets && go test
--- FAIL: TestScripts (0.01s)
    --- FAIL: TestScripts/login-tfa (5.95s)
        testscript.go:397: 
            # Ensure we haven't logged in. (0.000s)
            # This is a test account with a dummy password, and no two-factor auth set up. (0.000s)
            # Login will work, granted the password is present. (0.000s)
            # Check invalid 2fa method selections. (5.952s)
            > stdin badprovider.stdin
            > ! bitw login
            [stderr]
            error: could not login via password: Bad Request: {"error":"invalid_grant","error_description":"Auth-Email header invalid."}
            [exit status 1]
            > cmp stderr badprovider.stderr
            --- stderr
            +++ badprovider.stderr
            @@ -1,1 +0,0 @@
            -error: could not login via password: Bad Request: {"error":"invalid_grant","error_description":"Auth-Email header invalid."}
            @@ -0,0 +1,4 @@
            +1) Six-digit authenticator token
            +2) Six-digit email token (te*********@mvdan.cc)
            +Select a two-factor auth provider [1-2]: 
            +error: could not obtain two-factor auth token: selected option 33 is not within the range [1-2]
            
            FAIL: testdata/scripts/login-tfa.txt:22: stderr and badprovider.stderr differ

It seems like bitwarden changed their API in some breaking way. We'll need to figure out what needs to change on our end.

Found it in the upstream source code: bitwarden/server#1604

Seems like we need to set an HTTP header.

#32 is ready if you'd like to review or confirm that it fixes the problem for you.

Now I'm getting the following:

error: could not login via password: Bad Request: {"error":"invalid_grant","error_description":"Captcha required.","HCaptcha_SiteKey":"bc38c8a2-5311-4e8c-9dfc-49e99f6df417"}

Hm, I've never tested an account with a captcha, so it's not surprising that it doesn't work. I only tested one two-factor authentication method, available with free accounts: a TOTP.

Err, reopening for the 2FA issue.

Hmm, I don't have captcha in the 2FA settings.
I do have a paid account, but I'm only using the standard OTP method for 2FA.

Perhaps the site thought your API usage is bot-like and served a captcha? I'm really not sure. The problem is that bitwarden's API is fairly obscure, especially when it comes to authentication, so a significant portion is reverse-engineered. Just see the digging I had to do with that weird base64-encoded HTTP header.

Another good example is how CI on master is currently broken, because the end-to-end test doing a 2FA login seems to time out after ten seconds. I'm not sure why that happens - the bitwarden API also times out when supplying the 2FA token here as well. It's just a mystery.

Perhaps the site thought your API usage is bot-like and served a captcha?

I'm using the standard Bitwarden server, if that's what you mean. Here's the config output:

$ bitw config         
email       = "x@kkga.me"
apiURL      = "https://api.bitwarden.com"
identityURL = "https://identity.bitwarden.com"

Is there any other way I can help debug this? I would really love to use this as I like the integration with d-bus and secret-tools.

Right, I do mean that perhaps api.bitwarden.com requested a captcha for some reason. I haven't heard of such a thing before, unless it's an auth setting that you enabled, which doesn't seem to be the case.

Is there any other way I can help debug this?

Go is not a particularly hard language, so you could add debug prints via fmt.Println to try to see what's going on.

After some light googling I found https://www.reddit.com/r/Bitwarden/comments/q5y1ez/how_can_i_turn_off_the_hcaptcha_for_my_login_with/, which says:

The captcha is at the API, so it cannot be disabled at the client, but it is configured to only prompt if the API detects non-human behavior. Are you experiencing this prompt often?

So it seems like the fix would be that, if the client sees the server asking us to solve a captcha, the client should show the captcha to the user and ask for the answer - then send that to the server.

It seems like that Reddit thread has an upstream engineer in it, so I've asked them if they could document their API better.

@mvdan It seems that using an API key would avoid the captcha. Look at this thread for more info bitwarden/cli#383

@blacs30 thank you, that's useful. So it looks like we have one of two options:

  1. Tell the user to solve a captcha manually on first login. The server will then remember the device. Unclear how the API requests and responses look like for this case - as far as I can tell, it's not documented. Testing would also have to be pretty manual.

  2. Tell the user to authenticate with an API token rather than user and password. Perhaps the better solution long-term. There are some parallels, such as how the new GitHub CLI tells you to set up an API token, as their API no longer allows directly authenticating via passwords.

My instinct is to go with 2, because we'll just never had a good CLI UX with captchas.

Was looking around and found that this rust Bitwarden client is logging in via apikey once to register the device, as they call it, to the api server which prevents the captcha from appear in later queries.

FYI, with the official Bitwarden cli the login flow with the api key is this:

  • bw login --apikey this asks for the client_id and client_secret but it doesn't unlock the vault
  • bw unlock to unlock the vault and get a session token

I'm getting the same error:

error: could not login via password: Bad Request: {"error":"invalid_grant","error_description":"Captcha required.","HCaptcha_SiteKey":"bc38c8a2-5311-4e8c-9dfc-49e99f6df417"}

And I dont have 2FA active

I worked on a fix using, the api login method.
Now I'm making the code more clear expect a PR some time soon.

Thanks, @AlecsFerra! I've left you a review. Others are more than welcome to help review and test.