codemation / easyauth

Create a centralized Authentication and Authorization token server. Easily secure FastAPI endpoints based on Users, Groups, Roles or Permissions with very little database usage.
https://easyauth.readthedocs.io/en/latest/
MIT License
553 stars 52 forks source link

Does easyauth support basic authentication? #106

Closed randyberos closed 11 months ago

randyberos commented 12 months ago

Hello, I have a fastapi API server as an easyauth client. Is it possible to authenticate the API routes in the client server using Basic Authentication?

codemation commented 12 months ago

Hi Randy,

In general, you will always exchange username / password for a token using the /login endpoint first, then use the token against protected endpoints. The token contains information such as permissions which the endpoint uses to decide if a user is allowed or not.

Let me know if this helps.

randyberos commented 12 months ago

For our case, we would like to access the client APIs through a third party application QGIS and it would be tedious for our users if they need to go to another application and login to get a token that they will need to provide to the QGIS application to access our APIs. Is there a way for our client API to manually authenticate our users using the Basic Auth credentials they provide to our client endpoint?

codemation commented 12 months ago

@randyberos , here is one way to accomplish this with an EasyAuthClient

from fastapi import FastAPI

from easyauth.client import EasyAuthClient
from easyauth import get_user

server = FastAPI()

auth_client = EasyAuthClient.create(
    server,
    token_server='0.0.0.0',
    token_server_port=8090,
    auth_secret='abcd1234',
    default_permissions={'groups': ['users']}
)

async def custom_authenticator(username: str, password: str) -> str:
  token = await auth_client.rpc_server["easyauth"]["generate_auth_token"](
        username, password
  )
  if not "access_token" in token:
      message = (
          "invalid username / password"
          if "invalid username / password" in token
          else token
      )
      raise Exception(message)

  token = token["access_token"]

  # extract token id from token to store in valid token store
  token_id = self.decode_token(token)[1]["token_id"]
  auth_client.store["tokens"][token_id] = ""
  return token

This is a pretty good use case for a future enhancement of both EasyAuthServer & EasyAuthClient to provide a method that does exactly this. In summary, the client will pass the username / password to the connected EasyAuthServer via rpc & get a token, the token id will be cached locally as a valid token, then the token can be used on any endpoint attached with {"Authentication": "Bearer {token}"} header

randyberos commented 12 months ago

Thank you for this @codemation. 😊

I will try this approach in our application.