Are there basic authentication examples with Django and Tastypie?. I'm a little bit confused about how the authentication in Django works, specially with Tastypie.I wanna know how the authentication works with api keys and how to authenticate a user with the built-in User model which Django has. Any suggestion or code are really appreciated.
Thanks.
Just to answer your questions regarding authentication:
How the authentication in Django works?
Django authentication required SessionMiddleware to work. Once a session has been loaded, the Django authentication backend reads a special cookie _auth_user (IIRC) which contains currently logged in user's ID. If you have access to the django shell, you can manipulate it and make yourself logged in as any user! Once the backend notices there is a _auth_user key, it then adds a lazy User object to the request (so it delays the User.objects.get(...) until it is really needed). If there is no such key in the session dict, the user is claimed to be anonymous and an instance of AnonymousUser is added to the request object instead.
How does the authentication work in Tastypie?
Before your resource view is executed, a Resource.is_authenticated(request) method is called, which in turn calls the is_authenticated(request) method of the authentication backend of your the Resource of your choice. If the method returns False, the authentication is claimed to be failed and returns with Unauthorized error. If the method returns a HttpResponse, the response is returned instead. If the method returns True, the request is claimed to have been authenticated.
How does User model authentication work in Tastypie?
The User model authentication can be performed using SessionAuthentication backend provided by the Tastypie itself. What it does is creating a session for the current request so that the authentication middleware can then automatically insert relevant user model to the request. Notice that for this method to work, your API client has to support storing cookies and resending them in future requests.
You might find this useful. It allows you to authenticate the user based on the Django session cookie.
https://github.com/amezcua/TastyPie-DjangoCookie-Auth/blob/master/DjangoCookieAuth.py
I am using this in my application and it works!
Related
I see there is a django.contrib.auth.middleware.AuthenticationMiddleware but reading the documentation I don't think it determines when auth is actually auth is run. Does auth happen before or after middleware? Can that ordering be changed?
The authentication process and AuthenticationMiddleware unfortunately have little to do with each other. Authentication as a process is the practice of verifying credentials. In order to not have to do this for each request, one can create a "login session", which associates the browser with an authentication process that happened in the past. For the end user this is transparent as a "login process". This results in a "logged in user" and AuthenticationMiddleware puts this logged in user on the request object as request.user or if no login process has occurred, then the AnonymousUser.
In Django, authentication is done by whatever calls django.contrib.auth.authenticate and the login process by django.contrib.auth.login. In a vanilla installation this is done by django.contrib.auth.views.LoginView, which isn't hooked up to any url, except the admin login.
Authentication backends are not middleware. They are sources of truth for authentication data that is queried by the authenticate function. It's list is executed in order defined by the settings and the first one that returns True wins.
I think in the past the intention was for the authentication middleware to do more, but as it stands, a better name would be CurrentUserMiddleware.
No fixed place
You seem to think there is one spot where authentication backends are called on each request. This isn't the case, but depending on the authentication method, it can be. For example, Django Rest Framework's token authentication sends a token header on each request, which is authenticated each time in the view.
In theory, one can create a middleware that authenticates and sets the authenticated user each time, especially with token based auth, as they send credentials with each request. It's just unpractical, because it becomes harder and less explicit to exclude views from the process.
I'm creating a Login/Register API with Django Rest Framework which is consumed by my frontend, using JWT to authenticate and there are some basic things I can't seem to understand and maybe someone can help me out.
I created an endpoint to register a user (a POST to /users/). At first I was getting a "Authentication credentials were not provided." if I tried sending a request using Postman (on Django API GUI it would work normally I guess because they already send the correct authentication). However, when I think about it, it comes to me that he doesn't have the credentials yet since he's not registered and logged in, so its JWT wasn't created, so I added permission_classes = (AllowAny, ) to my APIView. But then it allows anyone to use the API, therefore anyone would be able to send a PATCH request to update some info without sending the JWT in the request. Anyone have any idea on how to handle that?
I think somehow I'm lacking some kind of concept about authentication. Maybe I need one exclusively for communicating my backend and frontend that will be used to register a user and the users JWT will be used to perform the other actions?
If needed, I can provide other informations about my architecture or code.
First As per your description,
I created an endpoint to register a user (a POST to /users/). At first I was getting a "Authentication credentials were not provided." if I tried sending a request using Postman (on Django API GUI it would work normally I guess because they already send the correct authentication).
You have to understand that since the api is a user registraion api, the permission class should always be set as permission_class = (AllowAny,), but you set permission_class = (IsAuthenticated,) in your view, so django expecting a proper authentication credential(a JWT token as you are using JWT) to make sure the requested user is authenticated. Thats why you are getting a "Authentication credentials were not provided." exception in your POST /users/ api.
Second, as you said later,
However, when I think about it, it comes to me that he doesn't have the credentials yet since he's not registered and logged in, so its JWT wasn't created, so I added permission_classes = (AllowAny, ) to my APIView
its obvious when a user registering himself/herself, then he/she will not have any credentials(JWT token).
then you said,
But then it allows anyone to use the API, therefore anyone would be able to send a PATCH request to update some info without sending the JWT in the request.
From these lines it seems that you are using single api view to Create(POST) and partial update(PATCH) of user. What you have to do is to make separate api views. That is one api view for Create/Register(POST) user and set permission_classes = (AllowAny, ) and another api view to Update(PATCH) user and set permission_class = (IsAuthenticated,). I think this will solve your problem.
EDITION: Now for better understanding how permission works in django rest framework, lets check this the way permission works in django rest framework.
I want to use firebase authentication for my django webapp. To achieve this, I think would I need to write a custom auth backend - is that right? I don't see any libraries that already do this - django-allauth looks like it comes pretty close as an alternative but I am interested in the phone number verification provided by firebase.
I'm also confused about what happens to the User model and functions like request.user or user.is_authenticated. Right now I use the authenticate and login functions - how does django know that a user is logged in via firebase? Would I still be creating a User model for every user?
Thanks
You can use Firebase Auth with any framework. You don't necessarily need to use custom auth. Typically, you would sign in the user on the client, get the ID token by calling firebase.auth().currentUser.getIdToken() and then pass the ID token to your server, verify it and parse its payload identifying the user ID and its other claims by using the Firebase Admin SDKs and then you can issue a session cookie identifying the user associated with that ID token.
On signout, you would clear that session cookie.
If you also need to persist that user on the backend after setting the session cookie, you can also use the Firebase Admin SDK to lookup a user identified by the user ID or just use the token claims to populate the user without any network call. You can populate that in the user model of associated framework if needed.
For more on session management, you can refer to this django documentation: https://docs.djangoproject.com/en/3.0/topics/http/sessions/
I'm using Django REST framework JWT library for authentication in my django application. And I thought the whole idea of using JSON Web Token Authentication was NOT having a database trip in every request.
But it still retrieves user's data (which is stored in the token's PAYLOAD) from database per request.
What am I doing wrong?
The webtoken mechanism and the server authentication internals are rather orthogonal.
The web token just allows the holder to say who they are. It is similar to holding a user's username and password, except the token can be revoked without the user having to learn a new password. This authentication technique has nothing to do with whether the server will do a database access.
If you wish to eliminate a DB access during authentication on the server, you can use some sort of authentication caching mechanism like django-cached_authentication_middleware.
I have an AngularJS Single Page Application that uses a Django backend API based on the Django Rest Framework. The API is protected via django-rest-framework-jwt. I would like to use django-allauth for account management and authentication on the server side.
I am just missing one single piece in the flow: How does my Oauth-Token from the client get transferred into a JWT-token? Basically, I would like to do as described here http://blog.wizer.fr/2013/11/angularjs-facebook-with-a-django-rest-api/ based on python-social-auth.
So my question is, how do I implement the ObtainAuthToken class from the link with django-allauth?
There are usually two login flows with social login: client-side ("Javascript SDK") and server-side. If your server needs to be authorised, it's usually a lot easier to go through the server-side flow. And that's also what all-auth does I think (and you didn't mention you use a frontend library like the blogpost you mentioned does).
Now the challenge is to provide the token from the server to the frontend. You would probably load the token in the HTML of the initialisation of the SPA, and then from Angular save the token client side (cookie, localStorage, etc.) so the session isn't lost on a refresh.
If you don't want the user to leave your app, you can open your /accounts/login/ or /accounts/signup/ url in a new window. In that new window they authorise your app, and your server receives the token upon return. There, you will have to generate a JWT token manually, and render that into the template so that javascript can access it. With js in that popup window, you can then communicate with your app that opened the popup and pass it the token – see this SO answer for an example – so it can save it.
Django-allauth provides signals that let you hook into the social login process. In your case, I would recommend subscribing to the allauth.socialaccount.signals.pre_social_login signal. The code will look something like this:
from allauth.socialaccount.signals import pre_social_login
#receiver(pre_social_login)
def create_jwt_token(sender, request, sociallogin, **kwargs):
# dig into the sociallogin object to find the new access token.
We used hello.js for O-Auth at the company I worked at.
You provide a shim on the Python end and get the refresh token and whatever other data needed once the user connects their social account.
We redirect them via Django to the page they attempted to access from their OAuth provider's page.
Each user still has their own email account which is needed for the JWT, but you could assume that whatever email is in the scope of their social account is their email then use django's functionality to create new users: User.objects.create(email=emailStringFromOauthData) etc.