NEXT.JS 14 POST method with google extension

Hyeongjin Song·2024년 1월 27일

jungle

목록 보기
11/12

구글 익스텐션에서 내 웹서버로 POST 요청을 보내야 하는데, CORS 관련 보안 이슈가 발생했다.
삽질을 해보다 결국 해답을 찾아서 이렇게 포스팅하게 되었다.

일단 기본적으로 나오는 에러는 다음과 같다.

헤더가 포함되지 않았다는 내용이다. 따라서 헤더를 추가해야 한다.

https://github.com/vercel/next.js/discussions/47933

1. 헤더 추가하기

next.config.js

/** @type {import('next').NextConfig} */
const nextConfig = {
    async headers() {
        return [
            {
                // matching all API routes
                source: "/api/:path*",
                headers: [
                    { key: "Access-Control-Allow-Credentials", value: "true" },
                    { key: "Access-Control-Allow-Origin", value: "*" },
                    { key: "Access-Control-Allow-Methods", value: "GET,DELETE,PATCH,POST,PUT,OPTIONS" },
                    { key: "Access-Control-Allow-Headers", value: "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version" },
                ]
            }
        ]
    }
};

export default nextConfig;

헤더는 추가되었지만, 와일드카드를 사용할 수 없다는 내용의 에러가 발생.

임시 방편으로는 와일드카드를 제거하고 직접 원하는 Origin을 전부 추가하는 방식으로 구현할 수 있다. 이렇게 되면 입력한 Origin의 요청에 대해서는 허용되게 된다.

{ key: "Access-Control-Allow-Origin", value: "https://www.youtube.com" },

하지만 서비스는 특정 Origin에 국한되어 있지 않으므로 사실상 완벽한 해결책은 아니다. 따라서 미들웨어에서 Origin을 분석하여 직접 헤더에 추가하는 방식을 사용하였다.

2. 미들웨어에 헤더 추가하기

middleware.ts

export default auth((req) => {
  const { nextUrl } = req;
  const isLoggedIn = !!req.auth;
  if(req.nextUrl.pathname==='/api/extension'){
    const response = NextResponse.next();
    response.headers.set('Access-Control-Allow-Origin', req.headers.get('origin') ?? "*");
    response.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    response.headers.set('Access-Control-Allow-Headers', "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version");
    return response;
  }
  ...

req.headers.get('origin')으로 Origin을 받아서 직접 헤더에 추가하도록 하였다. 이렇게 되면 모든 요청에 대해서 허용할 수 있게 된다.

해치웠나 싶었지만 여전히 오류가 발생했다.

preflight 관련 에러.

preflight란?

preflight request는 실제 요청 전에 브라우저에서 보내는 작은 요청입니다. 지금 요청을 보내는 프론트엔드가 백엔드 서버에서 허용한 Origin이 맞는지, 그리고 해당 엔드포인트에서 어떤 HTTP 메소드들을 허용하는지 등을 확인합니다. 만약 허용되는 Origin이고 요청하는 메소드도 허용되는 것이라면 실제 요청을 할 수 있게 해줍니다. 그렇지 않다면, 실제 요청을 보내기도 전에 보내지 못하게 막는 것이죠. 아래 그림을 보시면 Preflight request가 무엇인지 감을 잡으실 수 있을 것입니다.

preflight request가 이뤄지려면 서버에서 OPTIONS 메서드를 허용해줘야 합니다. preflight request는 OPTIONS 메서드에 의해 만들어지기 때문입니다.

출처: https://bskyvision.com/entry/CORS%EC%99%80-%EA%B4%80%EB%A0%A8-%EC%9E%88%EB%8A%94-preflight-request%EB%9E%80

NEXT.JS에서 이런 에러가 발생한 경우에 대해 찾아봤지만, 별다른 소득이 없었다.
(인기가 없나..ㅠㅠ NEST.JS는 cors처리만 해주면 자동으로 되는 듯.. 부럽)

그러던 차에 preflight가 OPTIONS 요청이라는 사실이 눈에 들어왔다.
그렇다면, api 요청에서 OPTIONS 요청에 대해 200을 리턴하면 되지 않을까? 하는 생각이 들었다.

그래서 /api/extension/route.ts에서 OPTIONS 함수를 만들어 200을 리턴하도록 했다.

3. preflight - OPTIONS 요청 추가하기

route.ts

// preflight - OPTIONS
export const OPTIONS = async (req: NextRequest, res: NextResponse) => {
  console.log("options: ");
  console.log(req);
  return new Response("OK");
};

이렇게 에러를 해결할 수 있었다. 🎉

profile
first in, last out

0개의 댓글