4

I started a Django app and i created the whole authentication layer using Django-Allauth, it already has quite some features such as email confirmation, password reset and two factor authentication. Now i realized that, since my app will be heavily interactive and with a lot of real time features, i'm going to need a Vue SPA to use with Django, so i'm thinking of creating the Vue SPA on the same server and domain and have Django as a Rest API.

Here is my problem: since i already made the whole authentication part using Django templates and Django urls, if i separate the rest of the frontend from the backend, will i have to rewrite everything? Is it possible to have a Vue app and a Django backend app separated on the same domain where authentication is handled by Django templates and all the rest is a Vue app with vue routes and all the other interactions are handled by Django Rest Framework endpoints?

So maybe something like this:

urlpatterns = [
    path('accounts/signup/', SignUpView.as_view(), name='signup'), #Django template
    path('accounts/login/', LoginView.as_view(), name='login'), #Django template
    ...
]

And these are the only Django-handled urls where the page is rendered by Django views. Once the user is logged in, they will be redirected to the VueJS app.

Jack022
  • 867
  • 6
  • 30
  • 91
  • 1
    It's not impossible, but especially if you want your SPA to dynamically change the browser's address (push history API), then you'll need a lot of very detailed URL configs to make the server serve the right files. At least you should reserve certain prefixes for certain parts, like `/api/` for all API calls and `/app/` for your SPA. – deceze Mar 18 '21 at 09:37
  • What is the HTTP server do you use? If it's nginx, you could check it out https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/ – linhx Mar 18 '21 at 09:38
  • 1
    I'm using Ningx, yes! I was thinking of doing something like `/account/` where everything is rendered by Django views, then `/app/` which is a SPA and finally to serve JSON data from Django `/api/`, all on the same server of course. I feel like this would be much easier and safer than building from zero again my own authentication using Vue and DRF, and i'm much more experienced with Django than Javascript – Jack022 Mar 18 '21 at 09:49
  • By default, you can't use your Auth, Routes that you built with Django in vue project, Especially, if you wan't, you can render each view in your Django project as Vue component which will be interactive with the user (but it's independent .. I mean it cant interact with other pages since the page will reload in each url change) – Kareem Dabbeet Mar 20 '21 at 11:51
  • Yes, i thought about that too, but i'm afraid it will make the code more messy and confusing since i'll use Vue heavily; using it as a separated spa or by loading webpack in Django just makes much more sense – Jack022 Mar 20 '21 at 11:56
  • I think it is doable. but i will need access to you code to be able to tell for sure – Ouss Mar 22 '21 at 17:11

1 Answers1

4

My personal opinion, it's not worth it to keep a bunch of server side pages just for sign-up, login, ... Managing both server-side pages and front-end pages in long run is a headache. But if you like that way, here are my suggestions.

For authentication, use Django auth. No matter if it's a server side HTML page or it's an API end-point. Django auth is simple and secure. Don't roll your own auth, don't store tokens in localstorage or so.

Fully separate these 3:

  • Front-end URLs (i.e. routes stored in Vue)
  • Back-end page URLs (i.e. HTML pages severd by Django)
  • Back-end API end-points URLs (i.e. the ones user never see, only Vue uses them under the hood)

They can be on separated domains but it can be just by a path prefix as well. As you yourself suggested in a comment.

Now when user visits some page in BE, it will use server side rendering and every user click is a browser refresh. Until you hit a FE URLs, then your front proxy should redirect user to FE or you'll serve JS files directly from Django. After that every user click is handled inside Vue without a refresh. If user hits a URL prefix that's for BE, then FE needs to do something like document.location = "/server-side/some-page.


BTW few days ago I answered another question that was similar to this, maybe you find the answer or comments there useful.


  1. So in order to log in from the SPA i need to send a csrf token, and in order to get the token i can create a Django view that returns a CSRF token to the user so that it can be used to login. Wouldn't it provide attackers a way to attack my server (stackoverflow.com/questions/43567052/…)

My suggestion is to turn CSRF protection off and instead make session cookie samesite=Lax (I think that's default in newer versions of Django). All major browsers support this and it prevents CSRF.

Otherwise you can read token from another API or from cookie like here

  1. So on production i will use Nginx to have the Vue app and the Django backend app on the same server and domain, but on development how can i do that? If i run the two apps on different terminals, won't django consider the Vue app to be in a different server?

It can't understand what server it is. The only thing you should care is the domain of the cookie. It should be set on your BE domain. When running on local both FE and BE are running on domain "localhost" so there should be no issue.

Arman Ordookhani
  • 6,031
  • 28
  • 41
  • Great answer, thanks! The biggest reason that makes me want to keep Django templates are two: 1) I'm using Django-Allauth for everything authentication related, and i don't know how i can use Django allauth from the SPA 2) As you too said, i should not roll my own auth and i don't want to do that. I'm 100% sure BE and FE will be on the same domain, can i use Django-Allauth or the standard Django Auth from the SPA without losing anything in terms of security? Can i do what i do with Django templates from my SPA instead? How difficult would it be? – Jack022 Mar 22 '21 at 22:04
  • You don't need to do many things. Django session cookies are automatically set when calling BE APIs. Probably Vue only needs an end-point to understand if user is logged in or not. Something like `/api/account/me` that returns current logged in user info. – Arman Ordookhani Mar 22 '21 at 22:16
  • Thank you a lot. In terms of security, would it change something if i authenticate from the SPA? So basically the only thing i would store in the localStorage would be a state like 'authenticated', right? I think your answer made me realize that i might as well do auth from the SPA, i just don't know if Django-Allauth or the built-in Django auth supports JSON responses, every time i try to authenticate using a post request i get an HTML response – Jack022 Mar 22 '21 at 22:27
  • I think you should store nothing in localstorage unless you want to optimize something. When user opens SPA, evey time, you can all an endpoint to see if user is logged in or not. You can usually easily wrap authenticate function in a new API end-point. – Arman Ordookhani Mar 22 '21 at 23:54
  • Thank you! I have two last questions: 1) So in order to log in from the SPA i need to send a csrf token, and in order to get the token i can create a Django view that returns a CSRF token to the user so that it can be used to login. Wouldn't it provide attackers a way to attack my server (https://stackoverflow.com/questions/43567052/csrf-token-of-django-into-vuejs-when-seperate-them) ? – Jack022 Mar 23 '21 at 00:00
  • 2) So on production i will use Nginx to have the Vue app and the Django backend app on the same server and domain, but on development how can i do that? If i run the two apps on different terminals, won't django consider the Vue app to be in a different server? – Jack022 Mar 23 '21 at 00:00
  • Thank you a lot again. My problem with disabling CSRF and allowing the other method is that i'm not completely sure Allauth supports it. While concerning the second point, i think that the problem is that on development the apps are on two different ports, so i think that while developing i need to set CORS_ORIGIN_ALLOW_ALL=True, while on production i'll remove this line. I think i won't have to change much in my settings.py during production, since port and server are the same. – Jack022 Mar 23 '21 at 10:32
  • 1
    CORS is not about authentication, it's protection in browser that prevents other websites sending AJAX requests to your server. Cookie will be shared between every port on "localhost". – Arman Ordookhani Mar 23 '21 at 14:24