Instagram Client Side Authentication using Python - python

I am currently working on a bottle project and will be using Instagram api. I was hoping to use the client side authentication however I am having problems with the access token as it does not returns as a parameter.
I am making the request here:
https://api.instagram.com/oauth/authorize/?client_id=client_id&redirect_uri=redirect_uri&response_type=token&scope=basic+follower_list
The app is redirected to token page correctly and I can even see the token in the url. But when I try to parse it, it comes out empty.
#route('/oauth_callback')
def success_message():
token = request.GET.get("access_token")
print token.values()
return "success"
The token.values() returns an empty list.
ps: Keep in mind that when I try to do the same operation with server side authentication, I can successfully get the code and exchange it for a token.

Once you make a query to Instagram api you must be receiving below response?
http://your-redirect-uri#access_token=ACCESS-TOKEN
the part after # is termed as fragment and not query_string parameter and there is no way you can retrieve that information on Server side in Bottle.
To actually get fragments, bottle.request.urlparts is used
urlparts
The url string as an urlparse.SplitResult tuple. The tuple
contains (scheme, host, path, query_string and fragment), but the
fragment is always empty because it is not visible to the server.
Use the SDK and preferably Server Side operations -> https://github.com/facebookarchive/python-instagram
If you will to go with this approach, then managing a JavaScript which parses the access-token and then posts to your bottle api for your consumption which I don't recommend...
From https://instagram.com/developer/authentication/
Client-Side (Implicit) Authentication
If you are building an app that does not have a server component (a
purely javascript app, for instance), you will notice that it is
impossible to complete step three above to receive your access_token
without also having to store the secret on the client. You should
never pass or store your client_id secret onto a client. For these
situations there is the Implicit Authentication Flow.

Related

Salesforce API - This session is not valid for use with the REST API - Invalid Session ID

For over a year, I have connected to Salesforce using the simple_salesforce package in order to pull some data from various objects and load it to a data lake.
I have used the authentication method using username / password / security token.
client = Salesforce(
username="****************",
password="*************",
security_token="****************"
)
On the 1st of February came the enforcement of multi factor auth. Starting on that day, I consistently hit the same error over and over.
[{'message': 'This session is not valid for use with the REST API', 'errorCode': 'INVALID_SESSION_ID'}]
After some research, I tried to add a permission set with API Enabled and then API Only user. Result: still the same error, but now I am locked out of the UI.
Has anyone else encountered similar issues and could point me towards the right resources, please? Thanks!
MFA shouldn't matter for API access according to https://help.salesforce.com/s/articleView?id=000352937&type=1 (Ctrl+F "API"), it's probably something else your admin did.
Username, password+token sounds like you're use SOAP login method.
See if you can create a "connected app" in SF to use the OAuth2 login method, more natural for REST API. I wrote a bit about it in https://stackoverflow.com/a/62694002/313628. In the connected app you should be able to allow API access, even full if needed. No idea if Simple has natural place for the keys though, it's bit rubbish if you'll have to craft raw http requests yourself.
Simple's documentation also mentions using JWT to log in (and that requires connected app anyway), basically instead of username + pass you go username + certificate + the fact admin preauthorised this user... You'll be fine until certificate expires.
The text part of https://gist.github.com/booleangate/30d345ecf0617db0ea19c54c7a44d06f can help you with the connected app creation; sample code's probably not needed if you're going with Simple

Get and parse data from the last message of a specific sender with python and Gmail API

Everyday, a sender "sender#sender.com" send me a message with a number inside.
I need to save this number everyday.
I want to write a python script with gmail API to get data from last mail from this sender, and then parse it.
I followed the Gmail API "Quickstart Guide" : here
I also check the page about User.message : here
However, I don't understand how to synchronize all of this to get the data.
Could someone explain me the process ?
If you where you able to complete the Gmail API quickstart, then you already have a GCP project, credentials and have authorized some Gmail API scopes for you app.
The above is the first step (being able to authenticate and be allowed to make requests for the API scope you need).
Since you need to pass a message's Id as a parameter for Users.messages.get you need to first retrieve it using listing messages for example.
So the next step is to make a request to Users.messages.list to list all messages from a user.
You could use the query (q) parameter to filter the messages by user like: q="from:someuser#example.com is:unread".
This will return a list of messages from someuser#example.com that are unread.
Try things out in the API explorer sidebar from the documentation until you have defined the request as you want, and then implement it into you app.
As aerials said.
users().messages().list(userId='me',q=("<parameters>"))).execute()
The above code will fulfill the exact same function as typing in a search request on the gmail website. You dont actually have to worry about labels or anything if you are operating at a small scale. Just follow the same syntax as the search bar on gmail.
However, I am not sure about the usage quotas on the q parameter for list. It may be more expensive for a bigger scale operation to use the q parameter instead of using the other api methods.

