3.2. A Flask Application#

A web application is less secure by default than a web server and it has more required setup. For those two reasons instead of starting our first web application on an internet-facing server, we’re going to use our development environments. In this lab we’ll create a very simple app that shows the process of setting up, starting, stopping and viewing a web application.

Step 1: Setup Python#

Flask is open source software written in Python. It is downloaded as Python source code and the source code becomes a part of the sites that are created with it. Your project will use Flask and other python packages to do its job and those packages need to be installed. The next commands creates a Python virtual environment that contains the packages you install. Unlike installing software on your system drive installing packages in a virtual environment prevents anything on your computer from being affected by the installation and makes it possible to uninstall the packages with rm.

Important

The working directory should be the root of your project repository. If you used the default repo name this command takes you there:

$ cd ~/cis-92            # For Cloud Shell 
$ cd /workspaces/cis-92  # For devcontainers  

The next command creates a Python virtual environment in a directory called .venv:

$ python -m venv .venv 

Virtual environments have to be activated before they’re used. VScode does this for you if you have the Python plugin installed. In Cloud Shell you may have to do it yourself in each new shell:

$ source ./.venv/bin/activate

Notice that your prompt changes.

With your environment activated you use the pip package manager to install Flask:

$ pip install flask

Now Flask is installed.

Step 2: Write Some Code#

It doesn’t take very much code to make a Flask app, that’s one of the great things about it. Put the following code into a file called app.py in the root of your repository:

from flask import Flask, make_response, request

app = Flask(__name__)

@app.route("/")
def index():
    username = request.cookies.get('username', None)
    if username is None:
        return "Welcome! You are not logged in.\n"
    else:
        return f"Welcome {username}!\n"

@app.route('/user/<username>')
def show_user(username):
    resp = make_response(f"You are logged in as {username}\n")
    resp.set_cookie('username', username)
    return resp

Save the file and run this command in the shell of your development environment:

$ flask run --debug
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5000
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 315-173-963

Step 3: View Your Application in a Browser#

Unless you’re developing natively on your own machine (i.e. not in a development container), viewing an application in your development environment requires that you use a tunnel of some kind. VScode has built in tunnelling under the Port tab next to the Terminal tab at the bottom. Cloud Shell Editor has a Web Preview button near the top right.

In class I demonstrate how to use both methods.

Step 4: Use curl#

Your development environment is a VM with its own IP address. To access it from a browser you need a tunnel, however to access it from curl on the command line you don’t. That’s because the command line is local to your development environment. Use this curl command to see the welcome page of your app:

$ curl -v http://127.0.0.1:5000
*   Trying 127.0.0.1:5000...
* Connected to 127.0.0.1 (127.0.0.1) port 5000
> GET / HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/8.5.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: Werkzeug/3.1.5 Python/3.12.3
< Date: Tue, 10 Feb 2026 17:54:09 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 31
< Connection: close
< 
Welcome! You are not logged in.
* Closing connection

Notice how the -v (for verbose) option shows you the HTTP protocol components that are otherwise hidden. Check out what happens when the application sets a cookie:

$ curl -v http://127.0.0.1:5000/user/me
*   Trying 127.0.0.1:5000...
* Connected to 127.0.0.1 (127.0.0.1) port 5000
> GET /user/me HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/8.5.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Server: Werkzeug/3.1.5 Python/3.12.3
< Date: Tue, 10 Feb 2026 17:56:32 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 24
< Set-Cookie: username=me; Path=/
< Connection: close
< 
You are logged in as me
* Closing connection

Now, in order to appear logged in the client has to send the username=me cookie with every new request:

$ curl -b "username=me" -v http://127.0.0.1:5000
*   Trying 127.0.0.1:5000...
* Connected to 127.0.0.1 (127.0.0.1) port 5000
> GET / HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/8.5.0
> Accept: */*
> Cookie: username=me
> 
< HTTP/1.1 200 OK
< Server: Werkzeug/3.1.5 Python/3.12.3
< Date: Tue, 10 Feb 2026 17:58:49 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 12
< Connection: close
< 
Welcome me!
* Closing connection

Cookies Are Not Secure!

Try rerunning the last command with username set to something else. Do you notice how the server blindly takes you at your word?

$ curl -b "username=hacker" -v http://127.0.0.1:5000

This would be a disaster for application security so cookies have to be encrypted on the server so that a user can’t maliciously alter them to impersonate someone else. When you create your Django application later this week you’ll give it a secret encryption key for this purpose.

Step 5: Stop the Application#

Use Ctrl-C to stop the flask command. Since no billable resources were created in this lab there’s nothing to clean up.