Which is the best way to configure auth between two apis using Django rest framework? - django

I'm using DRF for developing an API and I want to consume this API with another API and with an app. For the second API, how can I develop an API authentication? I think that using JWT is not good because I'll need to save the token on the consumer Api and keep refreshing it.

If your requirement is to avoid refresh of JWT token you can configure that at the settings.py
JWT_AUTH = {
'JWT_ALLOW_REFRESH': True,
'JWT_VERIFY_EXPIRATION': False}
You may use the package djangorestframework-jwt==1.11.0
If you don't want to use JWT at all you can still use the basic authentication rather than token based authentication.
Your authorization header would then have a format as follows:
Basic cG9pc29uaXZAYXJraGFtLmNvbTpwYXNzd29yZA==
The basic authentication will not change until you change the password.
But since you were asking which is best, I would recommend JWT with expiry for the right security reasons. But if you take out expiry from your equation JWT and Basic Auth just as same except that JWT can still be expired and you can demand reauthorization without the consumer changing the password.
Please note you can use basic and JWT authentication hand in hand.
For your second API's internal consumption you can use basic auth even if JWT is implemented.

Related

How protect from CSRF Login and Register endpoints (views) of an API created with DRF which use JWT as authentication?

I have been searching and reading other questions and blogs, but I didn't find anything concrete about my doubt.
A little of context:
I am developing a SPA which works with a REST API in Django by means of Django Rest Framework (DRF) and the authentication is made it through Bearer token: JWT (package 'Simple JWT'). So, I was reading whether it needs protection against CSRF:
• Do I need CSRF token if I'm using Bearer JWT?
• Should I use CSRF protection on Rest API endpoints?
• The Web API Authentication guide, Bearer tokens
Basically if the browser does not make an automatically authentication (with sessions or some kind of cookie), the odds of a CSRF vulnerability are slim. This approach is achieved with the Bearer Tokens using the JWT inside the 'Authorization' header.
Updated: In this developing stage it is setted Django-CORS, but in production it will be configured a proxy through Nginx. Avoiding CORS attacks.
The problem:
There are some public endpoints, that don't need authentication, so I used this permission in DRF settings
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticatedOrReadOnly'],
This way, unauthorized users only can make safe requests -methods: GET, HEAD and OPTIONS-. The users, with a JWT, can perform any kind of request.
Login and register views works through POST requests due to modify the state of the application. The issue is the above permission avoids that the 'anonymous' (to call it in somehow) user from being able to register or login. The question is, how do I protect them?
I have thought in maybe change the permission to these views to 'AllowAny'. But I don't know if this returns the concern about CSRF, because there is no Bearer token here, or perhaps other security vulnerabilities that I can't even imagine.
Another possibility is to only use the CSRF token in these views.
Or is there any better approach to protect these two endpoints?
I hope someone will be able to help me!
You can use CSRF tokens in your login and registration forms, and this will sufficiently protect you from CSRF attacks against these endpoints. You would then have to obviously allow for anonymous access to these endpoints. It's usual that login and registration endpoints are not behind a firewall and are accessible to anonymous users.

Validating jwt token in REST api

I have a doubt regarding the jwt token validation done by the REST api and was not able to find a simple yes/no answer. Assume that everything is being transferred over HTTPS.
I have the following setup
React app
REST API
AWS Cognito that handles the user registration/login
When a user wants to login, then the React app would call the AWS Cognito api and validate the credentials. If valid, Cognito will send back a jwt token (that will contain the necessary meta data) that can be passed to the REST API. Now I see two options
the backend verifies that the jwt token was not altered using the rfc spec. If valid, the api extracts the necessary meta data and continues to process the request
The backend verifies the validity of the jwt token, but also calls the Cognito service to verify the metadata in the token.
I think that since everything is handled over HTTPS and the fact that its hard create a valid token then the first point is enough. There is no need to have an extra call over the wire. Am I wrong ?
Found the following question from softwareengineering.stackexchange.com which pretty much answers my question. Link
The local validation of the JWT token is enough when the token was created with asymmetric encryption.

Secure authentication between ReactJS and Django

