Flask session persistance along multiple subdomains and OAuth1Session - python

I'm trying to use the OAuth token and storing it in the session object as I move between different subdomains. So I have the application starting the OAuth1.0a workflow at flask.mydomain.com. It then redirects to sub.mydomain.com/initiate to fetch the request tokens and I want to save the oauth token secret using sessions (not sure if this is the best way), and then authorizes at sub.mydomain.com/authorize. Once the authorization is complete, it goes to the callback but the oauth token secret does not exist in the session. I'm also trying to save the OAuth1Session so that whenever we go to a new route, that data is saved. So I'm not sure how to handle it since the sessions are defined within the scope of the function.
I read that app.secret_key = os.urandom(someval) doesn't make it work which is what I don't have and I made the OAuth1Session to be global originally which doesn't sound like a good idea (happens in the callback).
#app.route("/initiate")
def initiate():
oauth_session = OAuth1Session(client_key=client_key,client_secret=client_secret,callback_uri=callback_uri)
fetch_response = oauth_session.fetch_request_token(request_token_url)
oauth_token = fetch_response.get('oauth_token')
oauth_token_secret = fetch_response.get('oauth_token_secret')
session['oauth_token_secret'] = oauth_token_secret
full_authorization_url = oauth_session.authorization_url(authorize_url, request_token=oauth_token)
return redirect(full_authorization_url)
#app.route("/callback")
def callback():
session.permanent = True
if ('oauth_token_secret' not in session):
return "There is no oauth token secret"
verifier = request.args.get("oauth_verifier")
oauth_token = request.args.get("oauth_token")
oauth = OAuth1Session(
client_key=client_key,
client_secret=client_secret,
resource_owner_key=oauth_token,
resource_owner_secret=session['oauth_token_secret'],
verifier=verifier) # I would like this oauth session to persist until a certain amount of time before having to reauthenticate
fetch_access_tokens= oauth.fetch_access_token(access_token_url)
return redirect(url_for('.getstatus'))
#app.route("/getStatus")
def getstatus():
r = oauth.get(webservice_url + "/statuses")
if r.status_code == 401:
return redirect(url_for('initiate'))
print(r.content)
return r.content

I fixed the issue, it was with the SERVER_NAME config for the application. The SERVER_NAME was set to flask.mydomain.com, so I just removed it entirely

Related

equivalent of flask.request.url in FastAPI

i am trying to change google oauth2 example code from python flask to FastAPI.
this is the code
def oauth2callback():
# Specify the state when creating the flow in the callback so that it can
# verified in the authorization server response.
state = flask.session['state']
flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
CLIENT_SECRETS_FILE, scopes=SCOPES, state=state)
flow.redirect_uri = flask.url_for('oauth2callback', _external=True)
# Use the authorization server's response to fetch the OAuth 2.0 tokens.
print("this is the flask request url -----------", flask.request.url)
**authorization_response = flask.request.url**
flow.fetch_token(authorization_response=authorization_response)
# Store credentials in the session.
# ACTION ITEM: In a production app, you likely want to save these
# credentials in a persistent database instead.
credentials = flow.credentials
flask.session['credentials'] = credentials_to_dict(credentials)
creds = google.oauth2.credentials.Credentials(
**flask.session['credentials'])
return flask.redirect(flask.url_for('test_api_request'))
the line is authorization_response = flask.request.url
the value of it is "http://localhost:8080/oauth2callback?state=79aCVleeoxdA4bYgo5YnzuK8vsvM22&code=4%2F0AWtgzh611Sc3dhUo_pqQSa4RVTEZOgX9rJHc328XCJ4UmLvHdg5zz3t1k8VS3ihZwKMEA&scope=email+profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.modify+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.labels+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email&authuser=0&prompt=none"
now i just want to change this line to the same in fastapi, i have tried request.url.path but it gives me "/oauth2callback" or sometimes None.
The request.url property is a string-like object, and you can get the full URL by casting it as a string.
i.e. str(request.url)
You can also access properties of the URL individually - more information on this can be found in Starlette's documentation.

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)

How to expire access token using flask-jwt-extend when new login is initiated

