-
-
Save cmj/998f59680e3549e7f181057074eccaa3 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# Grab oauth token for use with Nitter (requires Twitter account). | |
# results: {"oauth_token":"xxxxxxxxxx-xxxxxxxxx","oauth_token_secret":"xxxxxxxxxxxxxxxxxxxxx"} | |
# 2024-11-14: verified working again | |
# 2025-01-07: added 2FA support | |
username="" | |
password="" | |
# Two-Factor Authentication | |
# You can use any time-based one time password (TOTP) authentication app like Google Authenticator, Authy, Duo Mobile, 1Password, etc.) | |
# - Wait for prompt, use authentication app to get code. | |
# - OR enter here your one-time backup code (limit of 5 active codes, must be used in order created; out of order sequence revokes previous codes) | |
totp_code="" | |
if [[ -z "$username" || -z "$password" ]]; then | |
echo "needs username and password" | |
exit 1 | |
fi | |
bearer_token='AAAAAAAAAAAAAAAAAAAAAFXzAwAAAAAAMHCxpeSDG1gLNLghVe8d74hl6k4%3DRUMF4xAQLsbeBhTSRrCiQpJtxoGWeyHrDb5te2jpGskWDFW82F' | |
guest_token=$(curl -s -XPOST https://api.twitter.com/1.1/guest/activate.json -H "Authorization: Bearer ${bearer_token}" -d "grant_type=client_credentials" | jq -r '.guest_token') | |
base_url='https://api.twitter.com/1.1/onboarding/task.json' | |
header=(-H "Authorization: Bearer ${bearer_token}" -H "User-Agent: TwitterAndroid/10.21.0-release.0" -H "X-Twitter-Active-User: yes" -H "Content-Type: application/json" -H "X-Guest-Token: ${guest_token}") | |
# start flow | |
flow_1=$(curl -si -XPOST "${base_url}?flow_name=login&api_version=1&known_device_token=&sim_country_code=us" "${header[@]}" \ | |
-d '{"flow_token": null, "input_flow_data": {"country_code": null, "flow_context": {"referrer_context": {"referral_details": "utm_source=google-play&utm_medium=organic", "referrer_url": ""}, "start_location": {"location": "deeplink"}}, "requested_variant": null, "target_user_id": 0}}' | |
) | |
# get 'att', now needed in headers, and 'flow_token' from flow_1 | |
att=$(sed -En 's/^att: (.*)\r/\1/p' <<< "${flow_1}") | |
flow_token=$(sed -n '$p' <<< "${flow_1}" | jq -r .flow_token) | |
# username | |
token_2=$(curl -s -XPOST "${base_url}" -H "att: ${att}" "${header[@]}" \ | |
-d '{"flow_token": "'"${flow_token}"'", "subtask_inputs": [{"enter_text": {"suggestion_id": null, "text": "'"${username}"'", "link": "next_link"}, "subtask_id": "LoginEnterUserIdentifier"}]}' | jq -r .flow_token) | |
# password flow and print oauth_token and secret | |
flow_3=$(curl -s -XPOST "${base_url}" -H "att: ${att}" "${header[@]}" \ | |
-d '{"flow_token": "'"${token_2}"'", "subtask_inputs": [{"enter_password": {"password": "'"${password}"'", "link": "next_link"}, "subtask_id": "LoginEnterPassword"}]}') | |
token_3=$(jq -r .flow_token <<< "${flow_3}") | |
check_2fa=$(jq -r .subtasks[0].subtask_id <<< "${flow_3}") | |
if [[ "${check_2fa}" != "LoginTwoFactorAuthChallenge" ]]; then | |
jq -c '.subtasks[0]|if(.open_account) then {oauth_token: .open_account.oauth_token, oauth_token_secret: .open_account.oauth_token_secret} else empty end' <<< "${flow_3}" | |
exit 0 | |
fi | |
# 2FA stuff | |
if [[ -z "$totp_code" ]]; then | |
echo "@${username} - Use your code generator app to generate a code and enter it below." | |
read totp_code | |
fi | |
curl -s -XPOST "${base_url}" -H "att: ${att}" "${header[@]}" \ | |
-d '{"flow_token":"'"${token_3}"'","subtask_inputs":[{"subtask_id":"LoginTwoFactorAuthChallenge","enter_text":{"text":"'"${totp_code}"'","link":"next_link"}}]}' | | |
jq -c 'if(.subtasks[0].open_account) then {oauth_token: .subtasks[0].open_account.oauth_token, oauth_token_secret: .subtasks[0].open_account.oauth_token_secret} else .errors[0].message end' |
What can I do in case the accounts has 2step verficaition enabled?
I'm not entirely sure that's possible with this onboarding flow for oauth tokens. It is, however, working for cookies using https://github.com/d60/twikit/ You can use that to get a cookie and use it with this cookie branch. Unfortunately it is just a PoC; only one account for now.
I'll poke around later this week.
https://github.com/d60/twikit/blob/main/twikit/client/client.py#L451
I'm not entirely sure that's possible with this onboarding flow for oauth tokens. It is, however, working for cookies using https://github.com/d60/twikit/ You can use that to get a cookie and use it with this cookie branch. Unfortunately it is just a PoC; only one account for now.
I'll poke around later this week.
https://github.com/d60/twikit/blob/main/twikit/client/client.py#L451
Already using 4 accounts and want to use more accounts to avoid 429 error. Can't use the cookie branch really. Would be best if there's any way to find out flow to authenticate 2fa.
Already using 4 accounts and want to use more accounts to avoid 429 error. Can't use the cookie branch really. Would be best if there's any way to find out flow to authenticate 2fa.
@muhitrhn I just added 2fa options to this and it seems to work fine using phone with Authy. I haven't tested it with backup codes, but should work. You still get oauth_token
and secret
with response.
Apparently SMS is not available for free accounts, so using an app seems to be the preferred method...
Let me know if it works, thanks!
Already using 4 accounts and want to use more accounts to avoid 429 error. Can't use the cookie branch really. Would be best if there's any way to find out flow to authenticate 2fa.
@muhitrhn I just added 2fa options to this and it seems to work fine using phone with Authy. I haven't tested it with backup codes, but should work. You still get
oauth_token
andsecret
with response.Apparently SMS is not available for free accounts, so using an app seems to be the preferred method...
Let me know if it works, thanks!
It worked perfectly. Thank you very much!
Hi @cmj , it is off topic but is there any graphql endpoint for X spaces from which I can find out the participants of a Space? I found one but it doesn't give all participants which is AudioSpaceById
. Is there maybe any which checks if a user is in the space?
Yeah that endpoint doesn't give every single listener. It breaks them out in 3 parts {admins,speakers,listeners}. I've monitored a number of "spaces" and that seems to have a limit on listeners
data, but it does change.
The short of it is, I don't think it's possible to page through all listeners. I don't think twitter had it in place to list all listeners
but I'll look again.
I'll add some of my spaces/broadcasts scripts to https://github.com/cmj/twitter-tools/ soon. I'm going to guess it has to do with the thousands that may listen and that number is so insanely dynamic it's not something one can pull proper data from.
E: Sorry I didn't address your last question. No. These are the known endpoints: https://raw.githubusercontent.com/fa0311/TwitterInternalAPIDocument/refs/heads/master/docs/json/API.json
@muhitrhn I'll have to wait for a large listener group to come live to play with, but for small "spaces" I guess one could do a check.
$ cat 1BdxYEyDoYMxX.json | jq -r '.data.audioSpace.participants.listeners[] | "Listener @\(.twitter_screen_name) (\(.display_name))"' | grep @Renz1337
Listener @Renz1337 (Ellorayni Reynolds)
Which would be this if stream is live:
./AudioSpaceById.sh 1BdxYEyDoYMxX | jq -r '.data.audioSpace.participants.listeners[] | "Listener @\(.twitter_screen_name) (\(.display_name))"' | grep @user
@cmj Right that's the same problem I am facing. I wonder how those data analytics tools does it. Is there any endpoint which checks if a user joined the space?
I played around with Spaces a bit more... The only thing that comes close is the AudioSpaceSearch
, however it's seems impossible to see if a random user joins the stream to listen. It will give results if you search for the host of a stream and sometimes another admin.
I'm not finding any other endpoint that would return the Space someone is actively listening to.
You could, if you knew a general search phrase (or "space" gave me the most) and passively filter all the results for the user. That's obviously going to use a lot of resources, and you also have a listener
limit.
@muhitrhn I stumbled across this endpoint https://x.com/i/api/fleets/v1/fleetline?only_spaces=true
You need to be following the account for you to see them actively listening to a Spaces stream.
Thank you for finding it @cmj! Really appreciate it. So how can I interact with it? It says 410 Gone: The Twitter REST API v1 is no longer active. Please migrate to API v1.1. https://dev.twitter.com/docs/api/1.1/overview
Edit: Nvm now it says 403 forbidden
. I think you can only access it with cookies and csrf? If that's the case can you help me maybe in converting https://github.com/PrivacyDevel/nitter to multi cookies and csrf based? Just telling me what to change will also do.
Made some modifications and this script seems to be working again.