Been reading and watching quite a bit, and asking a lot of questions regarding ReactJS and Django.
This particularly helped me to understand the the flow of data from Django REST Framework to ReactJS and from ReactJS to Django REST Framework.
Django Forms and Authentication with Front-end Framework (AngularJS/ReactJS)
However, the one thing I am trying to understand is authentication to the Django REST Framework. I understand from the documentation that it has built in authentication. Since this is sensitive data, I would obviously want it protected people retrieving it just by going to http://www.my_site.com/info/api.
I would need to setup ReactJS to be the only thing that can request data from the API whether that is through a key or username/password credentials. I am just curious how this is handled? Obviously I don't want that hard coded in ReactJS because it will compile with the rest of ReactJS.
Here's how I'd approach it: I'd use a JSON Web Token (JWT) for authentication and authorization.
You'd use your back-end to protect ALL API requests from invalid JWT's except for routes where a user won't have a token (ie, registration/log-in pages).
Here's how the flow of the application will go:
A new user registers to your app with standard credentials such as email and password.
Your back-end will create a new user, sign a new JWT token (usually with the user's ID). You'll probably use a third-party library to sign/verify tokens (I don't have experience in the Django community but I am sure a quick Google search will give you answers). Your back-end will send back this token. This is the only time the back-end will receive email, passwords or any other sensitive information on registration.
From this point on React will only use this token for authorization. React will save this token somewhere (ie, localStorage) and send this token along with the other parts of a request to the API routes you created with your back-end. You'll send this token in the authorization headers in the request.
Your back-end will validate this token using a third-party library. If it's invalid the request stops and an unauthorized error is returned. If it's valid the request continues.
This achieves the following:
Your API routes are protected against unauthenticated users
Each request to your API is verified for authorized users which protects anyone from requesting any part of your API.
You can further solidify this by only allowing requests for users to modify their own data. For example, protect Suzy's profile from being modified by people other than herself by only allowing her token with her ID to modify her account/data.
Important Note- Your backend will never save these tokens in storage. It will verify the token on each request. Read more about JSON Web Tokens (JWT) and how it works.
Django Rest Framework has built-in token authentication and a third party package for JWT Token Auth.
If you the standard token auth would work for you, then it could be pretty simple with drf-redux-auth. If you need JWT for some reason, as suggested by Keith above, you could easily fork the above...

Generate an OAuth2 token in a view

Let's say I have an AngularJS application that consumes the REST API of a Django application.
The Django application has got a built-in OAuth2 provider that can be called to retrieve an access token and use the protected endpoints of the API. This provider is using django-oauth-toolkit.
Let's assume there is a registered client with "password" grant type, so that the end users only need to provide their credentials in the front-end in order to get an access token from the back-end.
At some point we want to add some support for social networks login and we decide to use python-social-auth (PSA) to that end. Here is the workflow I want to achieve:
The user logs in on Facebook from the front-end (via the Facebook SDK) and we get an access token back from the OAuth2 provider of Facebook.
We send the Facebook token to an endpoint of our REST API. This endpoint uses the Facebook token and django-social-auth to authenticate the user in our Django application (basically matching a Facebook account to a standard account within the app).
If the authentication succeeds, the API endpoint requests an access token from the OAuth2 provider for this newly authenticated user.
The Django access token is sent back to the front-end and can be used to access the REST API in exactly the same way that a regular user (i.e. logged in with his credentials) would do.
Now my problem is: how do I achieve step 3? I first thought I would register a separate OAuth2 client with Client Credentials Grant but then the generated token is not user-specific so it does not make sense. Another option is to use the TokenAuthentication from DRF but that would add too much complexity to my project. I already have an OAuth server and I don't want to set up a second token provider to circumvent my problem, unless this is the only solution.
I think my understanding of PSA and django-oauth-toolkit is not deep enough to find the best way of reaching my goal, but there must be a way. Help!
I managed to get something working using urllib2. I can't speak towards whether or not this is good practice, but I can successfully generate an OAuth2 token within a view.
Normally when I'd generate an access token with cURL, it'd look like this:
curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://localhost:8000/o/token/
So we're tasked with making urllib2 accomplish this. After playing around for some bit, it is fairly straightforward.
import urllib, urlib2, base64, json
# Housekeeping
token_url = 'http://localhost:8000/auth/token/'
data = urllib.urlencode({'grant_type':'password', 'username':<username>, 'password':<password>})
authentication = base64.b64encode('%s:%s' % (<client_id>, <client_secret>))
# Down to Business
request = urllib2.Request(token_url, data)
request.add_header("Authorization", "Basic %s" % authentication)
access_credentials = urllib2.urlopen(request)
json_credentials = json.load(access_credentials)
I reiterate, I do not know if this is in bad practice and I have not looked into whether or not this causes any issues with Django. AFAIK this will do this trick (as it did for me).

Do you logout a user who login via OAuth2 by expiring their Access Token?

I am doing some work in Django, using the Django Rest Framework.
Users login via Oauth2 to facilitate integration with mobile applications.
I am using the Oauth2 authentication library that is packaged together with the Django Rest Framework.
To logout a user, I am expiring their access tokens, is this the correct way of doing things?
It's not correct. Normally, the access token expires when it reaches its expiration time.
Or in some these cases:
1. User revoke this access token.
2. Users change their password.
3. When refresh token is revoked, its issued access tokens will be deleted.
And here is a reference about log out.
I think what you mean is that you are creating a oauth2 provider?
If I am correct I would recommend switching to using token authentication. To create a oauth2 provider there are many restrictions and rules to follow and I assume when you create a oauth2 provider that it will be a public system that can be used by many people (that can and will misuse your service if it's has leaks)