Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create Django Session From Token

The Problem

I'm currently battling the well-known problem of serving authentication-enforced media files from Django. The background of the problem is simple:

  • We want to use Django's Media File support
  • Media files are not private by default. In fact, normally the webserver serves them directly.
  • We want to authenticate users when accessing media files
  • We are using token authentication on the front end
  • Since there is no valid session, the browser can't authenticate when accessing the private files (such as opening a PDF in a new tab)
  • We want Django to provide authentication for the browser, but need to somehow authenticate using the existing auth token
  • We still want nginx to send the file back, so we will leverage the X-Accel-Redirect after authentication.

Attempts To Solve

What I've done so far (and it works) is create another API view that requires token authentication and sends the file back, then created an Angular directive to swap out all protected URLs with a blob. When the user clicks a link, it gets the file using token authentication, then creates a blob that contains that data. The browser then opens that blob.

Unfortunately, blobs cannot be shared, so users cannot paste links to each other for these files. I'm wondering if there is a way around it.

Goal

My goal is to use the token to create a valid (and short expiring) session. That way, when the user clicks a link, a request is sent checking if there is a valid session, and then somehow configures the browser so that it can use that session. The whole process will look like this:

  • User clicks link (which is actually a more complex angular directive)
  • Angular fires request for session to server
  • Server responds with necessary information
  • Use JavaScript to configure browser session
  • Force browser to open link with newly established session
  • Validate user based on session, use header to pass over sending of file to nginx

I'm not looking for an implemented answer, I can handle the fine details myself. I'm more interested in getting feedback as to how this could be done in the best way. Namely:

  • How can I configure the browser given some session information in an API response?
  • How should I handle expiring these sessions so that it is secure
  • How should I establish this session? Is it reasonable to check/create the session each time a link is clicked (assume traffic is not a problem here)
  • Is this a reasonable, cross browser solution? Is there some better way?
  • How can I use an intermediate page to establish this session when the file URL is shared with a user who has no session but has a valid token?

Some Options

Update: I've spoken with some colleagues that have brought up the following options:

  • Instead of a session, have the API retrieve a single use or short-expiring token and append it to the URL of the file as a query parameter. Validate this inside the request. This works, but still does not allow the URLs to be shared.
  • Establish a session at the time of login. If that session is expired when a user tries to access a file, redirect to a session login, then when authenticated, redirect back to the file. This works too, but I want to avoid an extra authentication step, since tokens have a long expiry and sessions have a short one. Giving them the same expiry will also have drawbacks, as tokens that expire more often or sessions that expire less often are not ideal.
like image 307
Jamie Counsell Avatar asked Apr 24 '16 21:04

Jamie Counsell


1 Answers

You could simply put the Token into a cookie.

That way, it will be send to the server automatically by the browser, and you could use it for authentication when the user accesses a downloadable file directly.

Instead of reading the Authorization: header, tell your Django middleware to read the token string from the cookie.

like image 135
C14L Avatar answered Sep 30 '22 10:09

C14L