Flask use oauth verification to use google drive api - python

I am currently using Oauth2.0 to log into my Flask app. I have that working as intended. Now I want to use the same creds I got from logging in to be able to send requests to the Google drive api. Im not really sure where to start, the docs are difficult to follow.
note: I have activated the Google Drive api in the developer console.
Here is the code for the login callback.
globally:
GOOGLE_CLIENT_ID = config['google_client_id']
GOOGLE_CLIENT_SECRET = config['google_client_secret']
GOOGLE_DISCOVERY_URL = (
"https://accounts.google.com/.well-known/openid-configuration"
)
client = WebApplicationClient(GOOGLE_CLIENT_ID)
view function:
#bp.route('/login/callback')
def callback():
# Get authorization code Google sent back to you
code = request.args.get("code")
# Find out what URL to hit to get tokens that allow you to ask for
# things on behalf of a user
google_provider_cfg = get_google_provider_cfg()
token_endpoint = google_provider_cfg["token_endpoint"]
token_url, headers, body = client.prepare_token_request(
token_endpoint,
authorization_response=request.url,
redirect_url=request.base_url,
code=code
)
token_response = requests.post(
token_url,
headers=headers,
data=body,
auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET),
)
# Parse the tokens!
client.parse_request_body_response(json.dumps(token_response.json()))
# Now that you have tokens (yay) let's find and hit the URL
# from Google that gives you the user's profile information,
# including their Google profile image and email
userinfo_endpoint = google_provider_cfg["userinfo_endpoint"]
uri, headers, body = client.add_token(userinfo_endpoint)
userinfo_response = requests.get(uri, headers=headers, data=body)
# You want to make sure their email is verified.
# The user authenticated with Google, authorized your
# app, and now you've verified their email through Google!
if userinfo_response.json().get("email_verified"):
unique_id = userinfo_response.json()["sub"]
users_email = userinfo_response.json()["email"]
picture = userinfo_response.json()["picture"]
username = userinfo_response.json()["given_name"]
else:
return "User email not available or not verified by Google.", 400
user = User.query.filter(User.google_sub==unique_id).first()
login_user(user)
def get_google_provider_cfg():
return requests.get(GOOGLE_DISCOVERY_URL).json()
My thoughts are maybe I have to set up a google drive endpoint to be able to send api requests to with the same token? Im not quite sure.

Related

How to get Microsoft Graph API token to read mails

I'm trying to retrieve mails from my organization's mailbox, and I can do that via Graph Explorer. However, when I use the same information that I used in Graph Explorer, the generated token returns an error stating '/me request is only valid with delegated authentication flow.' in me/messages endpoint.
So, how can I generate the acceptable token for the /me endpoint?
An example python code or example Postman request would be amazing.
It sounds like the endpoint you're using in Graph Explorer is something like this
https://graph.microsoft.com/v1.0/me/messages
/me is referring to the user signed into Graph Explorer. If you want to read another user's messages you would use
https://graph.microsoft.com/v1.0/users/user#domain.com/messages
When connecting to Graph API as an application with no user interaction, you can never use /me endpoints, as there's no user logged in.
Reference
https://learn.microsoft.com/en-us/graph/api/user-list-messages?view=graph-rest-1.0
Python example to list messages
import requests
def get_messages(access_token, user):
request_url = f"https://graph.microsoft.com/v1.0/users/{user}/messages"
request_headers = {
"Authorization": "Bearer " + access_token
}
result = requests.get(url = request_url, headers = request_headers)
return(result)
msgs = get_messages(access_token = token['access_token'], user = "userPrincipalName#domain.com")
print(msgs.content)
Additional example of obtaining a token, using an app registration and client secret
import msal
def get_token_with_client_secret(client_id, client_secret, tenant_id):
# This function is to obtain a bearer token using the client credentials flow, with a client secret instead of a certificate
# https://docs.microsoft.com/en-us/graph/sdks/choose-authentication-providers?tabs=CS#client-credentials-provider
app = msal.ConfidentialClientApplication(
client_id = client_id,
client_credential = client_secret,
authority = f"https://login.microsoftonline.com/{tenant_id}")
scopes = ["https://graph.microsoft.com/.default"]
token = app.acquire_token_for_client(scopes = scopes)
return(token)

Can't fetch slack user profile information with API

