해당 게시글에서 작성되는 코드는 필자의 이전 프로젝트에서 사용했던 코드의 일부를 이용하여 작성하였으며, 불필요한 부분은 생략하여 작성되었음을 알립니다.
인증 (Authentication)과 인가 (Authorization)을 합쳐서 말함.
인증 : request를 보낸 사람이 누구인가
인가 : 권한을 제한
서버가 request를 보낸 유저를 파악하는 기능. 즉, 서버에 유저에 대한 정보가 저장되어 있어야 함. (유저 모델 생성)
한 명의 유저를 특정지을 수 있는 id(email/username)와 비밀번호를 가짐.
요즘은 id 대신 email을 사용하는 추세.
하나의 유저를 특정짓기 위해 사용하기 때문에 id(email)는 중복을 허용할 수 없음.
비밀번호는 유출되면 안 되므로 암호화하여 저장.
회원 가입을 통해 서버에 유저 데이터를 저장하게 됨.
일반적으로 회원가입 시 클라이언트는 서버에 회원가입 URL로 POST 요청을 보내게 됨.
axios.post(`${BASE_URL}/auth/signup`, {
name: e.target[0].value,
username: e.target[3].value,
pw: e.target[4].value,
email: email,
nickname: e.target[8].value,
})
로그인을 통해 본인 맞춤형 기능과 콘텐츠를 사용할 수 있게 됨.
일반적으로 로그인 시 클라이언트는 서버에 로그인 URL로 POST 요청을 보내게 됨.
axios.post(`${BASE_URL}/auth/login`, {
username: e.target[0].value,
pw: e.target[1].value
})
서버는 id를 통해 어떤 유저가 인증을 원하는지 찾고, 비밀번호를 통해 그 계정의 주인인지를 확인.
성공 response와 함께 문자열 형식의 인증서를 보내주어, 클라이언트가 컴퓨터에 저장하여 이후 request를 보낼 때 함께 보내주게 됨. 이를 통해 서버가 누가 request를 요청했는지를 알 수 있게 됨. (로그인 상태를 유지)
인증서는 특정 시간이 지나면 무효화돼서 사용할 수 없게 됨. (로그아웃)
쿠키 : 서버 response나 클라이언트 코드에 따라 브라우저에 저장되는 작은 단위의 문자열 파일들
로그인 성공 response와 함께 Set-Cookie 헤더에 쿠키를 인증서로 클라이언트에게 전달. 이후 클라이언트가 request를 보낼 때, cookie header에 자동으로 추가되어 전달 됨. 서버는 이 cookie header를 확인하여, 누가 request를 요청했는지 알 수 있음.

다른 사람이 쿠키를 가로채거나 악용할 경우, 보안 문제 발생 가능.
HTTPS를 사용할 때만 클라이언트에서 서버로 쿠키가 전달됨. HTTPS를 사용하면 항상 request와 response가 암호화되기 때문에 누군가 중간에 request를 가로챘을 때 정보 유출을 줄일 수 있음.
Set-Cookie: cookie_name=cookie_value; Secure;
클라이언트가 자바스크립트 코드로 해당 쿠키에 접근할 수 없음. 쿠키를 설정한 웹사이트에 request로 보낼 수만 있음.
Set-Cookie: cookie_name=cookie_value; Secure; HttpOnly;
CSRF 공격을 예방.

None : 동일 사이트와 크로스 사이트에 모두 쿠키 전송이 가능.
Strict : 서로 다른 도메인에서는 전송이 불가능.(CSRF를 완전히 방지할 수는 있지만, 사용자 편의성 문제 발생)
Lax : Strict 설정에 일부 예외(HTTP GET method/a href/link href)를 두어 적용되는 설정 (즉, 링크를 통해 사이트를 직접 방문할 때는 쿠키가 전달)
Set-Cookie: cookie_name=cookie_value; Secure; HttpOnly; SameSite=Lax;
로그인 성공 response body에 인증서를 추가하여 클라이언트에게 전달. 자동으로 저장되지 않으므로, JS 코드로 인증서를 직접 저장. (쿠키나 로컬 스토리지에 저장)
axios.patch(`${BASE_URL}/member/pw`, {
newPassword: e.target[0].value},
{headers:{Authorization: `Bearer ${JSON.parse(sessionStorage.getItem('jwt')).access}`
}})
request를 요청할 때 인증서를 읽어와 header에 추가해주어야 함. 서버는 Authorization을 통해 누가 request를 요청했는지 알 수 있음.
request에 인증서 포함여부를 쉽게 선택할 수 있고, 서로 다른 루트 도메인 사이 인증이 가능.
크게 2가지로 나뉘며 작동하는 원리에 따라 세션과 토큰으로 나뉨.
세션 : 서버가 저장하는 사이트 방문자들에 대한 기록
서버에 첫 request를 요청하면 이 방문에 대한 데이터를 저장.

클라이언트가 request할 때마다 쿠키로 세션 id를 같이 보냄으로써 서버가 누가 요청했는지 알 수 있음. (쿠키에 세션 id가 없다 = 첫 방문)
로그인 request가 요청되면 session에는 user_id를 저장 (null인 경우 로그인하지 않음)
서버 쪽에서 사용자의 로그인 상태 확인이 분명하고 쉬움.
서버 쪽에서 세션 정보를 관리하여 클라이언트 변조에 영향받기 어려움.
서버와 클라이언트간 주고 받는 데이터가 적음
인증 토큰을 사용해 request를 보낸 유저를 파악
인증 토큰(access token) : 유저에 대한 정보를 암호화한 문자열