I am creating the access token using the flask-jwt-extended and storing it into httpcookie only.
My requirement is if user logins to the site using credentials, I will generate one token and store it in httpcookie, so my protected route will be accessible through that access token.
If the same user will login to the site using the different system with the same credentials, then I want to expire the access token which I have created first, so when user will try to access the protected route it will be forbidden, it means, that it will logout the user explicitly from the first system.
Below is the code using which I am creating the access token and storing it in a cookie.
Note: in my case i am using imspin as an identity.
class NewJwtAuthentication(Resourse):
def post(self):
requestData = request.get_json()
LogRecordings().request(requestData)
id = requestData['id']
useremail = requestData['useremail']
if requestData['id'] == '' or requestData['id'] == '':
emptyDataResponse()
getstudentdetails = fetchAllWhere(DB_Queries.SelectAllUsingPinAndEmail, id,useremail)
if getstudentdetails :
#redirect(url_for('loginsuccess'))
access_token = create_access_token(identity=id)
refresh_token = create_refresh_token(identity=id)
d = jwt.decode(access_token, '48e48e4e1796b1de856737ca2418dd43', algorithms='HS256')
expiration_time = d['exp']
expires_on=datetime.fromtimestamp(expiration_time).strftime('%Y-%m-%d %H:%M:%S')
print(expires_on)
print(access_token)
print(refresh_token)
resp = make_response({'message': 'Login Successfull',
'csrf_token':flask_jwt_extended.get_csrf_token(encoded_token=access_token),
'csrf_refresh_token':flask_jwt_extended.get_csrf_token(encoded_token=refresh_token),
'accesstoken_expiry_time':expires_on,
'id':id})
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
#print(flask_jwt_extended.get_csrf_token(encoded_token=access_token))
#set_refresh_cookies(response, refresh_token)
return resp
else:
return make_response({'message':'could not verify' })
any help would be highly appreciated.

Display list of all registered beacons

I am working with beacons and want to display all the registered beacons on a same web page by making the request in python.
I am confused, After setting up the scope of OAuth2, how to send the request or discovery.build() to get list of all the requests.
I am setting up the scope by this:
#portal.route('/oauth2callback')
def oauth2callback():
flow = client.flow_from_clientsecrets(
'client_secrets.json',
scope='https://www.googleapis.com/auth/userlocation.beacon.registry',
redirect_uri=flask.url_for('portal.oauth2callback', _external=True),
)
if 'code' not in flask.request.args:
auth_uri = flow.step1_get_authorize_url()
return flask.redirect(auth_uri)
else:
auth_code = flask.request.args.get('code')
credentials = flow.step2_exchange(auth_code)
flask.session['credentials'] = credentials.to_json()
return flask.redirect(flask.url_for('portal.index'))
#portal.route('/')
def index():
if 'credentials' not in flask.session:
return flask.redirect(flask.url_for('portal.oauth2callback'))
credentials = client.OAuth2Credentials.from_json(
flask.session['credentials']
)
if credentials.access_token_expired:
return flask.redirect(flask.url_for('portal.oauth2callback'))
else:
http_auth = credentials.authorize(httplib2.Http())
drive_service = discovery.build('# What should I write')
# Or, requests.get(What should I write)
Can some one help me how to get list of all registered beacons by making the request.
Hrm. I don't have much experience with Python, but I'm pretty sure there are Google Sign-In clients for python such as here on GitHub.
With this you can integrate a login flow to your app.
Then, when you make calls to the Proximity Beacon Admin API, to auth you just have to set the HTTP header:
Authorization: Bearer <<OAUTH_BEARER_TOKEN_HERE>>
and your call should be authenticated properly. Then you can do the python equivalent of like http.get() or http.post(), add that HTTP header, and you should be able to see responses.
It get done by sending request like:
sess = requests.Session()
req = sess.get('https://proximitybeacon.googleapis.com/v1beta1/beacons', headers={'Authorization': 'Bearer '+credentials.access_token})

Oauth client initialization in python for tumblr API using Python-oauth2

