Uniquely identifying a user during the OAuth2 process - python

I have made a flask/python website which can create and edit events on a user's google calendar. Obviously the user has to give their permission via OAuth2 (which I struggled to understand but managed to make work in the end). Currently I am forcing the user to register and login to my site and I store various user settings and the refresh token attached to whatever username they select when they register with my site.... But now I want the user to be able to allow the user the use my site without having to register. I still want to store user settings and a refresh token but now I need to have some sort of label to identify the user so I know it's them when they come back (perhaps they will access my site from a different PC). Is there some string that I will have access to as part of the OAuth2 process that would serve to uniquely identify the user or do I need to do some additional step to grab such a string...
EDIT: looking at the comment made by shox and looking at the most upvoted answer to this SO question it seems that at the end of the oauth process I should...
send a GET to https://www.googleapis.com/oauth2/v3/userinfo, using the
OAuth2 bearer token you just received, and you will get a response
with some information about the user (id, name, etc.).
Unfortunately I'm not quite sure what that means nor how to code it in python. My best guess was as follows:
r = requests.get( "https://www.googleapis.com/oauth2/v3/userinfo",
params = {'token': credentials.token } )
data = r.json()
But data turns out to be {'error': 'invalid_request', 'error_description': 'Invalid Credentials'}
SOLVED: ... seems I needed to use the string "access_token" instead of "token" and now data contains an email address and a few other bits and bobs.
r = requests.get( "https://www.googleapis.com/oauth2/v3/userinfo",
params = {'access_token': credentials.token } )
data = r.json()

