4

I am developing a simple web application written in Flask to understand browser authentication from scratch. As a first step, I added Basic Authentication just to stop anonymous access using:

from functools import wraps
from flask import request, Response


def check_auth(username, password):
    """This function is called to check if a username /
    password combination is valid.
    """
    return username == 'admin' and password == 'secret'

def authenticate():
    """Sends a 401 response that enables basic auth"""
    return Response(
    'Could not verify your access level for that URL.\n'
    'You have to login with proper credentials', 401,
    {'WWW-Authenticate': 'Basic realm="Login Required"'})

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            return authenticate()
        return f(*args, **kwargs)
    return decorated

Source: http://flask.pocoo.org/snippets/8/

It works fine as far as security is concerned. But the problem is that it prompts me for a username and password. Once I give the username and password, the authorization is persistent. So my question is:

1) How is that the authorization is persistent? Is the Basic Authorization stored in the request header throughout the browser session? I can see that when I open an incognito window I again need to type it just once.

2) To make it more user friendly, can I have a login page that does the above job i.e set a persistent Basic Authorization throught the browser session using pure Javscript instaed of doing it using a browser popup?

Nishant
  • 20,354
  • 18
  • 69
  • 101

1 Answers1

2

You should download a tool like firebug and watch the headers going back and forth on your requests. This will be enlightening as to how your browser is re-authenticating without a username and password.

Unless I am misunderstanding Flask in its entirety. All this code is doing is sending a 401 with a basic request challenge in this line

   {'WWW-Authenticate': 'Basic realm="Login Required"'})

What this is doing is sending a response header. When the browser gets this, it sees Basic as the authentication protocol and launches a dialog. This dialog is the browser popping up and asking for a password so it can authenticate to the remote resource. After you do that, it will then, for the life of that tab or browser (depending on the browser itself), remember and send the authentication along already. Here is a discussion about making browsers forget that (see closing is cumbersome)

As for question number two... it is basically a duplicate of this

But in summary, you need to ask the client for credentials and then perform the negotiation. Some frameworks allow for silent basic authentication. So, if you get the username/password, base64 encode it, shove it in the header then the server has the information it needs to authenticate. Other frameworks use a token to persist authentication for the session. So you can have an unprotected resource /login.html and then post the form to the login end point. This appears to cover flask based login pages.

Of course this should only be done over https etc.

Community
  • 1
  • 1
TheNorthWes
  • 2,661
  • 19
  • 35