본문 바로가기
백엔드 개발/백엔드 일기

# 020. root domain으로 express cookie 세팅하기

by iamjoy 2022. 8. 29.

요약

express cookie를 사용해서 authentication 기능을 구현한다.

 

goal(목표)

- express cookie를 사용해서 authentication 토큰으로 jwt를 발급해서 auth_token={value}형태로 프런트에 정보를 내려준다.
- 프런트에서는 받은 쿠키를 사용해 서버에 접근한다.

 

Non-goal

로그인 방법에 대한 정책
jwt 에 대한 개념

 

plan (정책)


- domain을 설정하는 시점: 런타임 시점
도메인을 확인하고 설정하는 시점은 크게 두 가지이다.
(1) 
빌드 시점에서 도메인 값을 설정하는 방법이다. env파일에 DOMAIN 값을 설정해서 넣어줄 수 있다.
(2) 런타임 시점에서 도메인 값을 설정하는 방법으로, req.hostname을 확인해서 넣어주는 방법이 있다.

(1)은 도메인이 고정되어 있는 경우에 사용하는 것이 좋은데, domain이 얼마든 지 변화할 수 있는 상황이기 때문에 (2)를 선택해서 구현하려고 한다.

- 쿠키의 domain을 root domain으로 설정한다.
쿠키는 domain의 cname까지 영향을 받아, root domain이 같다고 하더라도 cname이 다른 경우 다른 저장소로 인식해 쿠키를 공유하지 않는다. 예를 들어 abc.com이라는 root domain이 있을 때 first.abc.com과 second.abc.com은 쿠키를 공유하지 않는다. 이에 대해 쿠키를 만들 때 설정에 domain을 root domain으로 지정해주면 쿠키가 abc.com기준으로 공유되기 때문에 first.abc.com과 second.abc.com이 쿠키를 공유할 수 있게 된다.

- jwt를 생성한다
정보를 암호화하는 방법으로 jwt를 선택한다. jsonwebtoken 패키지를 이용한다. auth_token={jwt value} 형식으로 주고 받는다.
토큰 expire는 임의로 7일을 설정한다.

 

TechSpec

 

 

서버 내부 구현

간단하게 MVC 환경을 만들기 위해 nestJS로 express 환경을 구성했다.
http://localhost:3000/ 에 auth_token:{jwt value}를 쿠키에 설정해 내려주도록 했다.

import { Controller, Get, Res } from '@nestjs/common';
import { AppService } from './app.service';
import jwt from 'jsonwebtoken';

@Controller()
export class AppController {
  constructor(private readonly appService: AppService) {}

  createToken(data: object) {
    return jwt.sign(
      {
        ...data,
        exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 60,
      },
      '_secret',
    );
  }

  @Get()
  getHello(@Res() res) {
    const data = { name: 'joie' };
    const token = this.createToken(data);
    res.cookie('auth_token', token, { httpOnly: true, maxAge: null });
    res.send(this.appService.getHello());
  }
}

 

이 코드를 실행하면 다음과 같이 쿠키가 설정되어 내려오는 것을 확인할 수 있다.
이 쿠키의 Domain을 보면 localhost로 설정되어있다. 이는 auth_token 쿠키 저장소가 localhost == root domain일 때 유지된다는 의미이다. 이 값을 원하는 대로 설정해보려고 한다.

 

cookie의 Domain이 root domain을 보는 것을 조금 더 명확하게 보기 위해 localhost를 특정 도메인에 연결하기 위해 hosts파일을 수정한다. 아래는 localhost를 joie.example.com에 매핑한 결과이다.

$ vi /etc/hosts <----- 파일 수정으로 이동

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1       localhost
255.255.255.255 broadcasthost
::1             localhost

#example
127.0.0.1 joie.example.com <------------------------- 이 부분을 수정한다.

# Added by Docker Desktop
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section


쿠키의 Domain이 joie.example.com으로 바뀌어 있는 것을 확인할 수 있다. 이제 이 부분을 root domain (example.com)을 보도록 하려고 한다. 그래야 joie.example.com이든 woody.example.com이든 쿠키 저장소를 공유할 수 있기 때문이다. 이를 처리하는 방법이 크게 두 가지가 있다.

 

첫번째 방법은 .env 로 바라볼 domain name을 고정값으로 넣는 방법이다. 이렇게 할 경우 서버는 빌드 시점에서 domain을 알게 된다. 하지만 이럴 경우 설정할 서버 도메인이 바뀌면 환경 변수를 맞춰 변경해야하는 불편함이 있다.

두번째 방법은 런타임 시점에서 서버가 host의 도메인을 알 수 있게 하는 방법이다. express req의 API 중 하나인 hostname을 사용하면 express request가 보내는 host의 도메인을 알 수 있다. 이 host 정보는 trust proxy를 통과한 requst에 대해 Host HTTP header에서 확인할 수 있다.

 

우리는 이 중에서 (2)를 선택해 root domain만 쿠키 도메인으로 셋팅하려고 한다. 따라서 아래와 같이 설정한다. 그리고서 쿠키를 찍어보면 다음과 같이 domain 설정이 root domain으로 바뀌어 있는 것을 확인할 수 있다!

  @Get()
  getHello(@Req() req, @Res() res) {
    const data = { name: 'joie' };
    const token = this.createToken(data);
    res.cookie('auth_token', token, {
      httpOnly: true,
      maxAge: null,
      domain: req.hostname.split('.').slice(-2).join('.'), // <-----root domain만 선택
    });
    res.send(this.appService.getHello());
  }

 

 

TBD

jwt

 

Reference

위의 내용은 github 코드로 정리되어 있습니다: https://github.com/erie0210/express-cookie-nestjs-react
req의 api https://expressjs.com/ko/api.html#req.hostname