One way to uniquely identify a Google user via OAuth 2.0 is to record the user's unique identifier. That identifier is known as the id property of the Source object.
To read that identifier you'll need to make a call to People.get() with people/me as the resourceName and metadata as personFields. The first value will identify the authorized account as the one that we are interested in. In the second parameter, personFields, we are indicating that we want metadata about the target account. The latter isn't needed per se, but because we need to fill a valid value in personFields. In summary, the request should look like this (if done with cURL):
curl \
'https://people.googleapis.com/v1/people/me?personFields=metadata&key={API KEY}' \
--header 'Authorization: Bearer {ACCESS TOKEN}' \
--header 'Accept: application/json' \
--compressed`
With that request you'll get a JSON response which first lines will read:
{
"resourceName": "people/{ID HERE}",
…
That would be the id that you want to use for user identification. Please, ask me any question if you need more help.

Related

not able to log in to a website using post request in python

I am trying to enter my username , password and login into the website.I am a begineer to this and am trying this for the first time.I dont know if I have to include any other data here.
The sample website that I am trying is: http://testing-ground.scraping.pro/login.I am passing my credentials and checking if the contents of the welcome page appears after successfully logging in by printing page.content.But it displays the content of access denied(this appears when you enter the wrong credentials).I dont know where I am wrong here.
import requests
with HTMLSession() as c:
url='http://testing-ground.scraping.pro/login?mode=login'
usr='admin'
pwd='12345'
c.get(url)
login_data=dict(username=usr,password=pwd)
c.post(url,data=login_data)
page=c.get('http://testing-ground.scraping.pro/login?mode=welcome')
print(page.content)
I have not tested this but it seems like you used the wrong names for the username and password parameters in the request. A quick inspection of the request sent by the site shows this:
As you can see, in the form data the username is sent as usr and the password is sent as pwd. However, when you built the dict for the login data, you used login_data=dict(username=usr,password=pwd), which constructs a dict of {"username": usr, "password": pwd}, which does not match the requirements of the actual request. What you want instead is dict(usr=usr,pwd=pwd).
Have a look in the <form> tag in page source. Or you can check the Network tab for post request for the name value of each field. The correct field names are usr and pwd.
So basically change this line of code:
login_data=dict(username=usr,password=pwd)
to
login_data=dict(usr=usr,pwd=pwd)

How to programmatically delete an email from list of bounced emails?

I am working on a GAE(Google App Engine) based python app and which have sendgrid python SDK(v3.2.10) integrated into it. What I am trying do is right now that whenever sendgrid pushes an event webhook of type "bounce" I want to delete that bounced email from the list of bounced emails present on sendgrid.
I have already gone through the documentation provided on the official site. First I tried to delete email address using SDK and it worked fine on localhost. But after deploying it to the live server it just doesn't do anything and falls in the exception clause.
Code snippet:
try:
send_grid_client = sendgrid.SendGridAPIClient(apikey=SENDGRID_API_KEY)
data = {"emails": [email.strip()]}
delete_response = send_grid_client.client.suppression.bounces.delete(
request_body=data)
except Exception as exception:
logging.info('Exception is: {}'.format(exception))
pass
As it did not work as expected, I am now trying to do the same using REST API.
Code snippet:
import requests
data = {"emails": [email]}
headers = {"Authorization": "Bearer {}".format(SENDGRID_API_KEY)}
delete_response = requests.delete("https://api.sendgrid.com/v3/suppression/bounces", data=json.dumps(data), headers=headers)
logging.info(delete_response)
logging.info(delete_response.status_code)
logging.info(delete_response.text)
Now, sendgrid API is continuously returning error 400 with message {"errors":[{"field":null,"message":"emails or delete_all params required"}]}. I simply could not figure out how to overcome this issue. Maybe I am missing how to pass request body in the delete function but, I could not figure it out.
I just figured out the issue.
It's the SendGrid API docs here which causes confusion as it is not mentioned clearly that they have a different way of calling the same endpoint when you want to delete a single email address or list of emails.
For a single email, it needs to be passed in the URL i.e. https://api.sendgrid.com/v3/suppression/bounces/{email_address}
For a list of emails, the list needs to be passed in the body of the delete request. i.e. it will look like this {"emails": [email_address_1, email_address_1, ...]}
As in the question above a single email was meant to be deleted and it was being passed as {"emails": [email_address_1]} in the delete request. Sendgrid API was not able to digest this info and was throwing an error. The email address was to be passed in the URL.
This issue has been resolved. But, I wonder why Sendgrid API was not able to digest this info {"emails": [email_address_1]}. Why they have a hard assumption that list will always have elements greater than one in it.

Need a Python script for Slack to deactivate a user [duplicate]

I have tried multiple approaches to this. Tried first getting the user without any user id - this returns me just my user, then tried getting user with other id's and it also retrieves data correctly. However, I can't seem to be able to set user attribute 'deleted'. i'm using this python approach.
slack_client.api_call('users.profile.set', deleted=True, user='U36D86MNK')
However I get the error message of:
{u'error': u'invalid_user', u'ok': False}
Maybe someone has already done this? It says in documentation that it's a paid service mentioning this message under a user property:
This argument may only be specified by team admins on paid teams.
But shouldn't it give me a 'paid service' response in that case then?
The users.profile.set apparently does not work for for setting each and every property of a user.
To set the deleted property there is another API method called users.admin.setInactive. Its an undocumented method and it will only work on paid teams.
Note: This requires a legacy token and doesn't work with App tokens - these are only available on paid plans and new legacy tokens can't be created anymore
in python you can do the following:
import requests
def del_slack_user(user_id): # the user_id can be found under get_slack_users()
key = 'TOKEN KEY' #replace token key with your actual token key
payload = {'token': key, 'user': user_id}
response = requests.delete('https://slack.com/api/users.admin.setInactive', params=payload)
print(response.content)
def get_slack_users():
url = 'https://slack.com/api/users.list?token=ACCESSTOKEN&pretty=1'
response = requests.get(url=url)
response_data = response.json() # turns the query into a json object to search through`
You can use Slack's SCIM API to enable and disable a user. Note that, as with the undocumented API endpoint mentioned in other answers this requires a Plus/Enterprise account.

How to get instagram username from username ID without API in Python?