유저의 로그인 상태를 저장해 request가 올 때 마다 저장/확인하지 않고도 request를 요청한 유저를 알 수 있음.
로그인 request가 요청되면, 서버는 token을 생성. (저장할 정보를 가지고 비밀키를 사용해서 암호화) 생성한 token을 response body에 추가하여 클라이언트에게 전달.
로그아웃 시 클라이언트에서 직접 저장한 token을 삭제해주면 됨.
멀티 디바이스 클라이언트를 대응하는데 부담이 적음.
클라이언트가 토큰 정보를 갖고 있어 서버를 scale Up하는 데 부담이 적음.
클라이언트 세션 관리에 대한 서버의 메모리 부담을 줄일 수 있음.
access 토큰이 만료됐을 때, 재로그인을 하지 않고도 access 토큰을 새롭게 발급받는 데 사용되는 토큰.
access 토큰을 단독으로 사용하면 안정성 문제가 발생할 수 있음.
토큰의 만료 기간을 길게 잡으면, 누군가 가로챘을 때 더 오래 유저 행세를 할 수 있고, 짧게 잡으면 로그인을 자주 해야해서 귀찮고 위험할 수 있음.
그러므로, refresh token을 같이 사용하여 문제를 해소.
로그인 시, 서버에서 access token과 refresh token을 함께 전송해주게 됨.
access token이 만료됐을 경우, reissue(재발급) URL로 request를 요청하게 되고, 서버는 refresh token이 유효함을 확인 후, 새로운 access token을 전달해줌.
const response = await axios.post(`${BASE_URL}/auth/reissue`,{
accessToken: access,
refreshToken: refresh
})
refresh token은 access token이 만료됐을 때만 서버로 전달하면 되므로, access token보다 적게 전달되기 때문에 빼돌릴 확률이 적음.
JSON 형식의 데이터를 문자열로 인코딩한 토큰
header (토큰 자체에 대한 데이터 저장) + payload (실질적으로 저장하려는 정보/데이터 종류 제한 없음) + signature (데이터 무결성과 변조 방지를 위한 서명)
signature은 Header와 Payload를 인코딩한 내용과 비밀 키를 알고리즘을 통해 암호화하였기 때문에, 이를 이용해 데이터 무결성과 변조 방지를 확인할 수 있음.
세션 기반 인증을 사용할 경우, 서버는 항상 로그인 세션 정보를 저장하고 request 요청이 누군지를 매번 비교해야 하므로, 로그인한 유저가 많아지거나 특정 시간에 몰리게 될 경우 request 속도가 느려질 수 있음.
토큰 기반 인증을 사용할 경우, 토큰 자체 내용을 해석하기만 하면 되기 때문에 효율적으로 작동 가능.
토큰 기반 인증은 토큰을 발행하는 방법이 똑같고, 비밀 키만 있으면, 발행을 한 곳과 확인을 하는 곳이 달라도 됨.
요즘 크고 복잡한 웹 애플리케이션들은 작은 부분들로 나눠서 개발하는 경우가 많으므로, 토큰을 사용하는 게 좋음.
REST에 부합하기 위해서는 서버가 상태 정보를 저장하지 않는 stateless한 특성이 있어야 함. 즉, 서버는 클라이언트에서 보내는 정보만으로 충분히 상태를 파악할 수 있어야 함.
세션 정보와 같이 서버가 상태 정보(로그인했는지, 안했는지)를 저장하고 있을 때 stateful하다고 함. 즉, REST API 서버를 만들 땐 토큰 기반 인증이 더 어울림.
세션 기반 인증은 서버에서 세션 데이터를 따로 관리하므로 특정 세션을 손쉽게 무효화할 수 있음.
토큰 기반 인증은 따로 서버가 상태 정보를 저장하지 않기 때문에 특정 토큰을 무효화하는 게 복잡함.
request가 어떤 권한이 있는지 판단
한 서비스가 다른 서비스에 있는 보호된 리소스에 대한 접근 권한을 위임하거나 받는 기능
간단히, 아닌 사이트에서 자신의 구글 계정의 구글 캘린더 정보를 가져오는 경우.
유저의 인증정보를 다른 사이트에 제공하지 않고도 접근 권한을 위임 => OAuth
민감한 개인정보를 제3자에게 넘겨주지 않으면서 제 3자가 보호된 리소스에 접근할 수 있게 해주는 절차.

OAuth 2.0 기술을 이용하여 한 사이트의 아이디로 여러 사이트에서 인증 받기 위해 사용. (소셜 로그인에 사용)
access token에 id token을 같이 전달함.
id token은 JWT 형식으로 발행되며 단순히 유저의 신원을 파악하기 위한 것으로 서버에 요청을 보낼 때 같이 보내지 않음.

Cookie SameSite 설정하기
세선 기반 인증과 토큰 기반 인증(JWT) 차이점
k8s 인증 완벽이해 #3 - OpenID Connect