How to secure JWT tokens with a DRF backend supporting both mobile and SPA clients?

I am developing an application that uses the Django REST Framework to provide a REST API.

I intend to protect it using token authentication, with the help of simple_jwt.

Example API overview:

  • /auth/login/: Supports POST, requires valid username and password, returns a JWT access and refresh
  • /auth/refresh/: Supports POST, requires a valid refresh token, returns new access and refresh tokens
  • /protected/endpoint/: Requires a valid access token

From reading on CSRF I have gathered:

  • CSRF is only needed if cookies are involved, so only use for the SPA client
  • To persist the JWT token:
    • SPA: Persist in an httpOnly cookie with secure=true and same-origin set
    • App: Persist in however the app persistent state works

So far so good, however, this would mean that my REST API needs to both require CSRF tokens for requests coming from the SPA and not require/ignore CSRF tokens for requests coming from mobile app clients.

Since this is logically impossible I was first thinking of implementing 2 separate APIs. I.e.:

  • /spa/auth/..., /spa/protected/...: For SPA clients, where all endpoints require a CSRF token
  • /mobile/auth/..., /mobile/protected/...: For mobile clients, where all endpoints are CSRF exempt.

But doing this just means that my CSRF protection is useless, since a malicious actor can just target my mobile API instead of my SPA API.

I also read about a bit about CORS but I am not sure how it fits into all of this.

Questions:

  • Am I correct CSFR is only needed when cookies are involved?
  • If the answer to the previous question is "yes", can I avoid storing the JWT token in a cookie altogether for SPA, but still somehow securely persist SPA login across browser sessions and page refreshes?
  • If the answer to the previous question is "no", then how can I support both types of clients while also preventing CSRF attacks?
  • If I cannot get around CSRF tokens for SPA, how should I store the CSRF cookie (do I even need it to be in a cookie?)? I assume it will need at least same-origin to be set, to avoid leaking it to other domains, but does it also need to be httpOnly and secure=true? I've read conflicting opinions on that.
  • How should I implement CSRF with DRF? The documentation for SessionAuthentication mentions CSRF but it is vague and even states that the default DRF CSRF implementation is not suitable for login views.
  • Where does CORS fit into all of this? Can I use it to fix the problems I have?

EDIT:

I've thought about this more - what if I subclass the CSRF middleware and allow it to be bypassed if there is an Authorization header present? Then the request can be granted or denied by the authentication middleware directly (effectively I am assuming that if there is an Authorization header I am dealing with a mobile client, which does not need CSRF protection).

Is that a bad idea?

In case it isn't, then how should the LoginView look like? It should still be protected against CSRF but neither the mobile, nor the SPA clients will have a token to set as the Authorizaton header...

Вернуться на верх