How to provide temporary download url in Flask?

flask itsdangerous
timedjsonwebsignatureserializer

Currently, my index.html file contains

<a href="static/file.ext">Download</a>

I want to change this so that the download url is only valid for a certain time. For example, how would I change it to

<a href="get_file?file=file.ext&token=TEMPORARYTOKEN">Download</a>

In my Flask file, I could then have

@app.route('/get_file')
def get_file():
    filename = request.args.get('file')
    token = request.args.get('token')
    if token is valid: # what can be done here
        return send_from_directory('static', filename)

How can I generate and handle the token? Or am I approaching this completely wrong?

There are a couple ways you can do this.

  1. Generate a UUID for your token and store it in a db table along with the desired expiration datetime. Then when someone calls the URL with the token, you can just check it against the db for validity and expiration.

  2. If you don't want to use a db to store the tokens, you can use GPG to encrypt a string that contains the expiration datetime and use the resulting encrypted string as your token. This means your token will be a lot longer than a UUID, but you'd avoid having to use a db.

I recommend using UUID and a db table.

Python Flask: How can a visitor download a file? : learnpython, So I've been experimenting on running python on a server using flask, and I want Here's how i do it with JavaScript, when i get the response from the download request: URL.createObjectURL(blob); // set a human file name link.download  Then, when you tell the user where to download the file, give them that URL. You can then delete the S3 file at the end of the time period using a cron job. This way, Amazon S3 is serving the file directly, resulting in a complete bypass of your Flask server.

Maybe you should use hmac.

Generate link

import hashlib
import hmac
import time
secret = "anything you like"  # such as generate from os.urandom(length)
def generate(filename):
    current_time = str(int(time.time()))
    token = hmac.new(secret, current_time, hashlib.sha256).hexdigest()
    return "get_file?file=%(filename)s&time=%(current_time)s&token=%(token)s" % {
        "filename": filename,
        "current_time": current_time,
        "token": token
    }

Verify link

import hashlib
import hmac
import time
secret = "anything you like"  # same as in generate function
def verify(time_in_link, token_in_link):
    time_limit = 15 * 60  # maximum time in sec(such as: 15(mins) * 60 (convert them to sec)`enter code here`) that you want them to start download after the link has been generated.
    if (time.time() - int(time_in_link)) > time_limit:  #timeout, return False
        return False
    if hmac.new(secret, str(time_in_link), hashlib.sha256).hexdigest() == token_in_link:  # Check the token is available or not
        return True
    else:
        return False

arivictor/How-to-make-secure-and-temporary-urls-in-Flask, Create Temporary URLs in Flask (Shower Idea). I'm currently working on a project that enables users to view sensitive private information, I was looking at a​  create dynamic link for file download Hi there, I'm trying to get a very simple flask application to provide a link to download a file, but struggling, I can get it to send the file if I return send from file, but then it doesn't redirect to another page, or I can get it to redirect to another page, but I can't get it to download.

The best way to do that is to use itsdangerous package. You can generate a URL that last whatever time you want. Furthermore you could encode secretly any information within the URL. The good thing about that is that NO need to deal or store timestamps into the database

To generate a URL that last for 30 mins and encode user id within the token

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

s = Serializer('WEBSITE_SECRET_KEY', 60*30) # 60 secs by 30 mins
token = s.dumps({'user_id': currentuser.id}).decode('utf-8') # encode user id 

Use the following to generate the URL you want

url_for('get_file', token=token)

To validate a URL

@app.route('/get_file/<token>')
def get_file(token):
    s = Serializer('WEBSITE_SECRET_KEY')
    try:
        user_id = s.loads(token)['user_id']
    except:
        return None
    user = User.query.get(user_id)

    if not user:
        flash('This is an invalid or expired URL, please generate a new one!', 'warning')
        return redirect(url_for('another_route'))

    return send_from_directory('static', filename, as_attachment=True)

Uploading Files, That way you can make sure that users are not able to upload HTML files that would and that uploads the file and redirects the user to the URL for the uploaded file: Well it will store them in the webserver's memory if the files are reasonable small otherwise in a temporary location (as Downloads: PDF · HTML · Epub. Variable rules allow values to be passed into the URL using <this_syntax> and allows us to work with variable data coming in via the URL. Although not a necessity, Flask provides us with some useful converters to add an additional layer of validation to any values soming in via the URL. We an use converters in our URL routes like so:

