I only need oauth2 for login so far, but I feel that to be reasonably complete, my app should still handle refresh tokens.
I'm fairly new to oauth, so here is my understanding:
By keeping access token lifetime short, but refresh token lifetime long, you force the client to "check in" regularly to renew the access token, and thereby maintain more control.
But how to actually do that using authlib and the flask integration?
There seems to be no refresh_token() on the FlaskRemoteApp, and I have not been able to find any example code showing this.
This seems to work to get a new token
res = oauth.myOauth2.fetch_access_token(refresh_token=session['tok_res']['refresh_token'])
session['tok_res'].update(res)
But fails when subsequently using the new access_token for an api call.
Could be a server error I suppose, or maybe I need to wait for the old token to expire before using the new one? The expires_at time, keeps updating and that makes no sense to me in that case.
It would be great if somebody could explain how refresh_token is intended to be used with authlib and flask.
Well, unless #lepture drops by with the answer, I have at least an answer.
I was simply missing grant_type='refresh_token' from my call.
So this now works as expected for me.
if session['oatoken']['expires_at'] - 2 < now: # refresh 2 seconds early
oatoken = oauth.myOauth2.fetch_access_token(
refresh_token=session['oatoken']['refresh_token'],
grant_type='refresh_token')
session['oatoken'].update(oatoken)
I played around a little with setting the update_token function in the registry, but was not able to make it work. In any case I believe this is only triggered if an api call using the token receives an "expired token" reply. In my case I'm only using Oauth for login, so I can just watch the expires_at time, and only hit the auth server when necessary.
Related
I am learning Django and have an idea for an app that would access data on the Microsoft Graph API for users of their outlook service.
It seems the cleanest way of doing this is by using a package like django-all-auth to handle obtaining and storing the authorisation token in the backend. There’s also an example on the Graph API website using python-social-auth.
However, I’ve been informed here that I can use a library like jQuery to make the API call directly, meaning the JSON data returned from the 3rd party API could bypass my server and go directly to the user’s browser.
With a 3rd party API requiring authorisation I’d need to get the auth token from my django back end to the front end so that it could be used in the Ajax request.
I appreciate that it would be an option to use the implicit or PKCE flows in the browser.
However, as an alternative I’d had the idea that I could use the server side OAuth flow to store the access token and refresh token in the back end and then send the auth access token from django back end to the user’s browser to be securely stored and used from there.
The benefit of this, as I see it, is that if the user’s access token expired you could make a call to the back end to use the refresh token in order to provide a new auth token, thus requiring the user to log in fewer times.
I also don’t see how this can be any less safe than the implicit flow, although me not seeing it doesn’t mean it doesn’t exist!
I know I’d have to use SSL to avoid any malicious actor snooping on the token. I’d also need to account for CSRF and XSS vulnerabilities, but thankfully django comes with solutions to both.
Would this method be a bad idea and considered bad practice?
My rationale for considering this is that it would reduce greatly the overhead of my server if I could cut out the intermediate step of rendering the JSON response in the page template before it’s sent to the user’s browser.
I think what I’m describing is addressed here, albeit with different frameworks.
If anyone else reads this and thinks of a problem with what I’m proposing please let me know.
I am a little confused right now. I am using googleapiclient to call the Docs API, google_auth_oauthlib.flow to handle the authorization flow, and google.oauth2.credentials only for, from what I can tell, the Credentials class.
I need to authorize users for my app for non-short periods of time (days-months). I need to know if I need to manually refresh their tokens should they expire.
The example Flask implementation here does not seem to manually need to refresh tokens if/when they expire. It says
# Save credentials back to session in case access token was refreshed.
in the test_api_request view as if credentials is automatically updated with a new token when the API is called by the object returned by build. Is this the case? A lot of the docs regarding these libraries have limited/vague information about how the token refresh works.
If not, how do I know when the token has expired? Does the Credentials instance have an expiry field? How do I get a new token using the refresh token?
Thanks
Looking at the source code from the three libraries involved, it seems like they manage refreshing the token for you and that's why they don't give you an expires_in field from the access token.
It's actually the drive.files().list().execute() expression that updates the access token because the refreshing is done per request (in case it's necessary), but it's the build method that makes it possible to do so. When it's called the following occurs:
build calls build_from_document (here)
build_from_document creates an instance of AuthorizedHttp (here)
The AuthorizedHttp instance manages refreshing the token when it's necessary, by calling the refresh method on Credentials (here)
You can see that the refresh method works with an expiry field (here)
And it parses the expires_in field given by the API. (here)
The three libraries involved in this process are google-auth-library-python, google-api-python-client and google-auth-library-python-httplib2.
Pretty convoluted process. If you want to read a simpler implementation of an OAuth client, you could try reading the Spotipy client implementation of the Authorization Code flow. It has nothing to do with the google libraries, but it might give you an idea of how it manages the token.
The gist of it is: You make a request to the token endpoint which gives you back an expires_in field along with the access_token, based on this field, you need to calculate the time in the future when this token will expire. When you make a request to the resource server, you need to check if the token is expired, if it is, you make a new request sending the refresh_token to the token endpoint.
I've omitted some steps, but if you want to know more, you can read about it here and in the RFC.
I'm building an app that has a frontend for both iOS and Android, and a Backend composed of a Flask API and a MySQL database.
Right now, our authentication uses JWT. Except that I'm not sure I totally understand how it is supposed to work.
I don't know where to find the specifications for JWT, so when I say JWT I simply mean a JSON payload encrypted using the PyJWT library.
Currently, the expiration of the tokens happens 6 months from their creation.
I feel like this is a rather insecure setup.
From all the examples I've seen, JWTs have a very short lifetime, and then there's some sort of "refresh token" that renews it.
But that's all I know. I don't understand it well enough to code it in Python.
Could someone please help explain what this refresh token is, what exactly it does, how it is created, etc.?
UPDATE:
As for the specifications for JWT, I read this: https://www.rfc-editor.org/rfc/rfc7519
It doesn't mention any refresh tokens.
So now my question is, is what I'm doing secure enough?
Is it worth it to have a logout API endpoint that sends the token and adds it to a blacklist, so no one can steal it?
Six months for a JWT is way too high and unsecure. You might want to keep it a few hours or a day max. Along with that, have a long lived refresh token (RT), which you can use to keep getting new JWT. The function of the refresh token is to maintain a long lived session (so that the user can be logged in for a long period of time), to detect token theft (if you keep changing the RT on each use) - since you mentioned stealing, and to enable you to use short lived access tokens (since those are exposed over the wire most frequently). And yes, blacklisting JWTs can be a good idea, but if you are keeping them short lived, then why do that?
This topic is quite vast and complex. You can refer to my blog post about this - it provides information about all session flows, their security and also has an end-to-end implemented library.
I am developing an app that creates a public Spotify playlist for a user who has given proper authorization to do so.
I am using Flask and Python requests library to accomplish this, but after I've sent a few consecutive POST requests to get an access token from Spotify (using authorization code obtained from previous logic), it begins to fail. I am referring to Step 4 of Authorization Code Flow from this link: https://developer.spotify.com/web-api/authorization-guide/#authorization_code_flow
I know the authorization code is valid, because it doesn't fail for the first few times I run the request (maybe 5-10 times).
When I print the response from the POST I get the following:
{'error_description': 'Authorization code expired', 'error': 'invalid_grant'}
I assume I am not using the authorization code fast enough to get an access token (after repeatedly failing on code logic before the access token POST request, I guess?) but how am I supposed to reset and refresh the authorization code so I can keep making requests repeatedly? Any info on how long I am disabled and generally good programming practice to avoid this scenario?
When you use the authorization code to get your access token, you will also get a refresh token back in the same message. Use that refresh token to request new access tokens, when the access tokens expire.
How to use the refresh token is written on the same page you linked to, just a bit further down: https://developer.spotify.com/web-api/authorization-guide/#request-access-token-from-refresh-token
I agree that this is not the easiest to understand, but there are good reasons for all these things. It is also a standard called OAuth2, which many websites use to let users authorize apps to access their data, so it is useful in a lot of places.
In this specific case: "why do I need a refresh token to get an access token, I already have an authorization code to get an access token?", it is because the authorization code has leaked to the outside because it was returned to you via the user's browser.
An authorization code is obtained when the user grants permission for the third-party application (the Client). As per OAuth's 2.0 specification the authorization code must be used once and it's recommended that it have a maximum lifetime of 10 minutes to mitigate security flaws.
Read more about authorization code here:
https://www.rfc-editor.org/rfc/rfc6749#section-4.1.2
On the other hand, instead of boring the user to go through all the OAuth 2.0 dance again (to authenticate and to grant permissions), the server side of Client application can use Refresh Tokens to ask for a new token when it's expired.
More about refresh tokens can be found at section 10.4 of OAuth 2.0 spec.
https://www.rfc-editor.org/rfc/rfc6749#section-10.4
I'm making a Django app with Fandjango and I'm trying to unit test it with Django's test framework. The only thing is, in order to test effectively I need a "signed_request" parameter that Facebook sends with every request. Right now I'm logging the requests my server gets from Facebook and copying + pasting the signed_request token I get, but that only works for a few hours at a time.
Is there a simple way to handle this without doing a mock of the whole Facebook API?
Thanks!
You can use Test Users:
http://developers.facebook.com/docs/test_users/
I think the access token never expires, or at less until you delete the Test User.
Well, I understand it's also possible to authenticate fully server side, using just OAuth without Javascript SDK. In that case you should be able to aquire a valid token yourself. There are, I think some libraries that can be used for that like:
http://pypi.python.org/pypi/django-social-auth/
However please note, I've never done this myself so it's more of a suggestion, than a definite answer.
EDIT
It seems like social-auth has some testing functionality that is capable of automatically signing in to a facebook account. You could probably copy the code from there.