Getting invalid_grant when trying to refresh token - python

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.

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

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).

Instagram Client Side Authentication using 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.

Facebook Graph API python facepy

I'm using facepy for retrieving fb comments and posts (This is the objective). I've given a valid access token (generated from http://developers.facebook.com/tools/explorer/?method=GET&path=me)
The error generated is:
NameError: name 'AAACEdEose0cBAHshwZCGJ6dHPb0x68c.......D' is not defined. And/OR
facepy.exceptions.OAuthError: [190] Error validating access token: Session has expired at unix time 1359752400.
I believe I've generated the correct access token (with the correct permissions) I thought I would test the facepy library for retrieving photos first. Is their a faster way to retrieve comments, respective user ids, and time stamp from a public fan page (I am guessing most of my target pages have 'public information')
Can someone help me on this?
from facepy import GraphAPI
graph = GraphAPI(AAACEdEose0cBAHshwZCGJ6dHPb0x68c.......D)
graph.get('me/posts')
graph.post(
path = 'me/photos',
source = open('parrot.jpg')
Never tried with the FB but some of the solutions which worked with other API's.
Error validating access token: Session has expired at unix time 1359752400.
Says All. However mostly occurs when I did connected it to some DB for storing some information retrieved from the API.I am sure you have made a right key and password so don't worry about it. Make sure the other connection is still open.
Second, it happened again when I did not accessed the API for weeks so make sure to log in once or twice.
Your API needs to be in quotes...
also generate an extended token via the below

Automatically refresh access token with django-social-auth (omab)

I am currently using django-social-auth to manage oauth2 registration with google-oauth2 for access to Google Drive. I have added offline access to my extra_arguments. Therefore Google returns a refresh token and it is stored by django-social-auth. The problem is that django-social-auth never uses this refresh token to update the access token. Therefore the access token expires after one hour, and I can't use it to perform offline requests. I want to keep the access_token valid 24/7 so I can keep my database synced with each users Google Drive.
GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {'access_type':'offline'}
GOOGLE_OAUTH_EXTRA_SCOPE = ['https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/userinfo.profile']
SOCIAL_AUTH_USER_MODEL = 'accounts.GoogleDriveUser'
SOCIAL_AUTH_EXTRA_DATA = True
SOCIAL_AUTH_SESSION_EXPIRATION = False
Is there a way to force django-social auth to update the access_token every time it expires using the refresh_token. I would love to see an example of how this problem could be solved.
It looks like UserSocialAuth objects now have a .refresh_token() method, which allows you to use .tokens and get the updated token.
There's no way directly implemented in django-social-auth at the moment (I've raised a ticket to track it https://github.com/omab/django-social-auth/issues/492), meanwhile this snippet will do the work, it just need to be improved a little to suite your needs.

Categories

Resources