Authorization

Published:

Authorization is important to implement properly with tests so that bugs and vulnerabilities are found as soon as as possible. According to OWASP it is the most common vulnerability.

Compressed Definition (Authorization):

Authorization is find whether one is permitted to access a resource. See Wikipedia Definition

Authorization in real-life

The most intuitive example is that you as a kid want to do you something you would ask you an adult whether you are allowed to do it. The adult would then allow or deny it.

Authorization with Web Application

The example for web application uses HTTP protocol. I want to keep the structure flexible and explicit, so it is not as abstract as it could. Usually frameworks have built-in ways to do it but not all of them are complete.

0 Authentication

Before authorization can be performed the user must be authenticated first. To establish the identity.

TODO: See another article about authentication.

1 The request

The current standard way is to use a header

Authorization: <type> <token>

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization

First we need to parse the header.

import re


def get_auth_token(request) -> str:
  """
  Returns authorization token in Authorization header.
  """
  header_regex = re.compile('Bearer .*')

  authorization_header: str = request.headers.get('Authorization')
  if authorization_header and header_regex.match(authorization_header):
        return authorization_header.split(' ')[1]
  raise NotAuthenticatedException('Authorization -header is missing or has invalid format.')

If the exception NotAuthenticatedException is raised then 401 UNAUTHORIZED response should be returned.

Then we need to retrieve the user based on the token we have. The JWT token might have the user information already encoded, but to be safe we refresh information from database.

SELECT * FROM AppUser
    LEFT JOIN AuthToken
        ON AppUser.id=AuthToken.user
    WHERE token="%dv9lQxbnW1Rcp&zq36z";

An example of token table could be

id | user | token
---+------+----------------------
1  | 1    | dv9lQxbnW1Rcp&zq36z

When you construct a user object, remember to keep the object immutable because of predictability and avoiding accidental database updates.

class UserReadOnly:
  """
  Keeps information of user. You may have much more fields.
  """

  def __init__(self, identifier: str, role: str):
    self.identifier: str = identifier
    self.role: str = role

2 Throttles

Some endpoints might need to be throttled so that a user cannot use too much resources. If you want to throttle authenticated users then the header need to be checked first. However, if it is also publicly accessed then it is better to check throttle first.

As throttles are checked often and need to be quickly accessed, I recommend using in-memory storage systems such as Redis. https://redis.io/

import redis
memory = redis.Redis()

memory.mset({

})

3 Role checks

4 Route by method

5 Usage Limits

6 Resource-specific permissions

Implementation checklist