인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

인프런 커뮤니티 질문&답변

원준님의 프로필 이미지
원준

작성한 질문수

스프링 시큐리티 OAuth2

OAuth2 인가서버로부터 access token 발급 후 저장 관련 질문

작성

·

2K

1

안녕하세요 강사님.

OAuth2 인가 프레임워크 관련하여 학습 중 인가서버로부터 받은 access token을 어떻게 저장하고 어떻게 활용할 수 있을지 고민하다가 궁금한 점이 있어 질문드립니다.

 

제가 생각했던 프로세스는 이렇습니다.

[리소스 오너가 소셜 로그인 시 (구글인 경우)]

  1. 리소스 오너가 구글 로그인을 한다.

  2. 클라이언트 (내가 만든 스프링 서버)는 구글의 인가서버로부터 리소스 오너의 userInfo 엔드포인트 접근 시 사용할 수 있는 access token을 받는다.

  3. access token을 활용해서 userInfo 엔드포인트에 접근하여 리소스 오너의 이메일, 이름 등의 정보를 가져온다. (이 부분은 내가 구현하지 않아도 스프링 시큐리티에서 제공)

  4. 소셜 로그인 시 얻은 정보 (oidc 활성화 시 id-token, 리소스 오너가 허용한 userInfo 등)를 클라이언트의 세션에 저장한다.

  5. 그리고 로그인 프로세스 완료되어 LoginSuccessHandler에서 이후 로직을 처리할 수 있다.

 

[이후 로그인 된 상태에서 클라이언트의 API 호출 시]

  1. 클라이언트의 API를 호출할 때 SecurityContextHolder에 userInfo를 담아 활용할 수 있다.

  2. access token은 클라이언트에 저장되어 있고, API 호출 시 꺼내어 리소스 서버에 접근할 수 있다.

 

그런데 SecurityContextHolder에 access token 정보가 보이지 않아 궁금한점이 생겼습니다.

  1. 만약 로그인이 된 상태에서 userInfo 엔드포인트에 접속 시 매번 새로운 access token을 발급 받아서 요청하는 것일까요? (SecurityContextHolder에 access token이 없어서 조금 헷갈리고 있습니다.)

  2. 100명의 리소스 오너가 로그인 할 때마다 access token을 발급받으면 총 100개의 access token이 발급되는게 맞을까요?

    1. 이러한 경우 클라이언트에 100개의 access token을 저장 후 userInfo 엔드포인트 접근 시 사용하며, 만약 만료되었다면 refresh token으로 access token을 재발급 받아 다시 userInfo 엔드포인트에 접근하는게 맞을까요?

  3. 만약 1개의 클라이언트에 100개의 accessToken을 저장 후 만료 전까지 사용하는 것이라면 클라이언트에 부하가 많이 발생하여 scale-out하는 경우에는 보통 어떻게 해결할 수 있을까요?

  4. Google, Naver, Kakao 등의 소셜에서 access token을 발급 받는 것 까지는 스프링 시큐리티가 지원해주지만 이후 다양한 엔드포인트를 호출하거나, access token 만료 시 refresh token으로 재발급 받는 로직 등은 제가 구현해야 하는게 맞을까요?

 

제가 아직 강의를 절반밖에 듣지 않아서 이후 강의해주시는 부분에 제가 질문드린 내용이 포함되어 있을 수도 있을 것 같습니다. 만약 포함되어 있다면 간략하게나마 어떤 강의 동영상을 참고하면 좋을 지 말씀해주시면 감사하겠습니다.

감사합니다.

 

답변 1

2

정수원님의 프로필 이미지
정수원
지식공유자

전체 질문에 대해 종합적으로 설명하겠습니다.

우리는 소셜로그인을 사용해서 인증을 받는 과정과 인증이후의 과정을 구분해서 이해할 필요가 있습니다.

소셜로그인은 단지 클라이언트에 접속한 사용자로 하여금 최종적으로 인증을 받을 수 있도록 편리한 수단을 제공한다는 점을 먼저 이해해야 합니다.

예를 들어 우리는 오랫동안 전통적인 방식인 폼 로그인을 통해 사용자가 인증을 받는 방식을 많이 취해 왔고 현재도 여전히 존재합니다.

그러나 폼 로그인이 가진 여러가지 단점을 개선할 필요가 생겨나고 좀 더 보안상 안정적이고 편리한 방식으로 인증체계를 갖추어 나갈 수 있는 방법들이 여러 모양으로 생겨났는데 그 중 OAuth2 인증 방식이 가장 널리 사용되는 인가 프레임워크로 발전하게 되고 이를 통해 전통적인 폼 로그인 방식을 대체하는 서비스로까지 성장하게 됩니다.

