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.