How to use google python oauth libraries to implement OpenID Connect?

I am evaluating different options for authentication in a python App Engine flex environment, for apps that run within a G Suite domain.
I am trying to put together the OpenID Connect "Server flow" instructions here with how google-auth-library-python implements the general OAuth2 instructions here.
I kind of follow things up until 4. Exchange code for access token and ID token, which looks like flow.fetch_token, except it says "response to this request contains the following fields in a JSON array," and it includes not just the access token but the id token and other things. I did see this patch to the library. Does that mean I could use some flow.fetch_token to create an IDTokenCredentials (how?) and then use this to build an OpenID Connect API client (and where is that API documented)? And what about validating the id token, is there a separate python library to help with that or is that part of the API library?
It is all very confusing. A great deal would be cleared up with some actual "soup to nuts" example code but I haven't found anything anywhere on the internet, which makes me think (a) perhaps this is not a viable way to do authentication, or (b) it is so recent the python libraries have not caught up? I would however much rather do authentication on the server than in the client with Google Sign-In.
Any suggestions or links to code are much appreciated.
It seems Google's python library contains a module for id token validation. This can be found at google.oauth2.id_token module. Once validated, it will return the decoded token which you can use to obtain user information.
from google.oauth2 import id_token
from google.auth.transport import requests
request = requests.Request()
id_info = id_token.verify_oauth2_token(
token, request, 'my-client-id.example.com')
if id_info['iss'] != 'https://accounts.google.com':
raise ValueError('Wrong issuer.')
userid = id_info['sub']
Once you obtain user information, you should follow authentication process as described in Authenticate the user section.
OK, I think I found my answer in the source code now.
google.oauth2.credentials.Credentials exposes id_token:
Depending on the authorization server and the scopes requested, this may be populated when credentials are obtained and updated when refresh is called. This token is a JWT. It can be verified and decoded [as #kavindu-dodanduwa pointed out] using google.oauth2.id_token.verify_oauth2_token.
And several layers down the call stack we can see fetch_token does some minimal validation of the response JSON (checking that an access token was returned, etc.) but basically passes through whatever it gets from the token endpoint, including (i.e. if an OpenID Connect scope is included) the id token as a JWT.
EDIT:
And the final piece of the puzzle is the translation of tokens from the (generic) OAuthSession to (Google-specific) credentials in google_auth_oauthlib.helpers, where the id_token is grabbed, if it exists.
Note that the generic oauthlib library does seem to implement OpenID Connect now, but looks to be very recent and in process (July 2018). Google doesn't seem to use any of this at the moment (this threw me off a bit).

Google+ login - Server side flow - Storing credentials - Python examples

I am building an app on Google App Engine using Flask. I am implementing Google+ login from the server-side flow described in the Python examples: https://developers.google.com/+/web/signin/server-side-flow and https://github.com/googleplus/gplus-quickstart-python/blob/master/signin.py.
Both of the examples have:
credentials = oauth_flow.step2_exchange(code)
and
session['credentials'] = credentials
storing the credentials object to the Flask session. When I run this code on my Google App Engine project, I get the error:
TypeError: <oauth2client.client.OAuth2Credentials object at 0x7f6c3c953610> is not JSON serializable
As discussed in this issue (marked WontFix), the OAuth2Credentials is not designed to by JSON serializable. It has methods to_json and from_json, which could be used to store it, e.g:
session['credentials'] = credentials.to_json()
However, in the same issue:
Never store a Credentials object in a cookie, it contains the applications
client id and client secret.
Perhaps I misunderstand how a Flask session object works, but from the doc:
... A session basically makes it possible to remember information from one request to another. The way Flask does this is by using a signed cookie. So the user can look at the session contents, but not modify it unless they know the secret key...
And therefore, we should not be storing a credentials object in the session, even if it is a signed cookie.
In my case, I currently only need to re-use the access token for disconnect purposes, so I can just store that.
What is the correct way to deal with this situation? Should the credentials not be stored in the session at all? Should at this point in the examples there be a comment "Securely save credentials here"?
Flask used to use pickle instead of JSON to store values in the session, and the Google example code was written with that in mind. Flask switched to a JSON-based format to reduce the impact of the server-side secret being disclosed (a hacker can hijack your process with pickle, not with JSON).
Store just the access token in your session:
session['credentials'] = credentials.access_token
You can recreate the credentials object with that token, using the AccessTokenCredentials class at a later time, should you need it again:
credentials = AccessTokenCredentials(session['credentials'], 'user-agent-value')
The AccessTokenCredentials object stores just the credentials; because it lacks the client id and client secret it cannot be used to refresh the token, however.
The user agent value is something you get to make up; it can help diagnose problems if you have access to the OAuth server logs; with Google I would not count on that so just make something up here.
"Flask by default uses the Werkzeug provided 'secure cookie' as session system. It works by pickling the session data, compressing it and base64 encoding it." - http://flask.pocoo.org/snippets/51/
In other words, flask is really weird. Anything you put in the session, it gets ciphered with the server key, sent to the client and stored in the client. The server then receives it on each subsequent request and decodes it with the same key. It also means session data will survive server reboots because it's sitting in the client.
To improve this for my app I've used the flask SessionInterface with Couchdb - and now the client only knows a sessionID that is checked against my database where the actual data is stored. Hurray.
Check this out, it has a few approaches to server side sessions depending what db you may be using - http://flask.pocoo.org/snippets/category/sessions/

Getting invalid_grant when trying to refresh token

When an OAuth2Credential object tries to refresh its access_token, sometimes it gets an error of invalid_grant and then it becomes unable to be refreshed. The code I used is based on Google's python API and Mirror API examples.
Background:
Using oauth2client module for authentication and OAuth2Credential object.
Storing the OAuth2Credential object pickled and base64'd into the database like Google's own example code
Using apiclient module to make calls to the Mirror API
This code runs on 3 different servers, all exhibiting the same issue when trying to send
The scopes I ask for are "https://www.googleapis.com/auth/glass.timeline" and "https://www.googleapis.com/auth/userinfo.profile"
I can confirm that access_type is set to "offline"
I ask for approval_prompt to be "force" just in case
Here is the code that is being used to call the mirror API:
from apiclient.discovery import build
http = credential.authorize(http=httplib2.Http())
service = build("mirror", "v1", http=http)
payload = <JSON_PAYLOAD_HERE>
service.timeline().insert(body=payload).execute()
When the service is called, there is the potential for it to issue a 401 which means the access_token needs to be refreshed. It then calls the refresh method which excepts with AccessTokenRefreshError with the error invalid_grant. At this point, the credential is as good as bunk, since the access_token is expired and the refresh_token will only give the same error.
I have seen pages that say this can happen due to either NTP problems, but I have confirmed (and even switched NTP servers) that my servers are in sync. The other documented possibility is that only 25 refresh tokens can exist before they get recycled, but I have implemented a store() method on the Credential object so when it is refreshed, the new credentials are saved in place (I can confirm that this works as I see new information in the database when it is refreshed).
Since I can't get a user's credentials to start exhibiting this problem on demand, I can't explain any other conditions to recreate the issue other than "waiting some time". I have seen the issue happen soon after authenticating and sending one call, all the way to a week's worth of time after a hundred calls.
The only way for now to get the issue to be resolved is to ask the user to reauthorize, but that isn't a solution since I am expecting to use the api's offline without user interaction. I'd also have no way to notify the user that they need to reauthorize.
Answer from the comment thread: the user had toggled off the Glassware from the MyGlass website which resulted in the token being revoked.
The user needs to go through the authorization flow again in order to be able to use the Glassware by either visiting the Glassware authorization endpoint or toggling it back "on" on MyGlass if available.

Categories

Resources