There's a lot out there on how to issue JWT tokens to clients from Django, but I'm looking for a way to store a JWT token that is issued to the Django app for authentication against an external API.
The setup:
Django requests and receives token from external API. It is good for 24 hours.
Every time a client a makes a request, the app must make an authenticated call to the external API. Ideally, if 3 clients make 2 requests each, we should only need to request a single JWT.
24 hours later, a fourth client makes a request. Django sees that the token is invalid and requests a new one.
The problems here:
Requests from multiple clients should not each require their own token.
The token must be able to be changed (this rules out sticking it in the settings)
The token must be stored securely.
Ideas so far:
Stick in the database with a field listing the expiry time. This seems questionable from a security standpoint.
Implement some kind of in memory storage like this https://github.com/waveaccounting/dj-inmemorystorage . This seems like overkill.
Any suggestions as to a better way to do this?
The django cache was the way to go. See the above link for an example.
Related
I have a resource server (built with Flask, but not sure if that matters right now) that has a RESTful API. The API is secured with OAuth2 access tokens and scopes.
Currently the access tokens are opaque (not JWT) and the resource server needs to call the /oauth/token/info endpoint on the auth server to check if the access token is valid and get the list of scopes associated with the access token, and then validate the scopes granted against the ones required. We have some custom code for this.
We now want to start to use JWT access tokens so that we can avoid this call to the auth server, but we can't roll them out to all OAuth clients just yet, only some. So the resource server will be getting a mix of opaque access tokens and JWT access tokens. The JWT will be signed with a RS256 private/public key, and the public key will be available from the auth server at a /oauth/discovery/keys endpoint that the resource servers could hit on startup once and cache so that it doesn't need to hit it on every request, unless the public key changes and doesn't match the kid in the JWT.
While doing this, I was hoping we could get rid of some of the custom code we've written and use some tried and tested library for us, hence AuthLib.
However, I can't seem to find any good examples of how to configure a resource server to handle either of these cases individually, let alone both at the same time. The examples I see seem to assume the resource server has access to the access token database.
I'm assuming I will need to write my own BearerTokenValidator that handles this, but I was hoping there would be examples somewhere on how to go about that. Ideally with the ability to cache the public key for the JWT and only refresh when the JWT kid claim changes.
I was sort of hoping that a TokenInfoBearerTokenValidator and a JWTBearerTokenValidator existed that I could use that did most of the work for me. Maybe there are and I'm just missing it?
AuthLib 1.0 has been released with additional support fro JWTBearerTokens that makes this easier to accomplish now.
I have a Django project that will ultimately consist of three apps. Two of which will be "normal" Django apps, the third is a djangorestframework app. I also plan on creating a desktop client for the project at some point.
I want the rest app to be the only entity communicating with the database. Hence I use requests to communicate with the rest endpoints from the views of the "normal" Django apps and I will do the same for the desktop client. I want all apps to be accessible only for authenticated users, so I'm using Django's authentication backend.
My question is how to pass on the authenticated user/session from the pure Django apps to the rest endpoints when using requests in the views.
I managed to authenticate on the rest API using request's HTTPBasicAuth, but that requires me to have the user's password at hand in plain text. Sure, I could create a technical user to do these requests. But that would also mean that each and every request would need to go through authentication first and that doesn't feel like the best approach.
I have tried to extract the session cookie from the request object that is provided to the views and pass it on through requests.get, but did not manage to put it into the requests.get call the right way.
As of now, using requests and the established sessions looks like my best bet, especially since that will be the way the desktop client will do things, too. So I'm currently looking for the right way to provide requests.get with the session cookie, but I'm certainly open for better solutions.
You should use tokens.
Basically any kind of authentication out of your django project should be managed with secure tokens.
And yes, authentication check should happen everytime you send a request. To make it faster, you can store tokens in memory. (You can use redis or maybe even load your db on memory or ... ) but this is the right and common way to it. Even django does this check everytime using it's builtin functions.
DRF docs recommended some few packages to manage these tokens:
DRF: Third party packages
I used knox for many projects and it's pretty good.
Basically to authenticate your users over all of your projects or microservices, you have to take the token from user, set it as header or ... for your request to the main database or authentication project.
Most of the apps use token in headers which you can simply add to all of your requests calls:
Requests docs: Custom Headers
Can someone example to me how CSRF works in the cluster setup?
I have a kubernetes cluster hosting a django website, and I'm having some occasional issues with 403 errors. I have multiple instances of the site load balanced in kubernetes.
How does CSRF work when a POST is sent from 1 instance and handled by another?
Does CSRF site work if the docker images are updated during the time the form is being filled out?
Thanks!
Can someone example to me how CSRF works in the cluster setup?
Exactly the same way it usually ought not to (CSRF is Cross Site Request Forgery, i.e. the attack). To protect against it, you hand out secret tokens to your clients which they must include with subsequent requests. Your backend must validate that the tokens are valid, applicable and were, in fact, issued by a trusted source. There's a few ways to do that bit:
You can use MACs for that (in which case you have something pretty close to JSON WebTokens).
You can save your tokens to some trusted store and query that store on subsequent requests.
That is pretty much all there is to it.
Since your CSRF protection emerges from the combination of choices you made above, how to make it work in a distributed setup also depends on the specific implementation of the CSRF protection scheme.
Going by the Django docs, the default way to do it uses a 'secret' which is reset every time a user logs in. That means if hitting a different server for two subsequent requests triggers a new log in, all old CSRF tokens are effectively invalidated. So based on that:
You need to adapt your Django project to make sure different instances can resume working with the same session, and a re-login is not triggered
All your Django instances need to be able to access the same per log-in secret, so that any one of them can validate a CSRF token issued by any other.
You should disable CSRF for every instance, and manage the CSRF security from the API Gateway
I apologize in advance for asking a rather cryptic question. However, I did not understand it despite going through a lot of material. It would be great if you could shed some light on this.
What is the purpose of a request_loader in flask-login? How does it interact with the user_loader decorator?
If I am using a token based authentication system (I am planning on sending the token to my angularJS front end, storing the token there and sending that token in the authorization-token header), will I need a request_loader or will a user_loader (where I check the auth header and see if the user exists) suffice?
From the Flask-Login documentation:
Sometimes you want to login users without using cookies, such as using
header values or an api key passed as a query argument. In these cases,
you should use the request_loader callback. This callback should
behave the same as your user_loader callback, except that it accepts
the Flask request instead of a user_id.
So, to answer your question, they both serve the same function for Flask-Login. They are both used to load the user. request_loader, however, is appropriate for custom logins.
Here's a great tutorial I found that utilizes request_loader to take advantage of token based authentication (The post is not my own, I'm merely sharing the link): http://gouthamanbalaraman.com/blog/minimal-flask-login-example.html
I need to make this clear.
This is the reason why you shoud use request_loader with flask_login.
There will be a lot of #login_required from flask_login used in your api to guard the request access.
You need to make a request to pass the check of auth.
And there will be a lot of current_user imported from flask_login,
Your app need to use them to let the request act as the identity of the current_user.
There are two ways to achieve the above with flask_login.
Using user_loader makes the request to be OK for #login_required.
It is often used for UI logins from browser.
It will store session cookies to the browser and use them to auth later.
So you need to login only once and the session will keep for a time.
Using request_loader will also be OK with #login_required.
But it is often used with api_key or basic auth.
For example used by other apps to interact with your flask app.
There will be no session cookies,
so you need to provide the auth info every time you send request.
With both user_loader and request_loader,
now you got 2 ways of auth for the same api,
protected by #login_required,
and with current_user usable,
which is really smart.
To verify users with Flask-Login's session_id for frontend requests through Angular, you must set the withCredentials configuration flag to true.
That is, if you are using Angular's $http.post(url,data [,config]) or $http.get(url [,config]), make sure the config object contains the property withCredentials set to true. This will instruct the browser to use its cookies in the same way it would for a full-on page visit.
For example,
$http.post('/api/login',{username:'myusername',password:'mypassword'},{withCredentials:true})
will post the data {username:'myusername',password:'mypassword'} to your site/app's /api/login route and, if you're using Flask-Login and are logged in, Flask will know.
You can set this behavior for all $http service requests by setting
$httpProvider.defaults.withCredentials=true
somewhere in your app. Currently, I have that line of code in my app.config block, which seems appropriate to me:
var myApp = angular.module('myApp');
myApp.config(function ($httpProvider) {
$httpProvider.defaults.withCredentials = true;
});
(Since this post is about Flask, folks may want to send form data through Angular in such a way that it can be found in request.form, which has a similar solution, fyi.)
I'm going to build an API in Flask for a (to be created) app which will be built using PhoneGap. In the API many calls will need authentication.
To get into the topic I was reading this tutorial on creating authentication for a Flask-built API. In this tutorial they first show how a user can use basic password authentication for every call, after which token based authentication is introduced.
As far as I understand, the client who calls the API should simply get a token and authenticate every subsequent call with that. In the meantime, the client should keep track of time and either get a new token every 9 minutes (before the old token expires) or simply keep on calling with the token until the client gets an Unauhorized Access message. Am I understanding this correctly?
Moving on, I wonder how it works with Apps on which you login on your phone and then are always logged in whenever you open the app (like for example the Facebook app). This is obviously more convenient to the user than always needing to provide the username/password and I would like to implement something like that as well. I wonder though; how is a permanent logged in feature like this implemented on the server side? Is it done by providing the password and username for every call, or using a never expiring token, or yet a different way?
All tips are welcome!
I've done what you want to do with:
Flask-security https://pythonhosted.org/Flask-Security/:
To manage users and permissions.
Flask-oauth-lib https://flask-oauthlib.readthedocs.org/en/latest/:
Provide oauth functionnality.
So, you have to take a look at Oauth flow, implements a user backend (like Flask-security) and implements an oauth server (with flask oauth lib for example) and bind it to your user backend.
After that, it's oauth standard flow. You just have to give the right token on each api calls and TADA !
With this way you can also, if you want, give access to your api to third-party app thanks to oAuth :)