HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonflaskMinor

Authentication for a Flask API

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
flaskforauthenticationapi

Problem

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?

Config

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


Exceptions

class BaseException(Exception):

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

class UnknownHostException(BaseException):
    pass

class MissingHashException(BaseException):
    pass

class HashMismatchException(BaseException):
    pass


Authentication methods

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

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

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

try:
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 req

Solution

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.

Code Snippets

# 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

Context

StackExchange Code Review Q#19786, answer score: 4

Revisions (0)

No revisions yet.