I am working on a webapp which has these:
FastAPI - Backend Chainlit - Frontend
The chainlit frontend is mounted on the FastAPI backend. He is how it looks in the code:
@app.get("/")
async def redirect_to_chainlit():
return RedirectResponse(url="/chainlit")
def mount_static_files(directory, path):
if os.path.exists(directory):
app.mount(path, StaticFiles(directory=directory), name=f"{directory}-static")
# mounting data and tool
os.makedirs("data", exist_ok=True)
mount_static_files("data", "/api/files/data")
app.include_router(chat_router, prefix="/api/chat")
# Mounting frontend
ROOT_DIR = Path(__file__).resolve().parent.parent
FRONTEND_DIR = os.path.join(ROOT_DIR, "frontend")
FRONTEND_PUBLIC_DIR = os.path.join(FRONTEND_DIR, "public")
FRONTEND_APP_PATH = os.path.join(FRONTEND_DIR, "app", "app.py")
if os.path.exists(FRONTEND_PUBLIC_DIR):
app.mount(
"/chainlit/public",
StaticFiles(directory=FRONTEND_PUBLIC_DIR),
name="chainlit-static"
)
logger.info(f"Mounted Chainlit static files from: {FRONTEND_PUBLIC_DIR}")
else:
logger.error(f'Cannot mount Chainlit - directory does not exist: {FRONTEND_PUBLIC_DIR}')
if os.path.exists(FRONTEND_APP_PATH):
mount_chainlit(app=app, target=FRONTEND_APP_PATH, path="/chainlit")
logger.info(f"Mounted Chainlit app from: {FRONTEND_APP_PATH}")
else:
logger.error(f'Cannot mount Chainlit app - file does not exist: {FRONTEND_APP_PATH}')
if __name__ == "__main__":
app_host = os.getenv("APP_HOST", "0.0.0.0")
app_port = int(os.getenv("PORT", "8080"))
reload_dirs = [dir for dir in os.listdir() if dir != "data"]
reload = False
uvicorn.run(
app="backend.main:app",
host=app_host,
port=app_port,
reload=reload,
reload_dirs=reload_dirs,
timeout_keep_alive=120,
timeout_graceful_shutdown=60
)
I have multiple routes:
- upload-files
- extract
- submit-feedback
here are the routes in app/api/routers/chat.py:
chat_router = r = APIRouter()
@r.post("/submit-feedback")
async def save_feedback(
request: Request,
feedback: dict = Body(...),
)-> FileUploadResponse:
@r.post("/upload-files")
async def upload_files(
request: Request,
files: list[UploadFile] = File(...)
) -> FileUploadResponse:
@r.post("/extract")
async def extract_request(
request: Request,
extract_req: ExtractRequest,
program: MultiModalLLMCompletionProgram = Depends(get_multi_model_extractor),
) -> InfoMessage:
The app does not perform any logins, instead the logins are taken care of by azure as there is an identity configured for authentication, here is how it looks like:
I need to access the user id in frontend and in backend. I need becasue users can uplaod files so they have their own dirs to store files. Also, when they send feedback, I want the feedback data to have the user id. Also, in frontend (chainlit) I load user files to view from user directory (i.e data/<user-identitufer-number/id>) so I need the userid in both front and backend.
I have tried using:
- headers: but it gives 401 not authorized even if I send access token in the headers
- singleSignIn: 401 not authorized
I tried with the headers:
@router.post("/upload-files")
async def upload_files(request: Request, files: list[UploadFile] = File(...)):
user_id = request.headers.get("X-MS-CLIENT-PRINCIPAL-ID")
It just gives 401 not authorized all the time.
I have also tried sending the token:
def get_token():
client_id=os.getenv("APP_REG_CLIENT_ID", None)
client_credential=os.getenv("APP_REG_CLIENT_SECRET", None),
tenant_id=os.getenv('APP_REG_TENANT_ID', None)
if client_id and client_credential and tenant_id:
app = msal.ConfidentialClientApplication(
client_id=client_id,
client_credential=client_credential,
authority=f"https://login.microsoftonline.com/{tenant_id}"
)
result = app.acquire_token_for_client(scopes=["https://management.azure.com/.default"])
print(result)
access_token = result["access_token"]
return access_token
else:
raise Exception("Environment variables for Azure App Registration are not set correctly.")
headers = {"Authorization": f"Bearer {get_token()}"}
response = await async_api_call(
method="GET",
endpoint="/api/chat/user-info",
timeout=600.0,
headers=headers
)
if isinstance(response, httpx.Response):
try:
return response.json()['user_id']
except (ValueError, KeyError) as e:
raise Exception("Invalid response structure") from e
else:
raise Exception(response.get("message", "Unknown error"))
but again 401 not authorized.
I just need the simples way possible to get the user id both during local run and on the webapp.
Can someone help please, I have been stuck for 2 days now and chatgpt is a just crap!

