[Python] CORS Issue between JS program and Python

Discussão em 'Python' iniciado por Stack, Março 14, 2025.

  1. Stack

    Stack Membro Participativo

    I kept encountering CORS issue on my RedwoodJS program with my customize authentication connecting to Supabase. I noticed that when I pass a request with a header, CORS issue is seen: Access to fetch at 'http://localhost:8087/profile' from origin 'http://localhost:8910' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

    But when I removed the headers on my request. It works properly. Example of this is my /login API endpoint.

    This is my built in authentication with RedwoodJS:

    import { useState, useEffect, useCallback } from 'react'
    import { config } from 'src/config'
    import { logger } from 'src/loggers/logger'

    export const useAuth = () => {
    const [user, setUser] = useState(null)
    const [token, setToken] = useState(localStorage.getItem('token'))
    const [loading, setLoading] = useState(true)

    const logIn = async (email: string, password: string) => {
    try {
    const url = config.REDWOOD_ENV_API_ENDPOINT + '/login'
    logger.info(`Login URL is: ${url}`)
    logger.info(
    `JSON body: ${JSON.stringify({ email: email, password: password })}`
    )

    const response = await fetch(url, {
    method: 'POST',
    body: JSON.stringify({ email: email, password: password }),
    })
    console.log(response)
    const result = await response.json()
    if (result.error) {
    throw new Error(result.error)
    }
    const accessToken = result.access_token
    localStorage.setItem('token', accessToken)
    setToken(accessToken)
    setUser(result.user)
    return result
    } catch (error: any) {
    console.error('Login error:', error)
    throw error
    }
    }

    const logOut = useCallback(() => {
    localStorage.removeItem('token')
    setToken(null)
    setUser(null)
    }, [])

    const getProfile = useCallback(async () => {
    const url = config.REDWOOD_ENV_API_ENDPOINT + '/profile'
    if (!token) {
    setLoading(false)
    return
    }

    logger.info(`Fetching profile from ${url}`)

    try {
    const response = await fetch(url, {
    method: 'GET',
    headers: {
    Authorization: `bearer ${token}`,
    'Content-Type': 'application/json',
    },
    mode: 'cors',
    })

    logger.info(`Profile response status: ${response.status}`)

    if (!response.ok) {
    const errorText = await response.text()
    logger.error(`Profile error: ${response.status} - ${errorText}`)
    throw new Error(`HTTP error ${response.status}: ${errorText}`)
    }

    const result = await response.json()
    if (result.error) {
    logger.error(`Profile result error: ${result.error}`)
    logOut()
    } else {
    setUser(result.data.user)
    }
    } catch (error) {
    console.error('Profile fetch error:', error)
    logOut()
    }
    setLoading(false)
    }, [token, logOut])

    useEffect(() => {
    getProfile()
    }, [token, getProfile])

    return { user, token, loading, logIn, logOut }
    }



    Then this is my Python back-end:

    def handle_cors_response(request: Request) -> Response:
    origin = request.headers.get("origin")
    allowed_origins = settings.REDWOOD_URL if isinstance(settings.REDWOOD_URL, list) else [settings.REDWOOD_URL]

    if origin in allowed_origins:
    return Response(
    status_code=204,
    headers={
    "Access-Control-Allow-Origin": origin,
    "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
    "Access-Control-Allow-Headers": "Content-Type, Authorization",
    "Access-Control-Allow-Credentials": "true",
    },
    )
    return Response(
    status_code=403,
    headers={"Content-Type": "application/json"},
    description=json.dumps({"error": "Origin not allowed"}),
    )

    def get_response_headers(request: Request, content_type: str = "application/json") -> dict:
    origin = request.headers.get("origin")

    return {
    "Content-Type": content_type,
    "Access-Control-Allow-Origin": origin,
    "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
    "Access-Control-Allow-Headers": "content-Type, authorization",
    "Access-Control-Allow-Credentials": "true",
    }

    @app.options("/{path:path}")
    async def handle_cors(request: Request):
    return Response(
    status_code=204,
    headers=get_response_headers(request),
    )

    @app.get("/profile")
    async def profile(request):
    auth_header = request.headers.get("Authorization") or request.headers.get("authorization")

    if not auth_header or not auth_header.startswith("bearer "):
    return Response(
    status_code=401,
    headers=get_response_headers(request),
    description=json.dumps({"error": "Unauthorized"})
    )

    token = auth_header.split("bearer ", 1)[1] if "bearer " in auth_header.lower() else auth_header.split("Bearer ", 1)[1]
    try:
    decoded_token = jwt.decode(token, settings.JWT_SECRET, algorithms=["HS256"], audience="authenticated")

    logger.info(f'Decoded token: {decoded_token}')
    return Response(
    status_code=200,
    headers=get_response_headers(request),
    description=json.dumps({"data": {"user": decoded_token}})
    )
    except jwt.ExpiredSignatureError:
    return Response(
    status_code=401,
    headers=get_response_headers(request),
    description=json.dumps({"error": "Token expired"})
    )
    except jwt.InvalidTokenError:
    return Response(
    status_code=401,
    headers=get_response_headers(request),
    description=json.dumps({"error": "Invalid token"})
    )


    I've tried doing the following:

    • Changed the get_response_headers to use * for debugging purposes. But error still persist:

    def get_response_headers(request: Request, content_type: str = "application/json") -> dict:
    origin = request.headers.get("origin")
    return {
    "Content-Type": content_type,
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "*",
    "Access-Control-Allow-Headers": "*",
    "Access-Control-Allow-Credentials": "true",
    }

    • Used bruno to make a request with headers for Authorization as intended. Monitored to be working but CORS issue is shown on RedwoodJS app.

    Continue reading...

Compartilhe esta Página