GraphQL Authentication with Passport & Prisma

Taegyung Gong·2020년 12월 27일
0

GraphQL

목록 보기
3/3
post-thumbnail

About GraphQL Authentication...

GraphQL server를 구축할 때 querymutation JWT를 이용한 인증에 대해 이야기 해 볼 예정입니다.😄

How to Authentication?

querymutation 를 이용한 API에 대해 Bearer 인증 방식을 적용 해 볼 예정입니다.

"Authorization": "Bearer <토큰>"

Bearer 인증 방식을 동해 HTTP 헤더로 인증 토큰을 넘기면 passport에서 설정해준 전략을 통해 request 객체 내 user객체의 존재 여부를 판별합니다.
이후 user객체가 올바르지 않다면 에러를 던져 실패로 처리하고 성공한다면 문제 없이 해당 API로 요청이 정상적으로 잘 가도록 구현 할 예정입니다.


1. Passport 설정

passport.js

import { PrismaClient } from '@prisma/client';
import { Strategy as JwtStrategy, ExtractJwt } from 'passport-jwt';
import passport from 'passport';

const prisma = new PrismaClient();

const jwtOptions = {
  jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  secretOrKey: process.env.JWT_SECRET_KEY,
};

const verifyJwt = async (payload, done) => {
  try {
    const isExist = await prisma.user.findOne({
      where: {
        id: payload.id,
      },
    });

    const user = {
      id: payload.id,
      nickname: payload.nickname,
      avatar: payload.avatar,
    };

    if (isExist) {
      return done(null, user);
    } else {
      return done(null, false);
    }
  } catch (err) {
    return done(err, false);
  }
};

export const authenticateJwt = (req, res, next): void => {
  passport.authenticate('jwt', { session: false }, (error, user) => {
    if (user) {
      req.user = user;
    }
    next();
  })(req, res, next);
};

passport.use(new JwtStrategy(jwtOptions, verifyJwt));


JWT 내 payload의 user id를 참조해 prisma client를 통해 유저를 찾아 유저가 존재 할 경우 req 객체 내 해당 user의 객체를 생성합니다.

isAuthenticated.js

import ERROR_MSG from '@utils/errorMessage';

export default (req): void => {
  if (!req.user) {
    throw Error(ERROR_MSG.unauthorized);
  }
  return;
};

passport 설정을 통해 JWT을 판별해 user가 존재하지 않을 경우 error을 반환하는 미들웨어를 추가합니다.


2. Server 설정

server.js

import { PrismaClient } from '@prisma/client';
import './env';
import { GraphQLServer, PubSub } from 'graphql-yoga';
import { authenticateJwt } from './middlewares/passport';
import isAuthenticated from './middlewares/isAuthenticated';
import schema from './schema';
import logger from 'morgan';

const PORT = process.env.PORT || 4000;

const prisma = new PrismaClient();
const pubsub = new PubSub();
const server = new GraphQLServer({
  schema,
  context: ({ request }) => ({ request, isAuthenticated, pubsub }),
});

server.express.use(logger('dev'));
server.express.use(authenticateJwt); // server가 요청을 수신할 때마다 JWT 인증 방식을 적용합니다.

server.start(
  {
    port: PORT,
    cors: { origin: true },
    endpoint: '/graphql',
    subscriptions: {
      path: '/graphql',
    },
  },
  () => {
    console.log(`Server running on http://localhost:${PORT}`);
  },
);



아래와 같이 GraphQL 서버에 context 옵션에 request와 인증과 관련된 middleware를 넘겨줍니다.

const server = new GraphQLServer({
  schema,
  context: ({ request }) => ({ request, isAuthenticated, pubsub }),
});



3. Authentication 적용

allUser.js

아래는 모든 유저의 정보를 조회하는 예시 resolver입니다.

import { PrismaClient} from '@prisma/client';

const prisma = new PrismaClient();

export default {
  Query: {
    allUsers: (_, __, { request, isAuthenticated }) => {
      isAuthenticated(request);
      return prisma.user.findMany({
        include: {
          messages: true,
        },
      });
    },
  },
};


3번째 인자는 context로 request, isAuthenticated와 같이 server.js에서 context를 통해 넘겨 준 함수들을 포함하고 있습니다.

request와 인증과 관련된 미들웨어를 사용함으로 써 해당 resolver에 인증 방식을 적용 할 수 있습니다.

isAuthenticated(request);

다른 query와 mutation을 이용한 API 요청에 대해서도 간단하게 적용 할 수 있겠죠?😄


마치며...

GraphQL의 경우 endpoint가 하나라 기존의 REST 방식과 달라 어떻게 각각의 API에서 인증을 처리할 지 처음에는 혼란스러웠습니다.🤔

하지만 공부를 하면서 찾아보니 GraphQLServer의 context를 통해 request 객체와 필요한 함수들을 넘겨줘서 이를 이용 해 해당 API의 인증 처리를 간단하게 적용 할 수 있는 것을 확인하였고 해당 내용을 적용해 본 후 정리한 내용을 적어 보았습니다.

혹시 이해가 안 가시거나 잘못된 내용이 있다면 이야기해주시면 감사하겠습니다.😊

참고

참고 블로그

profile
Web developer🐳

0개의 댓글