I'm new to Oauth. In the past for twitter applications written in Python i used python-oauth2 library to initialize client like this:
consumer = oauth.Consumer(key = CONSUMER_KEY, secret = CONSUMER_SECRET)
token = oauth.Token(key = ACCESS_KEY, secret = ACCESS_SECRET)
client = oauth.Client(consumer, token)
That was easy because twitter provides both CONSUMER and ACCESS keys and secrets. But now i need to do the same for tumblr. The problem is that tumblr provides only CONSUMER_KEY, CONSUMER_SECRET and these urls:
Request-token URL http://www.tumblr.com/oauth/request_token
Authorize URL http://www.tumblr.com/oauth/authorize
Access-token URL http://www.tumblr.com/oauth/access_token
Using this data how can i initialize client to access tumblr API?
UPD
jterrace suggested a code i tried to use before. The problem with it is oauth_callback. If i don't specify any, api returns error "No oauth_callback specified", but if i do specify some url like "http://example.com/oauthcb/" and follow the link http://www.tumblr.com/oauth/authorize?oauth_token=9ygTF..., then press Allow button, tumblr doesn't show any PIN code page, it immediately redirects to that callback url, which is useless since it's desktop application. Why PIN code isn't shown?
UPD 2
Tumblr API doesn't support PIN code authorization. Use xAuth instead - https://groups.google.com/group/tumblr-api/browse_thread/thread/857285e6a2b4268/15060607dc306c1d?lnk=gst&q=pin#15060607dc306c1d
First, import the oauth2 module and set up the service's URL and consumer information:
import oauth2
REQUEST_TOKEN_URL = 'http://www.tumblr.com/oauth/request_token'
AUTHORIZATION_URL = 'http://www.tumblr.com/oauth/authorize'
ACCESS_TOKEN_URL = 'http://www.tumblr.com/oauth/access_token'
CONSUMER_KEY = 'your_consumer_key'
CONSUMER_SECRET = 'your_consumer_secret'
consumer = oauth2.Consumer(CONSUMER_KEY, CONSUMER_SECRET)
client = oauth2.Client(consumer)
Step 1: Get a request token. This is a temporary token that is used for
having the user authorize an access token and to sign the request to obtain
said access token.
resp, content = client.request(REQUEST_TOKEN_URL, "GET")
request_token = dict(urlparse.parse_qsl(content))
print "Request Token:"
print " - oauth_token = %s" % request_token['oauth_token']
print " - oauth_token_secret = %s" % request_token['oauth_token_secret']
Step 2: Redirect to the provider. Since this is a CLI script we do not
redirect. In a web application you would redirect the user to the URL
below.
print "Go to the following link in your browser:"
print "%s?oauth_token=%s" % (AUTHORIZATION_URL, request_token['oauth_token'])
# After the user has granted access to you, the consumer, the provider will
# redirect you to whatever URL you have told them to redirect to. You can
# usually define this in the oauth_callback argument as well.
oauth_verifier = raw_input('What is the PIN? ')
Step 3: Once the consumer has redirected the user back to the oauth_callback
URL you can request the access token the user has approved. You use the
request token to sign this request. After this is done you throw away the
request token and use the access token returned. You should store this
access token somewhere safe, like a database, for future use.
token = oauth2.Token(request_token['oauth_token'], request_token['oauth_token_secret'])
token.set_verifier(oauth_verifier)
client = oauth2.Client(consumer, token)
resp, content = client.request(ACCESS_TOKEN_URL, "POST")
access_token = dict(urlparse.parse_qsl(content))
print "Access Token:"
print " - oauth_token = %s" % access_token['oauth_token']
print " - oauth_token_secret = %s" % access_token['oauth_token_secret']
print
Now that you have an access token, you can call protected methods with it.
EDIT: Turns out that tumblr does not support the PIN authorization method. Relevant post here.
If you just want to gain an access-token/secret to sign, you could just setup your callback URL as: http://localhost/blah
Fireup the CLI-app (after modifying the callback-url, secret and token ofcourse)
Follow the link in your browser
Allow app
View addressbar of the page you've been redirected to in the browser after allowing your app. It should look something like:
http://localhost/blah?oauth_token=xxxxxxxxxxxxxxxxxxxxxxxxxx0123456789ABCDEFGHIJKLMN&oauth_verifier=XXXXXXXXXXXXXXXXXXXXXXXXX0123456789abcdefghijklmn
Use the value of the query-parameter 'oauth_verifier' as your PIN:
XXXXXXXXXXXXXXXXXXXXXXXXX0123456789abcdefghijklmn
The CLI should print out your oauth-token and oauth-token-secret.
HTH! Got this working for tumblr in this way :)
Have a look at https://github.com/ToQoz/Pyblr
It uses oauth2 and urllib to provide a nice wrapper for exactly what you're trying to do.
It seems that what you're trying to do is access an OAuth 1 API with an OAuth 2 client.
See https://github.com/simplegeo/python-oauth2 and look for “three-legged OAuth example”.
had this problem with oauth2 and facebook.
#deepvanbinnen's answer lead me into the right direction.
facebook actually redirected to a page similar to this
'http://localhost/blah?code=AQAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#_=_'
using then the ' AQAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX#_=_ as the PIN actually got me the access to the requested facebook account.
#jterrance's answer is good. However, realize it is a one _time_ manual procedure to get the access token. The access token is the key that you use for all subsequent API calls. (That's why he recommends saving the access token in a database.) The string referred to as 'PIN' (aka the verification key) is not necessarily a number. It can be a printable string in any form. That verification key is displayed on the authorization page at the URL printed in step 2 then pasted into the prompt for a the 'PIN'.

Categories