Something I came up with in the shower:

from flask import Flask
import datetime as dt
import hashlib

app = Flask(__name__)

time_lock = dt.datetime.now().strftime("%m/%d/%Y")

@app.route('/')
def home():
    security_code = hashlib.sha256(time_lock.encode())
    return f"<a href='/test/{security_code.hexdigest()}'>Click Here</a>"


@app.route('/test/<security_code>')
def test(security_code):
    master_code = hashlib.sha256(time_lock.encode())
    if security_code == master_code.digest():
        return "Access granted!"

What this is doing is using a hash of the current date as a temporary URL. Obviously has security flaws but it's a crazy idea that does work and could be built upon to be more secure. Its very similar to the chosen answer but doesn't use persistent storage. This would be suited for securing links from being bookmarked possibly?

Return Files with Flask send_file Tutorial, In this case, if a person goes to /file-downloads/, and clicks the download button, they will get an image returned. How about a pdf? @app.route('/return-files/')  In this article I'm going to present several options for adding encryption to a Flask application, going from an extremely simple one that you can implement in just five seconds, to a robust solution that should give you an A+ rating like my site gets from this exhaustive SSL analysis service.

Another way would be to encode the primary key from the db in base64. That's usually how the short url-services all over the net get the short urls. The db ensures uniqueness and since it's base64 it'll take quite a few files before the urls grow long.

On every request you then check your db to see if the link is still valid. If it isn't you do something meaningful with the request.

flask.send_from_directory Python Example, This page provides Python code examples for flask.send_from_directory. def download(filename): if "email" not in session: return The URL generator of flask​-frozen is a method decorator # that expects the def entry_dist(path): return flask.send_from_directory(EFUNDS_DIST_DIR, path) # temporary efunds proxy. Generating a pre-signed S3 URL for reading an object in your application code with Python and Boto3. As mentioned above, you may want to provide temporary read access to an S3 object to a user of your application, such as downloading a PDF of an invoice. The code snippet below shows how you would do it in your application code.

Upload a File with Python Flask, The URL handler extracts the file from the request.files [] object and saves it to the required location. Related course: Python Flask: Create Web Apps with Flask Each uploaded file is first saved on a temporary location on the server, and then  Flask will detect and use them if you install them. Blinker provides support for Signals. SimpleJSON is a fast JSON implementation that is compatible with Python’s json module. It is preferred for JSON operations if it is installed. python-dotenv enables support for Environment Variables From dotenv when running flask commands.

Flask-Uploads, You can create different sets of uploads - one for document attachments, one for can use the save method to save uploaded files and path and url to access them. base_url – The URL (ending with a /) that files can be downloaded from. Flask â Templates - It is possible to return the output of a function bound to a certain URL in the form of HTML. For instance, in the following script, hello() function will rende

Sending files with Flask, Let's create a new route and put this into practice, allowing our user to download a report by providing a path in the URL. A Flask application is an instance of the Flask class. Everything about the application, such as configuration and URLs, will be registered with this class. The most straightforward way to create a Flask application is to create a global Flask instance directly at the top of your code, like how the “Hello, World!” example did on the

Comments
  • While I think your question is correct, I wanted to discuss one thing related to this. Just because of this constraint, we'll be forcing the framework(django/flask/RoR) to stream the file back, whereas I would have loved it if there was a solution in which we could get nginx/apache to serve it.
  • Is there a better way to provide temporary authentication for downloads using nginx or apache? How would it communicate with the rest of the program?
  • What framework are you using?
  • By framework do you mean something like Flask, or do you mean something else? As of now, I am just using Flask's built-in run() method to run the server locally, but for production I will probably deploy to a third-party server such as Heroku.
  • @darkryder send_from_directory and send_file from flask support X-Sendfile header, which delegates the actual sending of the file to the web server (usually nginx with flask).
  • instead of reinventing the wheel with GPG, for option 2 one should use itsdangerous package, which is already a flask dependency and has methods for this purpose specifically (URL signing). Security is hard to get right, one should always prefer to use a proven and audited lib that stood the test of time instead of coming up with your own encrypting/signing mechanisms.
  • itsdangerous package already does that, handling all HMAC and time calculation for you automatically and is already a flask dependency. Security is hard to get right, one should always prefer to use a proven and audited lib that stood the test of time instead of coming up with your own encrypting/signing mechanisms.