admin管理员组

文章数量:1389805

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.

本文标签: javascriptCORS Issue between JS program and PythonStack Overflow