이 중 소셜로그인 방식은 클라이언트가 직접 운영해야 하는 인가서버를 다른 기관(구글, 네이버, 애플)의 도움을 받아 OAUth2 의 기술적 구현이 가능하도록 한 것이라 볼 수 있습니다.

근데 이것은 곧 전통적인 로그인 방식을 소셜 로그인의 방식으로 대체한 것에 지나지 않습니다.

이 의미는 곧 로그인 이후의 처리방식은 폼 로그인이나 소셜로그인이나 크게 다를 바가 없다는 뜻이기도 합니다.

여기서 중요한 설명을 하나 드리자면 질문하신 내용 중에 SecurityContextHolder access token 이 보이지 않는다고 했는데 그것은 지극히 당연한 결과이고 보일 필요가 없습니다.

SecurityContextHolder 는 인증 이후의 진행을 위해 제공되는 기능이지 인증 과정에 관여하는 객체가 아닙니다. 즉 access_token 는 인증을 위해 제공되는 하나의 수단이지 인증 이후에 필요한 개념이 아니기 때문에 SecurityContextHolder 에서 취급해야 할 요소가 아닙니다.

access_token 은 클라이언트에게 권한을 부여하는 개념에 불과합니다. 어떻게 보면 인증 자체와도 거리가 먼 개념입니다. 단지 인증을 받기 위해 사용자의 정보를 가지고 오기 위한 수단에 가깝습니다.

정확하게 설명하자면 SecurityContextHolder 는 access_token 을 통해 사용자의 정보를 가지고 와서 최종 인증까지 수행한 다음 생성되는 인증 객체가 저장되는 객체이지 access_token 과는 아무런 관련이 없습니다.

제가 위에서 '전통적인 로그인 방식을 소셜 로그인의 방식으로 대체한 것에 지나지 않습니다.' 라고 설명한 것을 잘 생각해 보면 access_token 은 소셜로그인의 방식을 위해 사용되는 수단이며 일단 소셜로그인이 성공하게 되면 그 다음 진행은 세션방식으로 인증을 계속 유지할 것인지, 아니면 세션을 사용하지 않고 JWT 와 같은 토큰 방식으로 인증을 계속 유지할 것인지를 선택하는 결정만 남을 뿐 더 이상 소셜로그인의 과정이 다시 필요하지도 않고 access_token 도 필요 없습니다. 이미 소셜 로그인의 역할은 끝난 것입니다. 사용자가 접속할 때 마다 요청하는 것이 아닙니다.

소셜로그인은 1회적으로 인증을 받으면 되고 그 다음부터는 세션방식의 인증 유지 혹은 토큰 방식의 인증 유지가 필요할 뿐입니다. 만약 세션이 만료되거나 토큰이 만료된다면 다시 소셜로그인을 통해 인증을 받는 식으로 진행하는 것 뿐입니다. 그야 말로 인증이 필요한 상황이 되면 사용하고 인증이 이미 되었으면 그 다음 부터는 인증을 계속 유지하기 위한 절차만 구현 하면 됩니다.

다만 access_token 을 리소스 서버에 접근하기 위한 용도로서 사용해야 한다면 access_token 이 필요할 수는 있으나 여기서 기억해야 할 점은 access_token 은 클라이언트의 리소스 서버가 아닌 access_token 을 제공한 기관들의 리소스 서버로 접근하기 위한 용도여야 합니다. 왜냐하면 access_token 을 제공한 기관들이 access_token 을 검증할 키와 정보들을 가지고 있기 때문입니다.

결론적으로는 SecurityContextHolder 에는 access_token 이 존재하지 않는 것이 맞으며 만약 어떤 이유로 access_token 이 필요하고 이것을 활용할 목적이 있다면 이것을 세션 스토리지 혹은 로컬 스토리지에 저장해서 사용하면 됩니다. 이것은 저의 강의에서 OAuth2AuthorizedClient 를 설명하는 챕터가 있는데 이 강의를 참조하시면 됩니다.

전체적으로 설명드려서 조금 설명이 길었는데 본 강의 전반에 걸쳐 access_token 이 정확하게 무엇인지를 잘 이해하는 것이 더욱 중요하다 할 수 있습니다.

 

원준님의 프로필 이미지
원준
질문자

자세하게 답변해주셔서 너무나도 감사합니다.

원준님의 프로필 이미지
원준

작성한 질문수

질문하기