I'm trying to find a way to get instagram username from the username ID in Python.
What I found so far is this:
https://api.instagram.com/v1/users/[USER-ID]?access_token=[YOUR-ACCESS-TOKEN]
I have a token number, but it only works for users added to sandbox. For other users I receive the following error:
{"meta": {"code": 400, "error_type": "APINotFoundError", "error_message": "this user does not exist"}}
I'm searching a solution for hours with no luck so far.
Is there a way to arrive to the same result without using a token?
Thanks a lot!
In my case I am getting data from tagFeed so I have picture code. If you have picture code of any of user's post then you can get username like this
https://www.instagram.com/p/picCODE/?__a=1
example: https://www.instagram.com/p/BaGce-NlMg7/?__a=1
it will return a JSON with the owner - username
Point your browser to https://i.instagram.com/api/v1/users/USERID/info/ (replace USERID by the user id). It returns a JSON in which the field user.username is that user's username. With curl and jq installed, this shell oneliner will directly return the username:
curl -s https://i.instagram.com/api/v1/users/USERID/info/ | jq -r .user.username
Alternatively, the Instaloader package provides a convenient way to obtain a username given its ID, without using the official Instagram API.
import instaloader
L = instaloader.Instaloader()
profile = instaloader.Profile.from_id(L.context, ID)
print(profile.username)
It works by querying one of the profile's posts (for which only the profile's ID is required), obtaining that post's metadata (instagram.com/p/SHORTCODE) and then returning the owner.username value of that post.
No, unfortunately you can't. You need a token with public_content permissions, and for that, you need to have a live app (not in sandbox).

Insufficient permissions when trying to create a Quizlet set

I am trying to create a set on Quizlet.com, using its API found here: https://quizlet.com/api/2.0/docs/sets#add
Here is my code of a set I am trying to create:
import requests
quizkey = my_client_id
authcode = my_secret_code # I'm not sure if I need this or not
data = {"client_id":quizkey, "whitespace":1, "title":"my-api-set",
"lang_terms":"it", "lang_definitions":"en",
"terms":['uno','due'], "definitions":["one","two"]}
apiPrefix = "https://api.quizlet.com/2.0/sets"
r = requests.post(url=apiPrefix, params=data)
print r.text
The response is:
{
"http_code": 401,
"error": "invalid_scope",
"error_title": "Not Allowed",
"error_description": "You do not have sufficient permissions to perform the requested action."
}
I also tried "access_token":authcode instead of "client_id":quizkey, but this resulted in the error: "You do not have sufficient permissions to perform the requested action."
How can I fix this and not get a 401 error?
Alright so 3 and a half years later (!!) I've looked into this again and here's what I've discovered.
To add a set you need an access token - this is different to the client_id (what I call quizkey in my code), and to be quite honest I don't remember what authcode in my code is.
This token is obtained by going through the user authentication flow. To summarise it:
Send a POST request to https://quizlet.com/authorize like so:
https://quizlet.com/authorize?response_type=code&client_id=MY_CLIENT_ID&scope=read&state=RANDOM_STRING
Keep the response_type as code, replace client_id with your client_id, keep the scope as read, and state can be anything
I believe this requires human intervention because you're literally authorising your own account? Not sure of another way...
You'll receive a response back with a code
Let's call this RESPONSE_CODE for now
Send a POST request to https://api.quizlet.com/oauth/token, specifying 4 mandatory parameters:
grant_type="authorization_code" (this never changes)
code=RESPONSE_CODE
redirect_uri=https://yourredirecturi.com (this can be found at your personal API dashboard)
client ID and secret token separated by a colon and then base64-encoded (the user authentication flow link above tells you what this is if you don't want to do any of the encoding)
You'll receive the access_token from this API call
Now you can use that access_token in your call to create a set like I've done above (just replace "client_id":quizkey with "access_token":access_token)
You will need to authenticate in order to make sets. This link gives an overview:
https://quizlet.com/api/2.0/docs/making_api_calls
And this one provides details about the authentication process:
https://quizlet.com/api/2.0/docs/authorization_code_flow

Categories