일반적으로, http 통신의 가장 큰 특징은 "무상태성" 이라는 것이다.
무상태성이란, 통신 이후 상대방의 정보를 기억하지 않는다는 점이다. 즉, 일반적인 요청 <-> 응답의 관계인 http 프로토콜에서 상대방이 누구인지를 기억하지 않으므로, 확장성에 용이하다.
또한, http는 기본적으로 "비연결성" 의 특징을 가진다.
연결을 유지하지 않는다는 의미는, 서버와 http 통신을 하기 위해 3 handshake 로 연결을 완료한 후, 필요한 요청에 대해 응답이 끝나면 그 connection을 끊어버리는 것을 의미한다. 기존 http 1.0 에서는 위와 같은 비연결성을 통해 서버에서 연결되어 있는 유저의 수를 줄여서 부담을 덜어주고, 실시간으로 처리하는 양을 절대적으로 줄여주는 역할을 했지만, 매번 자원의 요청때마다 3 handshake를 하는 행위가 몹시 비효율적이고 느렸다.
따라서, 지금은 필요한 http/css/js의 요청때까지만 연결을 유지하고 그 이후로 다시 비연결성의 특징을 가지는 절충안을 http2.0에서 최적화하고 있다.
확장성이 용이하다는 것은, 서버가 응답의 역할만 하기 때문에 다른 컴포터를 늘려서 응답할 수 있는 컴퓨터를 늘리기 쉽다는 부분이다. 만약, 하나의 서버컴퓨터가 하나의 유저를 기억하고 담당해야한다면, 다른 컴퓨터들 역시 이 유저에 대해서 다 정보를 공유하거나 아니면 그 컴퓨터 하나만이 유일한 담당자가 될 수밖에 없어 확장이 어려워진다.
하지만 무상태성의 경우, 유저의 정보를 기억해야 하는 서비스와 관련된 부분에선 부족할 수밖에 없다.(ex, 로그인 유지)
따라서, 이렇게 유저의 정보가 계속 지속적으로 서버에서 유지되도록 하기 위한 방법으로 유저에게 이른바 passport와 같은 인증 시스템 데이터를 전달해주고, 서버는 그것을 확인하는 절차로 유저를 기억하게 하면 될 것이다.
이것을 위한 방법으로 가장 일반적으로 사용되는 것이 JWT이다
JWT의 가장 큰 이점은, 무상태성의 특징을 유지하면서 유저의 인증을 계속 유지하는 방식을 취할 수 있다는 점이다.
이것의 의미는, 유저의 상태는 서버에서 저장하지 않고 필요한 인증 데이터를 클라이언트에게 전달하고, 클라이언트는 매 요청마다 이 데이터를 전달해서 보안적으로 민감한 서비스의 경우 서버는 이 데이터를 해독하여 인증을 완료하는 방식으로 연결성을 유지하는 것이다
이 방식의 장점은, 서버가 굳이 유저의 인증을 위해 DB의 I/O를 요청할 필요가 없어진다는 점이다. 서버는 오로지 암호화된 인증내용을 내부 로직을 통해 해독만 하면 될 뿐이다. 해독이 완료되면 이 유저는 인증된 유저이므로 그 이후 필요한 작업을 하면 된다. 즉, 서버는 연결을 유지하지 않지만, 요청에서 유저가 자동으로 보내오는 데이터를 통해 마치 연결을 유지하는 것과 같은 동일한 효과를 가져올 수 있다. 다시말하면 데이터의 저장에 대한 부담을 클라이언트에게 분산하는 것이다.
JWT는 크게 3가지의 파트로 분류가 가능하다
Header
JSON 형태로 되어있고, 어떤 종류의 토큰이며 어떤 방식으로 알고리즘이 되어있는지 작성되어 있다.
Payload
토큰에 암호화하여 담아놓을 데이터들이 작성되어 있다
Signature
헤더와 페이로드를 포함하여 salt를 추가한 암호값을 넣는다.
대략적인 형태는 이와같다. HMACSHA256(base64UrlEncode(header) + '.' + base64UrlEncode(payload), secret)
이렇게 만들어진 JWT는 서버의 set-cookie 헤더에 의해 브라우저의 쿠키 파티에 저장되고, 브라우저는 매 요청때마다 특별한 상황이 아닌 이상 서버에게 이 쿠키를 같이 전송하여( 굳이 따로 전송하는 번거로움 없이 ) 무상태성의 유저를 기억하지 않는다는 단점을 보완한다.
만약, 이렇게 매번 요청에 자동으로 보내지는 것이 부담스럽다면 쿠키 옵션에서 domain, sameSite를 통해 타게팅을, path를 통해 정확하게 어떤 엔드포인트에 대해서만 쿠키가 보내질지 정해줄 수 있다.
또한, 애초부터 쿠키를 localStorage와 같은 장소에 저장했다가 클라이언트가 응답을 할때 헤더에 bearer 키의 값으로 함께 담아 보내는 방식도 있다.
해당 방법은 만약 쿠키를 사용할 수 없는 환경일 경우(예를 들어, 모바일 환경은 쿠키 스토리지가 없다.) 유용하다. 일반적으로는 해당 bearer 헤더 방식으로 하는 것이 확장성에도 용이하기 때문에 추천이 된다.
해당 토큰기반 인증의 장점은 아래와 같다.
만약 제작한 어플리케이션에서 다른 타 사이트의 기능이 필요하는 경우가 있을 것이다. (ex, facebook 게시글 공유)
그런데 이때, 이 기능을 위해서는 당연히 타 사이트의 인증이 필요하고, 이 결정권은 오롯이 유저가 가지고 있다. (유저가 로그인해야만 가능)
그렇다면, 해당 서비스를 이용하기 위해 유저한테 아이디와 비밀번호를 받아야 하는가? 하는 의문에서부터 Oauth는 시작되었다.
즉, Oauth는 타 사이트의 인증 기능을 대리하여 맡음으로 필요한 토큰을 받아 유저의 대신에 해당 서비스를 이용하는 방식이다.
Oauth에서 기억해야 하는 특수한 단어들은 아래와 같다.
인증의 절차는 아래와 같다.
먼저 클라이언트 서버는 타사이트에게 자신의 앱을 등록하여 client id와 client secret을 부여받고, Authorization server측은 이 데이터와 함께 클라이언트 서버가 등록한 redirect 주소를 저장해둔다.
클라이언트측에 존재하는 oauth 버튼을 누르면, Oauth인증과 관련된 탭이 열리고 유저는 이 탭에서 해당 scope와 관련된 사항에 클라이언트서버가 접근하려고 하는것에 동의하는지에 대해 물어본다.
허락을 누르는 순간, Resource server은 url요청으로 들어오는 query에 client id, redirect URL을 확인하고 이 리다이렉트 주소에 query로 code값을 붙여서 전송한다.
클라이언트(앱페이지) 에서 해당 경로에 대한 라우팅 처리를 통해 클라이언트 서버쪽으로 코드를 전송한다.
코드를 전송받은 클라이언트 서버는 이 코드와 client id, client secret, redirect URL을 함께 Resource Server에 전송하여 access token, refresh token을 받아내고, 이 토큰정보를 통해 타사이트에 해당 유저의 정보나 서비스를 요청하여 사용하게 된다.