Thank you so much in advance. I am trying to fetch user profile information through slack_authentication. Although the app is successfully authenticated with Slack, it could not get email and username.
{'ok': True, 'access_token': 'xoxp-xXXXXXXXXXXXXXXXX', 'scope': 'identify,channels:read,users.profile:read,chat:write:bot,identity.basic', 'user_id': 'XXXXXXXXX', 'team_id': 'XXXXXXXX', 'enterprise_id': None, 'team_name': 'test', 'warning': 'superfluous_charset', 'response_metadata': {'warnings': ['superfluous_charset']}}
I tried to add identify scope instead of identity.basic because slack doesn't allow you to use both identity.basic and other scopes.
The code is below:
#bp.route('/redirect', methods=['GET'])
def authorize():
authorize_url = f"https://slack.com/oauth/authorize?scope={ oauth_scope }&client_id={ client_id }"
return authorize_url
#bp.route('/callback', methods=["GET", "POST"])
def callback():
auth_code = request.args['code']
client = slack.WebClient(token="")
response = client.oauth_access(
client_id=client_id,
client_secret=client_secret,
code=auth_code
)
print(response)
Additional
I have realized how to get users info. I updated the code to like this.
The code is updated like below:
oauth = client.oauth_access(
client_id=client_id,
client_secret=client_secret,
code=auth_code
)
user_id = oauth['user_id']
response = client.users_info(user=user_id)
But this error occurs:
The server responded with: {'ok': False, 'error': 'not_authed'}
Your code looks like an installation routine for a Slack app using OAuth. But it does not contain a call to get a user profile.
To get the profile of a user you can call users.info and provide the ID of the user you are interested in.
Examples:
response = client.users_info(user=ID_OF_USER)
assert(response)
profile = response['user']['profile']
email = response['user']['profile']['email']
In order to retrieve the user's profile and email address you need these scopes:
- users:read
- users:read.email
The identity scopes are unrelated to the user profile. They are used for the "Sign-in with Slack" approach only, where you can authenticate with a Slack user on a 3rd party web site.
Finally, just to clarify, because this is often misunderstood: You only need to run through the OAuth installation routine once. The routine will yield you a token for the workspace, which you can store and use for any further calls to the API for that workspace.
Update to "Additional"
You are not using the API correctly.
You need to first complete the Oauth flow and collect the access token, which is in the response from client.oauth_access.
Then you need to initialize a new WebClient with the token you received. With the new client you can then access all API methods, like users.info etc.
Again: You should run through the OAuth process one time only and store the received token for later use.
Example:
oauth_info = client.oauth_access(
client_id=client_id,
client_secret=client_secret,
code=auth_code
)
access_token = oauth_info['access_token'] # you want to store this token in a database
client = slack.WebClient(token=access_token)
user_id = oauth_info['user_id']
response = client.users_info(user=user_id)
print(response)

Accessing LinkedIn data via API using python (and authorisation in general)

