I've written a couple of functions to check if a consumer of the API should be authenticated to use it or not.

Have I done anything blatantly wrong here?


API_CONSUMERS = [{'name': 'localhost',
                  'host': '',
                  'api_key': 'Ahth2ea5Ohngoop5'},
                 {'name': 'localhost2',
                  'host': '',
                  'api_key': 'Ahth2ea5Ohngoop6'}]


class BaseException(Exception):

    def __init__(self, logger, *args, **kwargs):
        super(BaseException, self).__init__(*args, **kwargs)

class UnknownHostException(BaseException):

class MissingHashException(BaseException):

class HashMismatchException(BaseException):

Authentication methods

import hashlib
from flask import request
from services.exceptions import (UnknownHostException, MissingHashException,

def is_authenticated(app):
    Checks that the consumers host is valid, the request has a hash and the
    hash is the same when we excrypt the data with that hosts api key

    app -- instance of the application
    consumers = app.config.get('API_CONSUMERS')
    host = request.host

        api_key = next(d['api_key'] for d in consumers if d['host'] == host)
    except StopIteration:
        raise UnknownHostException(
            app.logger, 'Authentication failed: Unknown Host (' + host + ')')

    if not request.headers.get('hash'):
        raise MissingHashException(
            app.logger, 'Authentication failed: Missing Hash (' + host + ')')

    hash = calculate_hash(request.method, api_key)

    if hash != request.headers.get('hash'):
        raise HashMismatchException(
            app.logger, 'Authentication failed: Hash Mismatch (' + host + ')')

    return True

def calculate_hash(method, api_key):
    Calculates the hash using either the url or the request content,
    plus the hosts api key

    method  -- request method
    api_key -- api key for this host
    if request.method == 'GET':
        data_to_hash = request.base_url + '?' + request.query_string
    elif request.method == 'POST':
        data_to_hash = request.data

    data_to_hash += api_key
    return hashlib.sha1(data_to_hash).hexdigest()

Building on @Drewverlee's answer, I would consider renaming BaseException to APIException, or something of the like.

Also, I don't think passing app as an argument is best practice, I would recommend using the function as a decorator on your endpoints instead:

# Your imports
from application import app # Or whatever your non-relative reference is

def is_authenticated(func):
    def func_wrapper():
        # Your code here without the original def call
    return func_wrapper

You can then use this on each endpoint, adding the @is_authenticated decorator, to ensure the app is properly authenticated.


Exception itself actually inherits from a class called BaseException so:

class BaseException(Exception):

Seems backwards.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.