NextAuth를 사용하여 API 요청 인증

NextAuth는 Next.js 앱의 사용자를 인증하는 좋은 방법입니다. 그러나 Next.js API 경로는 전체 백엔드 프레임워크를 대체하기에 적합하지 않습니다. 이 기사에서는 별도의 백엔드에 대해 인증하기 위해 NextAuth의 쿠키를 사용하는 데 필요한 모든 설정을 다룰 것입니다. 백엔드 프레임워크로 NestJS를 사용하는 동안 일반적인 논리/흐름은 거의 모든 백엔드 프레임워크로 이식 가능합니다.

Important Note: You can avoid a lot of this by proxying your API requests through Next.js. This tutorial is specifically for an API server on a separate, subdomain.



기본 아이디어



사용자가 성공적으로 로그인하면 NextAuth는 JWT 또는 세션 토큰이 포함된 쿠키HttpOnly를 발급합니다. API 서버에 액세스하기 위해 다른 토큰을 발급하는 API 경로가 있을 수 있지만 이로 인해 복잡성이 추가됩니다. 대신 NextAuth의 쿠키를 API의 토큰으로 사용할 수 있다면 어떨까요? 이는 토큰 관리를 NextAuth에 맡기고 복잡성을 줄일 수 있기 때문에 좋은 솔루션입니다. 그런 다음 백엔드는 유효성을 검사하고 계속 진행할 수 있습니다. 이것은 또한 백엔드가 프런트엔드 도메인과 관련된 하위 도메인에 있다고 가정합니다. 예를 들어 프런트엔드는 example.com에 있고 백엔드는 api.example.com에 있습니다.

프론트엔드



다음인증 구성



백엔드가 무엇이든 custom configuration for the session cookie in NextAuth.을 설정해야 합니다. 기본적으로 NextAuth는 쿠키에 대한 도메인을 지정하지 않습니다. 그 결과 하위 도메인을 포함하지 않고 도메인이 현재 페이지의 쿠키(예: example.com )인 쿠키가 생성됩니다. 그 외에 다른 모든 기본값은 괜찮습니다.

설정 방법은 다음과 같습니다.

// Inside your NextAuth config object
cookies: {
  sessionToken: {
    name: `__Secure-next-auth.session-token`, // Make sure to add conditional logic so that the name of the cookie does not include `__Secure-` on localhost
    options: { // All of these options must be specified, even if you're not changing them
      httpOnly: true,
      sameSite: 'lax',
      path: '/',
      secure: true,
      domain: `example.com` // Ideally, you should use an environment variable for this
    }
  },
}


"그게 어떻게 다릅니까? "라고 궁금해하는 도메인을보고있을 수 있습니다. 도메인을 지정하면 쿠키의 도메인 값이 앞에 추가 마침표(예: .example.com)와 함께 설정되어 브라우저에 하위 도메인으로 보내도 좋다고 알려줍니다.

요구하다



프런트엔드에서 요청할 때 쿠키 전송 요청에 대한 옵션도 추가해야 합니다.
  • fetch 요청: 요청 구성에서 credentials: "include" 지정
    MDN Reference
  • XHR 요청(예: Axios): withCredentials = true MDN Reference

  • 또한 선택한 요청 방법이 일부 HTTP 메서드에 대한 CORS 실행 전 요청을 만들 수 있는지 확인해야 합니다.

    백엔드



    헤더



    이것이 작동하려면 일부 CORS 헤더를 설정해야 합니다. 여기 있습니다:
  • Access-Control-Allow-Origin : 도메인을 지정해야 합니다. 와일드카드( * )는 요청 자격 증명에 대한 액세스를 허용하지 않습니다.
    MDN Reference
  • Access-Control-Allow-Credentials : true로 설정해야 합니다.

  • Access-Control-Allow-Headers : Cookies 헤더가 포함되어 있는지 확인하십시오.
    MDN Reference
  • Vary : Origin로 설정해야 합니다. 대부분의 프레임워크/라이브러리는 이를 자동으로 설정합니다.

  • 인증/검증



    선택한 백엔드에는 위와 유사한 조건 논리가 필요합니다. 기본 쿠키 이름을 사용한다고 가정하면 __Secure-next-auth.session-token 또는 next-auth.session-token 라는 쿠키에 액세스하게 됩니다. 이것이 JWT인 경우 유효성을 검사하고 인코딩된 정보를 추출합니다. 서버에서 NextAuth에 제공한 것과 동일한 JWT 서명 암호를 사용하는지 확인합니다. 세션 토큰인 경우 데이터베이스에서 조회하여 존재 + 만료되지 않았는지 확인합니다.

    NestJS - 여권



    다음은 Passport를 사용하여 NestJS에서 이를 구체적으로 구현한 방법입니다. 아직 Nest의 Express 플랫폼을 사용하고 있지만 대부분 Fastify 플랫폼과 호환됩니다. 먼저 다음과 같이 구성된 cors 패키지가 필요합니다.

    app.enableCors({
        origin: [
          'http://localhost:3000',
          'http://127.0.0.1:3000',
          // add your other urls here
        ],
        allowedHeaders: ['Cookie', 'Content-Type'],
        methods: ['GET', 'POST', 'PUT', 'PATCH', 'OPTIONS'],
        credentials: true, // This is what sets the `Access-Control-Allow-Credentials` header.
      });
    


    둘째, cookie-parser 패키지가 필요합니다.

    import cookieParser from 'cookie-parser';
    
    // ... other code
    
    app.use(cookieParser());
    


    마지막으로 passport-custom 패키지를 사용하여 사용자 지정 전략을 설정했습니다. 다음과 같이 구현했습니다.

    const cookieName = // This turnary statement is the conditional logic I mentioned previously
      process.env.NODE_ENV === 'production'
        ? '__Secure-next-auth.session-token'
        : 'next-auth.session-token';
    
    @Injectable()
    export class NextAuthSession extends PassportStrategy(
      Strategy,
      'nextauth-session',
    ) {
      constructor(private authService: AuthService) {
        super();
      }
    // The Request type is imported from Express
      async validate(req: Request): Promise<User | null> {
        const sessionToken = req.cookies[cookieName];
        if (!sessionToken) {
          throw new UnauthorizedException({ message: 'No session token' });
        }
    
    // authService.verifySession does a database lookup with Prisma
        const session = await this.authService.verifySession(sessionToken);
        if (!session) {
          throw new UnauthorizedException({
            statusCode: 401,
            message: 'Invalid Session',
          });
        }
    // Whatever you return gets added to the request object as `req.user`
        return session.user; 
      }
    }
    


    결론



    이것은 특히 Passport 사용 방법을 파악하는 데 약간의 시간이 걸렸습니다. 다른 사람들이 이 가이드를 보고 유용하게 사용하기를 바랍니다.

    좋은 웹페이지 즐겨찾기