Open jaymzh opened 6 years ago
Oh - so it looks like you can make it work, if, before you put in the 2fac code, you go to the site, then click the "did you log in", click yes, then click "save browser", THEN go back to pidgin and put in the code it works, at least for normal fb.
OH! And it works for Workplace too [but the alert comes up on non-workplace]. I'll leave this open for others to find and I'll comment on the workplace thread.
Aaaand, no that stopped working. :(
@dequis - as of now there's no Facebook or Workplace if you use 2fac (which ... I hope most people do). Pretty please for christmas all I want is a chat client? :) :)
Can't repro :/
19:44 <@dx|fb-2> ac on
19:44 <@root> Trying to get all accounts connected...
19:44 <@root> facebook - Logging in: Authenticating
19:44 <@root> facebook - Login error: Login approvals are on. Expect an SMS shortly with a code to use for log in (406)
19:44 <@root> facebook - Logging in: Signing off..
19:44 <@root> facebook - Logging in: Reconnecting in 5 seconds..
19:44 <@dx|fb-2> ac off
19:44 <@root> Deactivating all active (re)connections...
19:45 <@dx|fb-2> ac facebook set password '028470'
19:45 <@root> Setting changed successfully
19:45 <@dx|fb-2> ac facebook on
19:45 <@root> facebook - Logging in: Authenticating
19:45 <@root> facebook - Logging in: Fetching contacts
19:45 <@root> facebook - Logging in: Connecting
19:45 <@root> facebook - Logging in: Logged in
19:50 <@dx|fb-work2> ac add facebook [...]
19:50 <@root> Account successfully added with tag facebook
19:50 <@root> You can now use the /OPER command to enter the password
19:50 <@root> Password added to IM account facebook
19:50 <@dx|fb-work2> ac facebook set work on
19:50 <@root> work = `on'
19:50 <@dx|fb-work2> ac facebook on
19:50 <@root> facebook - Logging in: Authenticating
19:50 <@root> facebook - Login error: Login approvals are on. Expect an SMS shortly with a code to use for log in (406)
19:50 <@root> facebook - Logging in: Signing off..
19:50 <@root> facebook - Logging in: Reconnecting in 5 seconds..
19:50 <@dx|fb-work2> ac facebook off
19:50 <@root> Reconnect cancelled
19:50 <@dx|fb-work2> ac facebook set password 736178
19:50 <@root> Setting changed successfully
19:50 <@dx|fb-work2> ac facebook on
19:50 <@root> facebook - Logging in: Authenticating
19:50 <@root> facebook - Logging in: Fetching contacts
19:50 <@root> facebook - Logging in: Connecting
19:50 <@root> facebook - Logging in: Logged in
I should have sent you a debug log, I suck. Doing so now.
So I sent you pidgin debug logs, but just for fun I also tried bitlbee:
11:50 <@phil> account add facebook jaymzh "XXXXXXXXXXXXXXXXXX"
11:50 <@root> Account successfully added with tag facebook
11:50 <@phil> ac on
11:50 <@root> Trying to get all accounts connected...
11:50 <@root> facebook - Logging in: Authenticating
11:51 <@root> facebook - Login error: Login approvals are on. Expect an SMS shortly with a code to use for log in (406)
11:51 <@root> facebook - Logging in: Signing off..
11:51 <@root> facebook - Logging in: Reconnecting in 5 seconds..
11:51 <@root> facebook - Logging in: Authenticating
11:51 <@root> facebook - Login error: Login approvals are on. Expect an SMS shortly with a code to use for log in (406)
11:51 <@root> facebook - Logging in: Signing off..
11:51 <@root> facebook - Logging in: Reconnecting in 15 seconds..
11:51 <@phil> ac off
11:51 <@root> Deactivating all active (re)connections...
11:51 <@phil> ac facebook set password '881202'
11:51 <@root> Setting changed successfully
11:51 <@phil> ac on
11:51 <@root> Trying to get all accounts connected...
11:51 <@root> facebook - Logging in: Authenticating
11:51 <@root> facebook - Login error: Invalid username or password (401)
11:51 <@root> facebook - Logging in: Signing off..
I looked around, seems that there's a new auth path like this:
two_factor
login_first_factor
in error_data
in the original error message (seems fairly constant for me),I drafted an implementation of this with a python script, but the server doesn't like something about it, says "error_msg":"An unknown error occurred (1)"
. I'm going to need to sniff actual requests to find what i'm doing wrong, and my debugging tooling is in a different continent... Seems unlikely that I'll have time to rebuild that soon.
FWIW my dirty request signing script (python2)
import cgi
from urllib import urlencode
import hashlib
FB_API_KEY = '256002347743983'
FB_API_SECRET = '374e60f8b9bb6b8cbb30f78030438895'
def fb_sig(data):
params = ''.join(['%s=%s' % x for x in sorted(data.items())])
data['sig'] = hashlib.md5(params + FB_API_SECRET).hexdigest()
return data
data = {}
data['api_key'] = FB_API_KEY
data['format'] = 'json'
data['method'] = 'auth.login'
data['email'] =... '...'
data['password'] = '...'
#data['credentials_type'] = 'two_factor'
#data['error_detail_type'] = 'button_with_disabled'
#data['first_factor'] = '...'
#data['twofactor_code'] = '...'
#data['password'] = data['twofactor_code']
print("curl 'https://b-api.facebook.com/method/auth.login' -v --data-binary '" + urlencode(fb_sig(data)) + "'")
Replace the ...
, run, run its output, uncomment block of #data
, fill their ...
. Not really adding many details here because I'm sure some part is wrong. If I leave out credentials_type
it works, but that's just because my "server" still supports the old method of using password for twofactor_code, I bet.
If you somehow manage to get it working, set the hidden setting token
to the value of access_token. In purple it's accounts.xml stuff I think.
OK, I'm trying to play with this, but what is data['first_factor']
supposed to be? I treid setting it to data['password']
but that still gives me An unknown error occurred
.
The error message of the first login attempt has a login_first_factor
string in it, I copied that. It could be wrong, though.
Ah I see now, I missed that. So I tried that, and I tried both overriding data['password']
as you did, but also leaving it with the password, and both ways I get:
{"error_code":1,"error_msg":"An unknown error occurred (1)","request_args":[{"key":"method","value":"auth.login"},{"key":"api_key","value":"256002347743983"},{"key":"format","value":"json"},{"key":"first_factor","value":"XXXXXXXXXXXXXXX"},{"key":"credentials_type","value":"two_factor"},{"key":"sig","value":"YYYYYYYYYYYYYy"},{"key":"twofactor_code","value":"AAAAAAAAA"},{"key":"password","value":"--sanitized--"},{"key":"error_detail_type","value":"button_with_disabled"},{"key":"email","value":"phil\u0040ipom.com"}]}
BTW, for anyone else playing along at home, I modified the script slightly to make it a bit easier to use:
#!/usr/bin/python
import sys
import cgi
from urllib import urlencode
import hashlib
import getpass
FB_API_KEY = '256002347743983'
FB_API_SECRET = '374e60f8b9bb6b8cbb30f78030438895'
def fb_sig(data):
params = ''.join(['%s=%s' % x for x in sorted(data.items())])
data['sig'] = hashlib.md5(params + FB_API_SECRET).hexdigest()
return data
data = {}
data['api_key'] = FB_API_KEY
data['format'] = 'json'
data['method'] = 'auth.login'
data['email'] = 'YOUR_EMAIL_HERE'
if len(sys.argv) > 1:
data['credentials_type'] = 'two_factor'
data['error_detail_type'] = 'button_with_disabled'
data['first_factor'] = sys.argv[1]
data['twofactor_code'] = sys.argv[2]
data['password'] = data['twofactor_code']
else:
data['password'] = getpass.getpass()
print("curl 'https://b-api.facebook.com/method/auth.login' -v --data-binary '" + urlencode(fb_sig(data)) + "'")
You can run it once with no argument, and then the second time pass in the first_factor as arg1 and the SMS code as the second arg, like:
$ fb_test.py
Password: <enter your password here>
curl ....
$ fb_test.py XXXXXX 123456
curl ....
Continuing to mess with this I made the script just do the requests for you and prompt you for the bits it needs:
#!/usr/bin/python
import sys
import cgi
from urllib import urlencode
import hashlib
import getpass
import httplib
import urllib
import json
from optparse import OptionParser
DEBUG = False
FB_API_KEY = '256002347743983'
FB_API_SECRET = '374e60f8b9bb6b8cbb30f78030438895'
def fb_sig(data):
newdata = data.copy()
params = ''.join(['%s=%s' % x for x in sorted(data.items())])
newdata['sig'] = hashlib.md5(params + FB_API_SECRET).hexdigest()
return newdata
def debug(msg):
global DEBUG
if DEBUG:
print "DEBUG: %s", msg
parser = OptionParser()
parser.add_option('-d', '--debug', action='store_true', dest='debug', default=False)
(options, args) = parser.parse_args()
if options.debug:
DEBUG = True
data = {}
data['api_key'] = FB_API_KEY
data['format'] = 'json'
data['method'] = 'auth.login'
data['email'] = ''
if data['email'] == '':
print "ERROR: set an email address, please"
sys.exit()
data['password'] = getpass.getpass()
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "*/*"}
conn = httplib.HTTPSConnection('b-api.facebook.com:443')
params = urllib.urlencode(fb_sig(data))
conn.request('POST', '/method/auth.login', params, headers)
response = conn.getresponse()
debug("status, reason: %s, %s" % (response.status, response.reason))
response_data = response.read()
debug("undecoded response: %s" % response_data)
response = json.loads(response_data)
debug(response)
first_fac = json.loads(response['error_data'])['login_first_factor']
data['credentials_type'] = 'two_factor'
data['error_detail_type'] = 'button_with_disabled'
data['first_factor'] = first_fac
data['twofactor_code'] = getpass.getpass('Code: ')
data['password'] = data['twofactor_code']
params = urllib.urlencode(fb_sig(data))
conn.request('POST', '/method/auth.login', params, headers)
response = conn.getresponse()
debug("status, reason: %s, %s" % (response.status, response.reason))
response_data = response.read()
debug("undecoded response: %s" % response_data)
response = json.loads(response_data)
print response
Hey @dequis what's the easiest way to see what the official apps do? I can try debugging, but since it's all SSL, I'm not sure the easiest way to see what's going on..
Yeah I just need to rebuild my MITM setup, see:
I'm going to need to sniff actual requests to find what i'm doing wrong, and my debugging tooling is in a different continent... Seems unlikely that I'll have time to rebuild that soon.
For values of "soon" of "one week" which is over now. I'll look into this and other things this weekend, because apparently someone broke other parts of fb, sync sequences are sometimes gone and receiving messages goes on a different queue. Also the TLS 1.3 thing because why not.
FWIW I documented the stuff I did with earlier versions at https://wiki.dequis.org/notes/facebook/ - but it's been long enough that I bet the cert pinning methods changed again.
OK cool, thanks. If I get time to set that stuff up, I'll poke at it, but I'm guessing you'll get to the bottom of this faster than I will.
I didn't have a big enough block of time this weekend to try to setup the whole MITM setup unfortunately. Did you get a chance to look?
Nope, I only had enough time to sort the other issues (and one of them was just because someone else came up with the fix which was just bumping a version in the user agent lol).
On the bright side I am no longer technically-homeless!
Having a place to live is definitely more important than fixing my bugs! I'm glad you have a place to live :)
Thought I'd follow up here and see if you had made any progress. As always, happy to donate to you (or your favorite charity) to help the cause.
Hi! Sorry, nothing. My next two weekends are already fully booked and evenings ceased to exist. Also thanks for the offer (i genuinely appreciate it) but it wouldn't really buy me more time.
I just tried again (in case they reverted whatever thing they were rolling out), and neither normal Facebook nor workplace work with 2fac, so I (and probably others) still have no ability to use purple-facebook at all.
@jaymzh @dequis
Just active app password in FB.
Settings > Security and Login > App Password > Create an app password.
Then login with that password and your FB username.
It's working for me.
Thanks
This did not work for me when I filed the Issue, but it does work now! It even works on Workplace!
nice. works for me now, too. previously app passwords did not work.
{"error_code":1,"error_msg":"An unknown error occurred (1)","request_args":[{"key":"method","value":"auth.login"},{"key":"api_key","value":"256002347743983"},{"key":"format","value":"json"},{"key":"first_factor","value":"XXXXXXXXXXXXXXX"},{"key":"credentials_type","value":"two_factor"},{"key":"sig","value":"YYYYYYYYYYYYYy"},{"key":"twofactor_code","value":"AAAAAAAAA"},{"key":"password","value":"--sanitized--"},{"key":"error_detail_type","value":"button_with_disabled"},{"key":"email","value":"phil\u0040ipom.com"}]}
Hi. Have you solved this problem yet? please help me
Very late to the party but if someone needs this, these parameters should work
base_data = {
"fb_api_req_friendly_name": "authenticate",
"locale": "en",
"email": self.email,
"password": self.password,
"format": "json",
"api_key": FB_ANDROID_MESSENGER_API_KEY,
"method": "auth.login",
"generate_session_cookies": "1",
"generate_machine_id": "1",
"device_id": self.device_id,
}
data = base_data.copy()
data["twofactor_code"] = input("2fa code here: ")
data["credentials_type"] = "two_factor"
data["error_detail_type"] = "button_with_disabled"
data["first_factor"] = error_data["login_first_factor"]
data["password"] = data["twofactor_code"]
data["userid"] = error_data["uid"]
data["machine_id"] = error_data["machine_id"]
# data_dict["currently_logged_in_userid"] = data_dict["0"] # does not need i think
@jackblk given that FB just killed app passwords, this is very timely.
Where you able to use this to somehow get the pidgin plugin to work?
Also where are you getting self.device_id
from, @jackblk ?
OK, just shoving in a UUID seems to work. Combining @jackblk 's stuff with my previous script, this seems to work. Jam your email and a random UUID at the top
#!/usr/bin/python2.7
import sys
import cgi
from urllib import urlencode
import hashlib
import getpass
import httplib
import urllib
import json
from optparse import OptionParser
DEBUG = False
# put a UUID in here
MACHINE_ID = ''
# put your email in here
EMAIL = ''
FB_API_KEY = '256002347743983'
FB_API_SECRET = '374e60f8b9bb6b8cbb30f78030438895'
def fb_sig(data):
newdata = data.copy()
params = ''.join(['%s=%s' % x for x in sorted(data.items())])
newdata['sig'] = hashlib.md5(params + FB_API_SECRET).hexdigest()
return newdata
def debug(msg):
global DEBUG
if DEBUG:
print "DEBUG: %s", msg
if EMAIL == '':
print "ERROR: set an email address, please"
sys.exit()
if MACHINE_ID == '':
print "ERROR: set a machine id (to any UUID), please"
sys.exit()
parser = OptionParser()
parser.add_option('-d', '--debug', action='store_true', dest='debug', default=False)
(options, args) = parser.parse_args()
if options.debug:
DEBUG = True
data = {
"fb_api_req_friendly_name": "authenticate",
"locale": "en",
"format": "json",
"api_key": FB_API_KEY,
"method": "auth.login",
"generate_session_cookies": "1",
"generate_machine_id": "1",
"email": EMAIL,
"device_id": MACHINE_ID,
}
data['password'] = getpass.getpass()
headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "*/*"}
conn = httplib.HTTPSConnection('b-api.facebook.com:443')
params = urllib.urlencode(fb_sig(data))
conn.request('POST', '/method/auth.login', params, headers)
response = conn.getresponse()
debug("status, reason: %s, %s" % (response.status, response.reason))
response_data = response.read()
debug("undecoded response: %s" % response_data)
response = json.loads(response_data)
debug(response)
error_data = json.loads(response['error_data'])
first_fac = error_data['login_first_factor']
data['credentials_type'] = 'two_factor'
data['error_detail_type'] = 'button_with_disabled'
data['first_factor'] = first_fac
data['twofactor_code'] = getpass.getpass('Code: ')
data['password'] = data['twofactor_code']
data['userid'] = error_data['uid']
data['machine_id'] = error_data['machine_id']
params = urllib.urlencode(fb_sig(data))
conn.request('POST', '/method/auth.login', params, headers)
response = conn.getresponse()
debug("status, reason: %s, %s" % (response.status, response.reason))
response_data = response.read()
debug("undecoded response: %s" % response_data)
response = json.loads(response_data)
print response
But doing as @dequis recommended and putting the resulting access_token
into token
into accounts.xml does not work for me, I still get a "Login approvals are on..." error. Also 'stoken' keeps showing up. I put the token into both token and stoken, but I haven't made it work yet. Anyone else?
@jackblk given that FB just killed app passwords, this is very timely.
Where you able to use this to somehow get the pidgin plugin to work?
Well app password is dead so my app is dead too, so I try to find a way for 2fa. I currently don't use pidgin anymore so I'm not sure 😢. But the token & cookies are usable for my app.
OK, just shoving in a UUID seems to work. Combining @jackblk 's stuff with my previous script, this seems to work. Jam your email and a random UUID at the top
#!/usr/bin/python2.7 import sys import cgi from urllib import urlencode import hashlib import getpass import httplib import urllib import json from optparse import OptionParser DEBUG = False # put a UUID in here MACHINE_ID = '' # put your email in here EMAIL = '' FB_API_KEY = '256002347743983' FB_API_SECRET = '374e60f8b9bb6b8cbb30f78030438895' def fb_sig(data): newdata = data.copy() params = ''.join(['%s=%s' % x for x in sorted(data.items())]) newdata['sig'] = hashlib.md5(params + FB_API_SECRET).hexdigest() return newdata def debug(msg): global DEBUG if DEBUG: print "DEBUG: %s", msg if EMAIL == '': print "ERROR: set an email address, please" sys.exit() if MACHINE_ID == '': print "ERROR: set a machine id (to any UUID), please" sys.exit() parser = OptionParser() parser.add_option('-d', '--debug', action='store_true', dest='debug', default=False) (options, args) = parser.parse_args() if options.debug: DEBUG = True data = { "fb_api_req_friendly_name": "authenticate", "locale": "en", "format": "json", "api_key": FB_API_KEY, "method": "auth.login", "generate_session_cookies": "1", "generate_machine_id": "1", "email": EMAIL, "device_id": 'aba9641c-fed9-4af8-8d32-d12e0dafd506', } data['password'] = getpass.getpass() headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "*/*"} conn = httplib.HTTPSConnection('b-api.facebook.com:443') params = urllib.urlencode(fb_sig(data)) conn.request('POST', '/method/auth.login', params, headers) response = conn.getresponse() debug("status, reason: %s, %s" % (response.status, response.reason)) response_data = response.read() debug("undecoded response: %s" % response_data) response = json.loads(response_data) debug(response) error_data = json.loads(response['error_data']) first_fac = error_data['login_first_factor'] data['credentials_type'] = 'two_factor' data['error_detail_type'] = 'button_with_disabled' data['first_factor'] = first_fac data['twofactor_code'] = getpass.getpass('Code: ') data['password'] = data['twofactor_code'] data['userid'] = error_data['uid'] data['machine_id'] = error_data['machine_id'] params = urllib.urlencode(fb_sig(data)) conn.request('POST', '/method/auth.login', params, headers) response = conn.getresponse() debug("status, reason: %s, %s" % (response.status, response.reason)) response_data = response.read() debug("undecoded response: %s" % response_data) response = json.loads(response_data) print response
But doing as @dequis recommended and putting the resulting
access_token
intotoken
into accounts.xml does not work for me, I still get a "Login approvals are on..." error. Also 'stoken' keeps showing up. I put the token into both token and stoken, but I haven't made it work yet. Anyone else?
I was able to use this script and add the token and it worked. This is what I added into accounts.xml in the settings section:
<setting name='token' type='string'>(value of access_token)</setting>
I was able to use this script and add the token and it worked. This is what I added into accounts.xml in the settings section:
<setting name='token' type='string'>(value of access_token)</setting>
Aha!! I was missing the type attribute. Thanks!! That works!
Eh, I spoke to soon. It worked briefly. Then my account got locked. I unlocked it and now that gives me invalid username or password
Eh, I spoke to soon. It worked briefly. Then my account got locked. I unlocked it and now that gives me
invalid username or password
Oh scratch that. Had to update the password in pidgin (didn't realize it used that once it had a token).
Yeah me too. But I was able to solve it this way:
"device_id": 'aba9641c-fed9-4af8-8d32-d12e0dafd506',
I had to replace this with MACHINE_ID
and generate my own uuid into MACHINE_ID
, but then it worked! Thanks a lot for the script.
"device_id": 'aba9641c-fed9-4af8-8d32-d12e0dafd506',
I had to replace this with
MACHINE_ID
and generate my own uuid intoMACHINE_ID
, but then it worked! Thanks a lot for the script.
Ooops, fixed. Thanks!
I put some work into the script to make it a bit easier for people not familiar with python or dicts or other stuff. It will spit out errors in some common cases instead of crashing. It's also now in py3. Here's a script, that when you run it, looks like this:
$ pidgin-fb-login-test.py
Access Token generator for Facebook 2factor login
This tool will perform 2-factor login to FB and then print out an
access token needed for the FB plugin for bitlbee and pidgin. Take
the resulting code and put it in the "token" tag in accounts.xml
Password:
Code:
Access token: <.....>
You need to edit the script to add your email and a UUID (which you can get by running uuidgen
), but that's it. The script is here:
https://gist.github.com/jaymzh/3ed8817cf8c20222ca09ce33a544b695
Question about this process that I didn't see an obvious answer to:
if one does:
$ grep -A90 -i prpl-facebook accounts.xml | sed -n '/<\/account>/q;p' | grep setting | egrep 'id|token'
you can see that there already exists some data that looks like it's trying to use in the script:
<setting name='cid' type='string'>${CID-base64}</setting>
<setting name='uid' type='string'>${UID-base10}</setting>
<setting name='did' type='string'>${DID-uuid}</setting>
<setting name='mid' type='string'>${MID-base10}</setting>
<setting name='token' type='string'>${TOKEN-base64}</setting>
or at the very least, is returned by the python script above:
{u'machine_id': u'${MID-base64}', u'uid': ${UID-base10},u'access_token': u'${TOKEN-base64}'
(the only one not in the response is "cid")
Should we be making sure to update those lines from the response into accounts.xml as well, or just TOKEN?
Also, would it make sense, if it's available, to just use the 'did' from accounts.xml in the python script?
just thinking out loud here...
So, the short answer is: as long as the token is set, it doesn't seem to matter much. And to be clear, this script is just a short-term stop gap until @grimmy get is PR up that implements this natively, otherwise I'd be trying to make it parse-and-edit the accounts.xml, but I didn't care that much for something that I hope dies in a week or two.
All that said, those are all good questions. I actually used mid as my device_id, but I'm not sure. I imagine, looking at the flow you're supposed to pass in a device_id, and then use the machine_id you get back when you auth, but I don't actually know
Yeah, sorry I'm super busy the next few days and not sure when I'll be able to finish this, but I'm hoping I'll have it done next week.
I put some work into the script to make it a bit easier for people not familiar with python or dicts or other stuff. It will spit out errors in some common cases instead of crashing. It's also now in py3. Here's a script, that when you run it, looks like this:
$ pidgin-fb-login-test.py Access Token generator for Facebook 2factor login This tool will perform 2-factor login to FB and then print out an access token needed for the FB plugin for bitlbee and pidgin. Take the resulting code and put it in the "token" tag in accounts.xml Password: Code: Access token: <.....>
You need to edit the script to add your email and a UUID (which you can get by running
uuidgen
), but that's it. The script is here:https://gist.github.com/jaymzh/3ed8817cf8c20222ca09ce33a544b695
actually you must use 'did' (device_id) mentioned in the accounts.xml instead of an random uuid, this is how worked on me
Tip: the stoken
setting is actually the OAuth2 secret. Entering that in solved the problem of facebook straight up locking my account after using Pidgin
This is how I logged in successfully (a more detailed version for those who are begginers with pidgin):
'did'
's value and copy it'did'
(which indeed is an UUID
) to the MACHINE_ID
, write your email and save it<setting name='token' />
and modify it so it must look something like this <settings name='token' type='string'>(the token you got)</setting>
Yeah me too. But I was able to solve it this way:
1. Put the new password into pidgin 2. Close pidgin, open accounts.xml 3. Clear the stoken and token setting (as in, delete all those settings, not the value) 4. Reauthenticate, get new token, put new token in accounts.xml again
Suddenly unable to use 2fa again, using the script above.
(or using my merged script that parses accounts.xml, grabs the correct data, and call the fb login page: https://raw.githubusercontent.com/akhepcat/Miscellaneous/master/pidgin-fb-login-2fa.py )
Don't have enough skills to burp this and figure out what's changed, only that it's not working anymore for me.
@akhepcat it broke for me as well in the past 24h, but I have managed to get my bitlbee-facebook account back online by simply generating another token.
On my side, I keep getting 401 invalid username or password even tho I'm pretty sure I did everything right !
@Azizb750 's instructions with the script worked perfectly for me.
I reported this in the Workplace bug, but it looks like this is now happening on non-workplace. Two-factor no longer works either in app-password mode, nor in login-approval-code mode.
If you use an app password, you just get permission denied (tried with both "username" and "email" as username).
If you use normal password, Pidgin will tell you about the approval code, you then put it in, and it tries to connect for a minute or so, and then eventually you get
invalid username or password (401)
.