-
-
Notifications
You must be signed in to change notification settings - Fork 8.7k
Description
Hello everyone! Starting off I love this framework :-)!
I'm currently facing this issue regarding security and my API keys.
My approach to design my API was to have the API access keys stored in a database. (hashed) And then once the key would be sent to the header I would hash it again and see if it's present on the db.
I've managed to do almost everything except the fact that I cannot hash the API key once it' submitted ... perhaps easier with an example ...
def check_all_hashed_keys(db: Session = SessionLocal()):
quer = db.query(models.ApiKeys).with_entities(models.ApiKeys.value).all()
clean = [ str(path)[3:-3] for path in quer]
return clean
API_KEY = check_all_hashed_keys()
API_KEY_NAME = "access_token"
COOKIE_DOMAIN = "localtest.me"
api_key_query = APIKeyQuery(name=API_KEY_NAME, auto_error=False)
api_key_header = APIKeyHeader(name=API_KEY_NAME, auto_error=False)
api_key_cookie = APIKeyCookie(name=API_KEY_NAME, auto_error=False)
print(Security(api_key_query))
async def get_api_key(
api_key_query: str = Security(api_key_query),
api_key_header: str = Security(api_key_header),
api_key_cookie: str = Security(api_key_cookie),
):
if api_key_query in API_KEY:
return api_key_query
elif api_key_header in API_KEY:
return api_key_header
elif api_key_cookie in API_KEY:
return api_key_cookie
else:
raise HTTPException(
status_code=HTTP_403_FORBIDDEN, detail="Could not validate credentials"
)
So API_KEY is a list containing all the Access tokens ( hashed by bcrypt ), now I want to compare both keys however I have a problem! The key submitted is not hashed and the one in the database is.
After checking this code https://github.com/tiangolo/fastapi/blob/master/fastapi/security/api_key.py
I realize that I cannot extract the token via code in order to hash it, which then makes me unable to verify if the Key matches any of the ones present on the database.
Does anyone know a better way of doing this? I thought about changing the source code to my needs ans basically hash it there
class APIKeyQuery(APIKeyBase):
def __init__(
self, *, name: str, scheme_name: Optional[str] = None, auto_error: bool = True
):
self.model: APIKey = APIKey(**{"in": APIKeyIn.query}, name=name)
self.scheme_name = scheme_name or self.__class__.__name__
self.auto_error = auto_error
async def __call__(self, request: Request) -> Optional[str]:
api_key: str = request.query_params.get(self.model.name)
if not api_key:
if self.auto_error:
raise HTTPException(
status_code=HTTP_403_FORBIDDEN, detail="Not authenticated"
)
else:
return None
return api_key
Something like this
api_key: str = request.query_params.get(bcrypt.hashpw(self.model.name.encode('utf-8'), bcrypt.gensalt()))
This looks like a terrible way and I'd like to avoid it at all possible costs!
Anymore information that you may require I can post it here
Best, Jose