CORS Error when I return an Error code from Middleware #6983
-
|
If I try to return an 401 Response from middleware, my JS client throws a CORS exception. It seems that FastAPI does not respond to the client Pre Flight request until after middleware has completed. Here is my middleware @app.middleware("http")
async def auth(request: Request, call_next):
authorizationHeader = request.headers.get("Authorization")
keycloakUserInfoURL = keycloakHost + "/auth/realms/" + \
keycloakRealm + "/protocol/openid-connect/userinfo"
headers = {'Authorization': authorizationHeader}
r = requests.get(keycloakUserInfoURL, headers=headers)
if(r.status_code != 200):
return Response(status_code=401, content="Token not valid") #This is causing the error
else:
response = await call_next(request)
return responseHow can I return a 401 error from middleware and not have frontend clients complain about CORS? |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments
-
|
I have managed to get a workaround, but it involves having to respond to the preflight request manually and adding CORS headers manually in the error response. It does not seem like intended behaviour that I am unable to send a 401 from middleware, without having to munge my own CORS logic into the middleware. @app.middleware("http")
async def auth(request: Request, call_next):
authorizationHeader = request.headers.get("Authorization")
keycloakUserInfoURL = keycloakHost + "/auth/realms/" + \
keycloakRealm + "/protocol/openid-connect/userinfo"
headers = {'Authorization': authorizationHeader}
r = requests.get(keycloakUserInfoURL, headers=headers)
# manually check if this is a preflight request
# if so, send response
if "access-control-request-method" in request.headers:
response = await call_next(request)
return response
# If this is not a preflight request
# Check if the JWT is valid
if(r.status_code != 200):
# If JWT not valid, send a 401, but manually include the Access-Control-Allow-Origin header
return Response(status_code=401, headers={"Access-Control-Allow-Origin": "*"})
response = await call_next(request)
return response |
Beta Was this translation helpful? Give feedback.
-
|
Is your middleware in the right order? |
Beta Was this translation helpful? Give feedback.
-
|
FastAPI uses CORSMiddleware from starlette. That middleware handles the pre-flight requests (OPTION method). Hence, it should, as @Mause was thinking, be in the order of evaluation before your middleware. To read more, please see this section in the doc. Also, I would not suggest responding with Response directly. Maybe raise HTTPException instead and it will be automatically handled by the ExceptionMiddleware. |
Beta Was this translation helpful? Give feedback.
-
|
same problem. @app.middleware("http")
async def check_jwt_header(request: Request, call_next):
if request.url.path != "/api/login" and request.url.path.startswith("/api") and request.method != "OPTIONS":
res = index.check_jwt(request.headers.get("jwt"))
if res:
return res
response = await call_next(request)
return response
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
) |
Beta Was this translation helpful? Give feedback.
-
|
Yep, CORS needs to be executed first/outside of the other middleware for it to work and take precedence over the second middleware. |
Beta Was this translation helpful? Give feedback.
-
|
Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs. |
Beta Was this translation helpful? Give feedback.
-
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from middlewares.exception import ExceptionHandlerMiddleware
app = FastAPI()
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
expose_headers=["*"]
)
from starlette.middleware.authentication import AuthenticationMiddleware
from core.security import JWTAuth
app.add_middleware(AuthenticationMiddleware, backend=JWTAuth())
from app.users.routes import router as guest_user, user_router
from app.auth.route import router as auth_router
from app.modules.routes import module_router
from app.upload.routes import upload_router, upload_public_router
from core.database import Base, engine
from utils.logger import setup_logger
logger = setup_logger(__name__, "logs/main_service.log")
Base.metadata.create_all(bind=engine)
app.mount("/uploads", StaticFiles(directory="uploads"), name="Uploads")
app.include_router(guest_user)
app.include_router(user_router)
app.include_router(auth_router)
app.include_router(module_router)
app.include_router(upload_router)
app.include_router(upload_public_router)
app.add_middleware(ExceptionHandlerMiddleware)
@app.get("/")
async def root():
return JSONResponse(content={"status": "running ..."})I get a cors error from 401 token error in my axios vite react project Could you help ? |
Beta Was this translation helpful? Give feedback.
Yep, CORS needs to be executed first/outside of the other middleware for it to work and take precedence over the second middleware.