I signed up for a new instance and noticed that Mastodon Archive doesn’t allow me to log in using OAuth2. What’s going on? Let’s look at the API again.
Register the application:
`curl -X POST -d "client_name=mastodon-archive&redirect_uris=urn:ietf:wg:oauth:2.0:oob&scopes=read" -Ss https://tabletop.social/api/v1/apps`
This gives me a JSON containing `client_id` and `client_secret`. Store these as environment variables of the same name.
Store the password in an environment variable, too.
export client_id=... export client_secret=... export password=...
Login to get the access token:
`curl -X POST -d "client_id=$client_id&client_secret=$client_secret&grant_type=password&username=kensanata@gmail.com&password=$password" -Ss https://tabletop.social/oauth/token`
Store it in an environment variable, of course.
export access=token=...
Test it:
`curl --header "Authorization: Bearer $access_token" -sS https://tabletop.social/api/v1/timelines/home`
This seems to work even though it doesn’t work for *Mastodon Archive*!
Let’s create the necessary files, manually:
echo $client_id > tabletop.social.client.secret echo $client_secret >> tabletop.social.client.secret echo $access_token > tabletop.social.user.kensanata.secret
And test it:
$ mastodon-archive archive kensanata@tabletop.social Get user info Get statuses (this may take a while) Get favourites (this may take a while) Skipping mentions Skipping followers Saving 33 statuses, 13 favourites, 0 mentions, and 0 followers
Thus, we now know that the problem is the app registration and obtaining the access token. Everything else works as expected.
#Mastodon #Mastodon Archive
(Please contact me if you want to remove your comment.)
⁂
Debugging what `Mastodon.py` does... Here is what my code does, essentially:
print("Registering app") Mastodon.create_app( 'mastodon-archive', api_base_url = url, to_file = client_secret) print("Log in") mastodon = Mastodon( client_id = client_secret, api_base_url = url, debug_requests = True) url = mastodon.auth_request_url( client_id = client_secret, scopes=scopes) print("Visit the following URL and authorize the app:") print(url) print("Then paste the access token here:") token = sys.stdin.readline().rstrip() mastodon.log_in( username = username, code = token, to_file = user_secret, scopes=scopes)
And I get the error in the last statement.
Registering app Log in Mastodon: Request to endpoint "/api/v1/instance/" using method "GET". Parameters: {} Headers: None Files: {} Mastodon: Response received with code 200. response headers: {...} Response text content: {...} Visit the following URL and authorize the app: https://social.nasqueron.org/oauth/authorize?client_id=...8aba&response_type=code&redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&scope=read Then paste the access token here: ...033d Mastodon: Request to endpoint "/oauth/token" using method "POST". Parameters: {'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob', 'code': '...033d', 'grant_type': 'authorization_code', 'client_id': '...8aba', 'client_secret': '...b138', 'scope': 'read'} Headers: None Files: {} Mastodon: Response received with code 401. response headers: {... 'WWW-Authenticate': 'Bearer realm="Doorkeeper", error="invalid_grant", error_description="The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."' ...} Response text content: {"error":"invalid_grant","error_description":"The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."}
I started wondering: is this because of the `scope` parameter? I was missing the `scope` parameter in my call to `create_app`. I made that change but saw no difference.
I then thought perhaps the problem is the missing `redirect_uris` in `auth_request_url` and `redirect_uri` in `log_in`. I added them both but saw no difference.
I then thought perhaps something about scopes was wrong so I removed `scopes`, `redirect_uris` and `redirect_uri` from the various calls but saw no difference.
Sadly, the Mastodon.py documentation and the Doorkeeper documentation it refers to is very sparse indeed. `Mastodon.py` doesn’t tell me how to really do OAuth and Doorkeeper only tells me how to do it with a password (Resource Owner Password Credentials) and not how to use Client Credentials.
Resource Owner Password Credentials
It is all quite frustrating.
And most disturbing of all: it continues to work for *octodon.social* but doesn’t work for any of the other instances I have tried, e.g. *social.nasqueron.org*.
As I said, it is all quite frustrating.
As expected, switching the entire thing to password credentials “works”:
mastodon = Mastodon( client_id = client_secret, api_base_url = url) print("We need your credentials just this once to log in.") sys.stdout.write("Email: ") sys.stdout.flush() email = sys.stdin.readline().rstrip() sys.stdout.write("Password: ") sys.stdout.flush() password = sys.stdin.readline().rstrip() mastodon.log_in( username = email, password = password, to_file = user_secret, scopes=scopes)
The result:
$ mastodon-archive login kensanata@social.nasqueron.org We need your credentials just this once to log in. Email: kensanata+nasqueron@gmail.com Password: *secret* Get user info Login OK
The word of the day is “frustrating”.
– Alex Schroeder 2018-05-13 19:23 UTC