I'm trying to access LinkedIn data via API (I don't have an app, I just want to access company data - or see what can be accessed). There are other questions here on this topic, but most are out of date (using packagaes which precede LinkedIn's current authorisation process).
I followed the LinkedIn documentation on authorisation: https://developer.linkedin.com/docs/oauth2
I created an application (using a nonsense website url as I do not have a website). This gave me a Client ID and Client Secret.
Using (out of date) stuff from LinkedIn (https://github.com/linkedin/api-get-started/blob/master/python/tutorial.py) I wrote:
import oauth2 as oauth
import urllib.parse as urlparse
consumer_key = 'my client id e.g. sjd6ffdf6262d'
consumer_secret = 'my customer secret e.g. d77373hhfh'
request_token_url = 'https://api.linkedin.com/uas/oauth/requestToken'
access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken'
authorize_url = 'https://api.linkedin.com/uas/oauth/authorize'
consumer = oauth.Consumer(consumer_key, consumer_secret)
client = oauth.Client(consumer)
resp,content = client.request(request_token_url, "POST")
request_token = dict(urlparse.parse_qsl(content))
clean_request_token = {}
for key in request_token.keys():
clean_request_token[key.decode('ascii')] = request_token[key].decode('ascii')
request_token = clean_request_token
print ("Go to the following link in your browser:")
print ("%s?oauth_token=%s" % (authorize_url, request_token['oauth_token']
This link takes me to a website where I 'give permission', and am then shown a pin code. Using this pin (called oauth_verifier here):
oauth_verifier = 12345
token = oauth.Token(request_token['oauth_token'],
request_token['oauth_token_secret'])
token.set_verifier(oauth_verifier)
client = oauth.Client(consumer, token)
content = client.request(access_token_url,"POST")
access_token = dict(urlparse.parse_qsl(content[1]))
clean_access_token = {}
for key in access_token.keys():
clean_access_token[key.decode('ascii')] = access_token[key].decode('ascii')
access_token = clean_request_token
token = oauth.Token(key=access_token['oauth_token'],secret=access_token['oauth_token_secret'])
client = oauth.Client(consumer, token)
response = client.request("http://api.linkedin.com/v1/companies/barclays")
This response has a 401 code, due to "The token used in the OAuth request has been revoked."
The underlying problems are:
I don't really get how APIs work, how they work with python, how authorisation works or how to know the api url I need.
In case relevant, I have experience web scraping (using requests plus beautiful soup to parse) but not with APIs.
I eventually worked it out, posting here in case anyone comes this way. Before you invest time, I also found out that the freely available API now only allows you to access your own profile or company page. So you can write an app that allows a user to post to their own page, but you can't write something to grab data. See here:
LinkedIn API unable to view _any_ company profile
Anyway, to get the limited API working, you need to:
Create a LinkedIn account, create an application and add a redirect URL to your application page (I used http://localhost:8000). This doc says how to set up the app: https://developer.linkedin.com/docs/oauth2
Following the steps in the above link, but in python, you make a request to gain an "access code".
html = requests.get("https://www.linkedin.com/oauth/v2/authorization",
params = {'response_type':'code','client_id':client_id,
'redirect_uri':'http://localhost:8000',
'state':'somestring'})
print html.url to get a huge link - click on it. You'll be asked to login and allow access, and then you'll be redirected to your redirect url. There'll be nothing there, but the url will have a long "access code" on the end of it. Pull this out and send it to LinkedIn with a Post request:
token = requests.post('https://www.linkedin.com/oauth/v2/accessToken',
data = {'grant_type':'authorization_code','code':access_code,
'redirect_uri':'http://localhost:8000',
'client_id':client_id,'client_secret':client_secret})
token.content will contain an "access_token". This is what is needed to access the API. e.g. to access your own profile:
headers = {'x-li-format': 'json', 'Content-Type': 'application/json'}
params = {'oauth2_access_token': access_token}
html = requests.get("https://api.linkedin.com/v1/people/~",headers=headers,params = params)
Hopefully that's useful to someone starting from scratch, the info is mostly out there but there are lots of assumed steps (like how to use the access token with requests).

Generate access token by google login using oauth2

My front end in Angular JS.
It sends me google token after user logs in with gmail
In backend I verify the token and extract information from it as below
#csrf_exempt
def check(request):
CLIENT_ID = 'xxxxx'
try:
json_data = json.loads(request.body.decode('utf-8'))
idinfo = id_token.verify_oauth2_token(json_data['google_token'], requests.Request(), CLIENT_ID)
if idinfo['iss'] not in ['accounts.google.com', 'https://accounts.google.com']:
raise ValueError('Wrong issuer.')
print("idinfo")
print(idinfo)
Now I got the user details here and want to generate an access token to access my API's for every request.
Is there any built in function from oauth2 to generate an access token.
Any suggestion that would help me. Thanks.

How To Get LinkedIn Return URL after Authentication

I am trying to use https://github.com/ozgur/python-linkedin
if __name__ == '__main__':
API_KEY = 'XXXXXXXXXXX'
API_SECRET = 'XXXXXXXXXX'
RETURN_URL = 'http://localhost:8080'
authentication = LinkedInAuthentication(API_KEY, API_SECRET, RETURN_URL, PERMISSIONS.enums.values())
print authentication.authorization_url
This code prints:
https://www.linkedin.com/uas/oauth2/authorization?scope=r_basicprofile%20r_emailaddress%20w_share&state=1e7f21566bdd75cee5d71d0615f338ad&redirect_uri=http%3A//localhost%3A8080&response_type=code&client_id=XXXXXXXXXX
When I click this link, LinkedIn authentication page is opening. After authentication, it returns that URL:
http://localhost:8080/?code=CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC&state=f40c8d9ec67df057e72eeb235f4d8e7c
If I copy that CCCCCCCC... code quickly and use it in
application = LinkedInApplication(authentication)
authentication.authorization_code = "CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC"
application = LinkedInApplication(token=authentication.get_access_token())
print application.get_profile()
it prints the profile information that I need. But I don't want to click to URL and copy that CCCCC... code into my python code. I want to do these programmatically. I need to get that authorization_code. How can I do that?
I run into an invalid redirect_uri error when I follow the link that I get, so I can only help you get started.
If the code was on the page you are linked to, you could simply HTTP GET the page and extract the code. However, since you say you must load the page in your browser, authenticate yourself, then get the code from the resulting page, the process is a bit more complicated. Can you try a GET on the page with your credentials already included?
import requests
if __name__ == '__main__':
API_KEY = 'XXXXXXXXXXX'
API_SECRET = 'XXXXXXXXXX'
RETURN_URL = 'http://localhost:8080'
authentication = LinkedInAuthentication(API_KEY, API_SECRET, RETURN_URL, PERMISSIONS.enums.values())
auth_url = authentication.authorization_url
#Create an HTTP request with your credentials included
response = requests.get(auth_url, auth=requests.auth.HTTPBasicAuth('username', 'password'))
print response
print response.text
This is just to get you started. I believe that authenticating yourself programmatically is possible, but it may be slightly more complicated than this basic approach. Let me know what this returns for you.

Categories