I was looking at the Github API and it allows you to fetch all repository invites through an API endpoint (see https://developer.github.com/v3/repos/invitations/#list-invitations-for-a-repository). This works fine like this:
from requests.auth import HTTPBasicAuth
import requests
login = 'xxx'
password = 'yyy'
url = 'https://api.github.com/user/repository_invitations'
repository_invites = requests.get(
url, auth=HTTPBasicAuth(login, password)).json()
print('response: ' + str(repository_invites))
I can then get out each request its url like this:
for repository_invite in repository_invites:
print('url: ' + repository_invite.get('url'))
Which gives something back like:
url: https://api.github.com/user/repository_invitations/123456789
Github also mentions that you can accept an invite at https://developer.github.com/v3/repos/invitations/#accept-a-repository-invitation which mentions
PATCH /user/repository_invitations/:invitation_id
What I don't get is how I can tell Github how to accept it though. This endpoint seems to be used for both deleting and accepting an invitation. Github talks about PATCH at https://developer.github.com/v3/#http-verbs which mentions you can use either a POST or send a PATCH request, however not how. So the question is, how do I know what I should send in the PATCH call? I tried this for example:
result = requests.patch(repository_invite.get('url'), json.dumps({'accept': True}))
print('result: ' + str(result.json()))
Which gives back:
result: {'message': 'Invalid request.\n\n"accept" is not a permitted key.', 'documentation_url': 'https://developer.github.com/v3'}
In order to call the API endpoint you will need to have authentication with your Github user and you need to send a Patch call (which can take data/headers if you would need them). Here's a working sample:
for repository_invite in repository_invites:
repository_id = repository_invite.get('id')
accept_invite = requests.patch('https://api.github.com/user/repository_invitations/'+ str(repository_id),
data={}, headers={},
auth=HTTPBasicAuth(github_username, github_password))
Without the authentication the Patch call will give back a 404 response code because it is only accessible behind a login for obvious safety purpose. If you call the endpoint user/repository_invitations/ followed by the ID Github will automatically accept the invitation.
Related
I am trying to access the Youtube API via python so that I can insert videos into a playlist. To do so I have to use oauth2 to authorize myself. I have looked up many guides and videos and followed their instructions step by step but I always get the same result, saying Error 400: redirect_uri_mismatch
The code that I am using is
from google_auth_oauthlib.flow import InstalledAppFlow
flow = InstalledAppFlow.from_client_secrets_file("client_secrets.json", scopes=['https://www.googleapis.com/auth/youtube.force-ssl'])
flow.run_local_server(port=8080, prompt='consent')
credentials = flow.credentials
print(credentials.to_json())
I have also tried
from google_auth_oauthlib.flow import InstalledAppFlow
flow = InstalledAppFlow.from_client_secrets_file("client_secrets.json", scopes=['https://www.googleapis.com/auth/youtube.force-ssl'])
flow.run_console()
credentials = flow.credentials
print(credentials.to_json())
I understand that this occurs when there is a mismatch between the redirect_uri on the request side and what is listed in the console. But I have triple checked that on https://console.developers.google.com/ I have the redirect URI to be http://localhost.com:8080 and have checked to make sure that my client_secrets.json file reflects the same. I have set my JavaScript origins to also be http://localhost.com:8080. I have set my oauth clientID to be a web application as I am running this in pycharm. However, whenever I run my code I get the same error saying The redirect URI in the request, http://localhost:8080/, does not match the ones authorized for the OAuth client. To update the authorized redirect URIs, visit: https://console.developers.google.com/apis/credentials/oauthclient/${your_client_id}?project=${your_project_number}
I have looked at the other questions on stackOverflow and have tried the solutions that were suggested but none of them have worked. I have no idea why I cannot get authorization and desperately need help
I have recently been working with API's but I am stuck on one thing and it's been holding me back for a few days.
I am trying to work with Privacy's API and I do not understand the Authentication/Authorization process. When I enter the url in a browser I get the error "message": "Please provide API key in Authorization header", even when I use the correct format of Authorization. I also get an error when I make a request in Python. The format I'm using for the url is https://api.privacy.com/v1/card "Authorization: api-key:".
If someone could explain how to work this or simply give an example of how I would make a request through Python3. The API information is in the link below.
Thank you in advance.
https://developer.privacy.com/docs
This is the code I am using in Python. After I run this I receive a 401 status code.
import requests
headers={'Authorization': 'api-key:200e6036-6894-xxxx-xxxx-xxxx'}
url = 'https://api.privacy.com/v1/card'
r = requests.get(url)
print("Status code:", r.status_code)
You need to add the authentication header to the get call. It isn't enough to include it in a header variable. You need to provide those headers to requests
import requests
response = requests.get('https://api.privacy.com/v1/card', headers={'Authorization': 'api-key 65a9566c-XXXXXXXXXXXX'})
print(response.json())
I found out that editing a full_description of a DockerHub repository can be done via a JavaScript API, and figured this would be a fun excuse to learn the requests package for python. The JavaScript API definitely works, e.g. using this simple docker image.
The JS API basically does
Send a POST request to https://hub.docker.com/v2/users/login with the username and password. The server responds with a token.
Send a PATCH request to the specific https://hub.docker.com/v2/repositories/{user or org}/{repo}, making sure the header has Authorization: JWT {token}, and in this case with content body of {"full_description":"...value..."}.
What is troubling is that the PATCH request on the python side gets a 200 response back from the server (if you intentionally set a bad auth token, you get denied as expected). But it's response actually contains the current information (not the patched info).
The only "discoveries" I've made:
If you add the debug logging stuff, there's a 301. But this is the same URL for the javascript side, so it doesn't matter?
send: b'{"full_description": "TEST"}'
reply: 'HTTP/1.1 301 MOVED PERMANENTLY\r\n'
The token received by doing a POST in requests is the same as if I GET to auth.docker.io as decribed in Getting a Bearer Token section here. Notably, I didn't specify a password (just did curl -X GET ...). This is not true. They are different, I don't know how I thought they were the same.
This second one makes me feel like I'm missing a step. Like I need to decode the token or something? I don't know what else to make of this, especially the 200 response from the PATCH despite no changes.
The code:
import json
from textwrap import indent
import requests
if __name__ == "__main__":
username = "<< SET THIS VALUE >>"
password = "<< SET THIS VALUE >>"
repo = "<< SET THIS VALUE >>"
base_url = "https://hub.docker.com/v2"
login_url = f"{base_url}/users/login"
repo_url = f"{base_url}/repositories/{username}/{repo}"
# NOTE: if I use a `with requests.Session()`, then I'll get
# CSRF Failed: CSRF token missing or incorrect
# Because I think that csrftoken is only valid for login page (?)
# Get login token and create authorization header
print("==> Logging into DockerHub")
tok_req = requests.post(login_url, json={"username": username, "password": password})
token = tok_req.json()["token"]
headers = {"Authorization": f"JWT {token}"}
print(f"==> Sending PATCH request to {repo_url}")
payload = {"full_description": "TEST"}
patch_req = requests.patch(repo_url, headers=headers, json=payload)
print(f" Response (status code: {patch_req.status_code}):")
print(indent(json.dumps(patch_req.json(), indent=2), " "))
Additional information related to your CSRF problem when using requests.Session():
It seems that Docker Hub is not recognizing csrftoken named header/cookie (default name of the coming cookie), when making requests in this case.
Instead, when using header X-CSRFToken on the following requests, CSRF is identified as valid.
Maybe reason is cookie-to-header token pattern.
Once updating session header with cookie of login response
s.headers.update({"X-CSRFToken": s.cookies.get("csrftoken")})
There is no need to set JWT token manually anymore for further requests - token works as cookie already.
Sorry, no enough privileges to just comment, but I think this is relevant enough.
As it turns out the JWT {token} auth was valid the entire time. Apparently, you need a / at the end of the URL. Without it, nothing happens. LOL!
# ----------------------------------------------------V
repo_url = f"{base_url}/repositories/{username}/{repo}/"
As expected, the PATCH then responds with the updated description, not the old description. WOOOOT!
Important note: this is working for me as of January 15th 2020, but in my quest I came across this dockerhub issue that seems to indicate that if you have 2FA enabled on your account, you can no longer edit the description using a PATCH request. I don't have 2FA on my account, so I can (apparently). It's unclear what the future of that will be.
Related note: the JWT token has remained the same the entire time, so for any web novices like myself, don't share those ;)
I have been at this for sometime now and wanted to see if anyone had and idea of what I could be doing wrong. What I am trying to do is add a song to a playlist using the provided Spotify Web APIs. According to the documentation on this https://developer.spotify.com/documentation/web-api/reference/playlists/add-tracks-to-playlist/ I need to establish the scope of the user.
"adding tracks to the current user’s private playlist (including collaborative playlists) requires the playlist-modify-private scope" I have created the playlist as collaborative and I am using the login credentials of my personal account to reach this playlist I created. all this is under the same login.
What I am finding is that my scope is not getting added to my token on my call for my token causes a 403 error when I try to add the song.
Here is what that call looks like
https://accounts.spotify.com/authorize/?client_id=mynumber&response_type=code&scope=playlist-modify-private&redirect_uri=http:%2F%2Flocalhost:55141/Home/GetToken/
here are the docs on using authorization to get the correct token.
https://accounts.spotify.com/authorize/?client_id=894400c20b884591a05a8f2432cca4f0&response_type=code&scope=playlist-modify-private&redirect_uri=http:%2F%2Flocalhost:55141/Home/GetToken/
further more if I go into the dev support here
https://developer.spotify.com/documentation/web-api/reference/playlists/add-tracks-to-playlist/
and click the green try button and then request a new token it works.
Bottom line some how my request is not taking my scope request. Any Ideas?
Thanks
To get the token with a specific scope you need to go to the authorize endpoint and get the code. The code is what you want to get to be able http post to the endpoint https://accounts.spotify.com/api/token and get a token with your desired scopes. You can simply get the code by pasting a url like this in your browser...
https://accounts.spotify.com/authorize?client_id=<client_id>&response_type=code&scope=streaming%20user-read-email%20user-read-private&redirect_uri=<redirect_uri>
Only add %20 in between scopes if you have multiple ones
You will then be sent to spotify's website and they'll verify you want to do this. Once you verify it your browser will redirect you to what you set the redirect_uri to be in the url above. At the end of the url that you are sent to, you should be able to see the parameter name code with the code value assigned to it. You then get that code and put it in your http post body params to the https://accounts.spotify.com/api/token endpoint. Make sure you accurately follow the query params requirements in your post method.
An example of the post in python using the requests library:
authorization = requests.post(
"https://accounts.spotify.com/api/token",
auth=(client_id, client_secret),
data={
"grant_type": "authorization_code",
"code": <code>,
"redirect_uri": <redirect_uri>
},
)
authorization_JSON = authorization.json()
return authorization_JSON["access_token"]
In the end you should get a json that shows the scopes you set a long with a refresh the token later on to make more requests.
I know this answer is quite late but I was experiencing the same issue as well which is how I came across this question. I hope this helps anyone that sees this at a later date.
Source: https://developer.spotify.com/documentation/general/guides/authorization-guide/#client-credentials-flow
I'm integrating Google's login with a Flask site using Flask-OAuth.
Everything is working fine. I can authorise the login and get a token back etc without any difficulties. But when I use Flask-OAuth's get method to request the logged in user's email address I get an error saying:
TypeError: Unicode-objects must be encoded before hashing
I'm using Python3 and this has the smell of a Python version issue but I can't figure out what I'd need to change.
The code I'm using is this:
def get_additional_data(self):
access_token = session.get('oauth_token')
headers = {'Authorization': 'OAuth ' + access_token[0]}
return self.service.get(
'https://www.googleapis.com/oauth2/v1/userinfo', None,
headers=headers)
I'm not sure what I can encode in that request. Even if I don't pass the headers I get the same error (rather than an invalid request or something like that).
I've run 2to3 on oauth2/__init__.py and the tweaks is suggests are very minor and shouldn't prevent the code from running in Python 3. Also, everything else OAuth2 related is working.
The bad news is that the solution to this problem is switching to Flask-OAuthlib.
The good news is it required very few changes from Flask-OAuth to get it working.