본문 바로가기
개발 - Coding/Backend

Redirect URI는 프론트엔드여야 할까? 백엔드여야 할까? (OAuth 2.0에 대해서 알아보기)

by dev_jinyeong 2024. 12. 24.

계기: Redirect URI는 프론트엔드여야 할까? 백엔드여야 할까?

 

최근에 회사에서 개발을 진행하던 중, 로그인 방식 중 MS Entra ID 로그인을 구현해야 하는 요구사항이 있었습니다.

 

MS Entra ID는 마이크로소프트에서 제공하는 OIDC 규격의 서드파티 로그인 서비스인데요.

 

사실 이번에 직접 구현해보기 전까지는 OAuth 2.0과 OIDC에 대해서 개념만 대충 알고 있었고, '실제로 구현하게 되면 그때 문서 보고 하지~' 같은 안일한 마음으로 열심히 공부하지 않았습니다.

 

 

그런데 막상 구현하려고 보니 생각보다 막히는 부분도 많았고, 프론트엔드 분들과 소통할 때도 서로 생각하는 시퀀스가 달라서 뭐가 맞는지에 대해서 고민이 많이 되더라구요.

 

그 중에서 가장 의견이 분분했던 Redirect URI는 프론트엔드와 백엔드 중 어느 쪽의 엔드포인트여야 할까? 에 대해서 답해보면서 OAuth 2.0에 대해서 알아보고 제 나름의 결론을 말씀드리도록 하겠습니다.

 

OAuth 2.0에 대해 모르면서 어떻게 개발 가능했는가?

 

많은 분들이 프로젝트를 시작하면, 로그인 방식에 대해서 '로그인을 OAuth 2.0으로 구현했다'거나, '서드파티 로그인을 지원했다' 라고 적곤 하시는데요.

 

저도 사실 사이드 프로젝트를 하면서도 API 규격 문서에 있는대로 갖다 썼을 뿐, 여기에 대해서 크게 고민해본 적이 없었습니다.

 

왜 그럴 수 있었냐면, 사실 사이드 프로젝트에 보안이나, 제약사항이란 개념이 희미하기 때문입니다.

 

어떤 설정이 잘못되거나 하면 바로 Google, Microsoft, 카카오, 네이버 등의 개발자 페이지에 들어가서 내가 원하는 대로 고치면 어떻게든 앞뒤가 맞게 되어서 동작은 합니다.

 

그래서 정확히 어떻게 동작하는지에 대해서나, 프로토콜의 시퀀스에 대해서 모른 상태에서도 어떻게든 개발을 할 수 있는거죠.

 

또한 개발자 콘솔에서는 많은 부분이 추상화되어 옵션만 선택하면 되기 때문에 실수의 여지가 많이 줄어듭니다.

 

하지만 회사에서 프로젝트를 하게 되면 다양한 제약사항이 발생하게 됩니다.

 

설정을 내 마음대로 고칠 수 없고 신청 문서를 작성해야 한다든가, 서비스에 접근할 수 있는 IP가 웹 방화벽으로 제한된다든가 하는 일들입니다.

 

이런 제약사항이 발생하면, 프로토콜의 액터와 시퀀스에 대해서 정확히 이해하고 있어야 개발 과정에서 비용도 줄어들고, 최종 산출물에서 버그도 줄일 수 있습니다.

 

일반적으로 알려진 OAuth 2.0 시퀀스

 

OAuth 2.0을 지원하는 벤더는 매우 많습니다만 제가 MS 기준으로 작업하기도 했고, 문서도 가장 잘 나와있다고 생각되어 MS 기준으로 설명하겠습니다.

 

일반적으로 OAuth 2.0의 액터의 관계는 아래와 같습니다.

 

 

이 관계에 대해서 아주 간결하고 추상적으로 설명하면 아래와 같습니다.

 

  1. Resource owner가 Client에 접근합니다.
  2. Client는 Resource owner로 하여금 Authorization server를 통해 Authorization을 부여하게끔 요청합니다.
  3. Client는 발급받은 Authorization으로 Resource server에 resource를 요청합니다.

 

각각의 액터에 대해서 더 자세히 설명해보면요.

 

Resource owner: resource의 소유자입니다. 다만 이 '소유'의 개념은 추상적입니다. 실제로 resource를 갖고 있는 것이 아니라, resource에 대한 권한을 갖고 있으면서 이 권한을 위임할 수 있습니다. 실제 resource는 resource server에 위치합니다. resource owner는 end-user라고도 합니다.

 

Authorization server: resource owner에 대한 authentication, resource server에 대한 authorization을 제공합니다. Client는 resource server에 대한 Authorization을 받아서 resource server에 접근할 수 있습니다.

 

Resource server: resource를 실제로 가지고 있는 서버입니다. 적절한 authorization에 대해서 resource를 제공합니다.

 

Client: resource owner로부터 권한을 위임받아서 resource에 접근하고 이에 기반한 서비스를 제공합니다.

 

더 자세한 설명을 보고 싶으시면 아래 링크를 참고해주세요.

https://learn.microsoft.com/ko-kr/entra/identity-platform/v2-protocols

 

그런데 이건 아주 추상화된 설명이구요.

 

실제 HTTP 요청에 기반한 시퀀스는 아래와 같습니다.

 

 

그래도 크게 어렵진 않습니다.

 

/authorize 엔드포인트로 인가를 요청하고, 여기서 받은 authorization code로 /token에 access token을 요청하고, 이 access token으로 resouce를 요청하는 흐름입니다.

 

다만 여기서부터는 구체적으로 어떻게 authorization을 부여할 것인지에 대한 구현 부분에 대한 규격이 필요하게 됩니다.

 

여기서의 Authorization code는, RFC 6749에서 정의하고 있는 Authorization Code Grant 규격을 준수한 것인데요.

 

다른 RFC 문서도 마찬가지긴 하지만, RFC 6749도 직접 읽어보는 게 좋다고 생각합니다.

 

RFC 6749는 아래 링크에서 확인할 수 있습니다.

https://datatracker.ietf.org/doc/html/rfc6749

 

Authorization Code Grant 시퀀스를 보면 아래와 같이 설명하고 있습니다.

 

     +----------+
     | Resource |
     |   Owner  |
     |          |
     +----------+
          ^
          |
         (B)
     +----|-----+          Client Identifier      +---------------+
     |         -+----(A)-- & Redirection URI ---->|               |
     |  User-   |                                 | Authorization |
     |  Agent  -+----(B)-- User authenticates --->|     Server    |
     |          |                                 |               |
     |         -+----(C)-- Authorization Code ---<|               |
     +-|----|---+                                 +---------------+
       |    |                                         ^      v
      (A)  (C)                                        |      |
       |    |                                         |      |
       ^    v                                         |      |
     +---------+                                      |      |
     |         |>---(D)-- Authorization Code ---------'      |
     |  Client |          & Redirection URI                  |
     |         |                                             |
     |         |<---(E)----- Access Token -------------------'
     +---------+       (w/ Optional Refresh Token)

   Note: The lines illustrating steps (A), (B), and (C) are broken into
   two parts as they pass through the user-agent.

                     Figure 3: Authorization Code Flow

 

A ~ E 까지의 흐름을 보면 어떤 흐름으로 Authorization 부여가 구현되는지 알 수 있습니다.

 

A: Client가 User-Agent(일반적으로 web application, mobile application 등)로 하여금 Authorization을 요청합니다.


B: User-Agent가 Resource Owner로 하여금 Authentication을 수행하도록 합니다. (서드파티 로그인 화면) 이때, Authentication이 완료된 이후 Authorization을 전달할 Redirection URI를 함께 전달하도록 합니다.

 

C: Authorization Server가 Authorization Code를 발급합니다. 이를 통해서 Client는 Authorization만을 위임받습니다. -> OAuth 2.0 핵심

 

D: Client는 위임받은 Authorization으로 Access Token을 발급받습니다. 이 과정은 Redirection을 이용하여 이루어집니다. 이때 Redirection URI는 기존에 Authorization Server와 합의된 Redirection URI와 동일해야 합니다.

 

E: Authorization Server가 Access Token (Refresh Token은 옵션)을 발급합니다.

 

Redirect URI에 대한 생각 차이가 왜 생기는가?

 

이제 OAuth 2.0 시퀀스를 이해했기 때문에 좀 더 심화 주제로 진행할 준비가 되었습니다.

 

위의 시퀀스만 보면 어려울 게 없는데요.

 

그런데 왜 Redirect URI가 프론트엔드여야 하는지, 백엔드여야 하는지에 대한 생각 차이가 생길까요?

 

그것은 Client에 대해서 명확하게 정의되어 있지 않기 때문입니다.

 

   client
      An application making protected resource requests on behalf of the
      resource owner and with its authorization.  The term "client" does
      not imply any particular implementation characteristics (e.g.,
      whether the application executes on a server, a desktop, or other
      devices).

 

RFC 6749 문서에서 정의하는 액터 항목에서 Client 부분을 보면 위와 같은데요.

 

The term "client" does not imply any particular implementation characteristics (e.g., whether the applicaiton executes on a server, a desktop, or other devices).

이 부분을 보면, RFC 6749에서는 Client의 구현에 대해서 제한을 두고 있지 않습니다.

 

그러니까 OAuth 2.0에서, 그리고 OAuth 2.0을 기반으로 하는 OIDC에서도 Client에 대한 구체적인 사항은 정의하고 있지 않은 것입니다.

 

이건 RFC 6749에서 Client 구현에 대한 자유도를 주는 것이죠.

 

그래서 결론부터 말하면, Client의 Redirect URI는 백엔드여도 프론트엔드여도 무관합니다.

 

이렇게만 결론을 지으면 RFC 6749를 따르기만 하면 되니, 굳이 블로그 글로 쓸 필요는 없겠죠.

 

작업을 진행하면서 아래와 같은 일이 있었습니다.

 

---

 

처음에 MS Entra ID 연동 작업을 진행하기 전에 선배에게 가서, 시퀀스에 대한 설명을 들었고 Redirect URI를 백엔드 엔드포인트로 하라는 말을 들었습니다.

 

(앞에서 언급한 것처럼, 이렇게 작업해도 OAuth 2.0을 준수하는 시퀀스이고 아무 문제 없이 연동됩니다.)

 

그렇지만 저는 작업하면서 Redirect URI가 프론트엔드여야 이치에 맞겠다는 생각이 들었습니다.

 

또 저희 쪽 팀 프론트엔드 분과 작업하는데 자꾸 연동에서 문제가 발생했습니다. (이 부분은 뒤에서 자세히 설명하겠습니다.)

 

그래서 선배한테 가서 "Redirect URI는 프론트엔드가 맞는거 같아요." 라고 이야기를 했습니다.

 

그런데 이 부분은 선배가 정한 게 아니고, 매우 잘하시는 시니어 분께서 여러 이유로 인해서 Redirect URI를 백엔드로 하는 게 더 좋다고 정해주셨다는거에요.

 

여기에 대해서는 크게 세 가지 근거가 있었는데요.

 

  1. 백엔드로 Redirect 하는 게 더 일반적인 시퀀스이다.
  2. Client에서 Authorization Code를 몰라도 되기 때문에 보안상 더 안전하다.
  3. 2번과 비슷하게, Client에서는 Access Token을 몰라야 보안상 더 안전하다.

 

그런데 이것에 대해서 아무리 고민해봐도 저는 맞지 않다고 생각이 되더라구요.

 

그래서 여러 자료를 깊게 조사하고 이에 대해서 제 나름대로 내린 결론을 공유드리고자 합니다.

 

Redirect URI를 백엔드로 설정하면서 겪었던 문제와 트러블슈팅

 

사실 이 부분은 지나고 보니 이미 잘하시는 분이 봤을 때는 이런 걸로 막힌다고? 또는 왜 이런 시도를 하지? 라고 생각하실 것 같기는 합니다.

 

그래도 제가 겪었던 시퀀스를 따라가면 좀 더 이해하기 쉽지 않을까? 싶어서 공유해봅니다.

 

저희는 프론트엔드로 Next.js, 백엔드로 Spring Boot 스택을 사용하고 있습니다.

 

처음에 제가 선배에게서 전달받은 시퀀스는 다음과 같았습니다. (다소 간결하게 만든 부분이 있습니다.)

 

  1. 프론트엔드에서 MS 로그인 페이지를 띄워준다. (w/ 백엔드 redirect uri)
  2. 로그인에 성공하면 MS 인증서버로부터 브라우저가 302 found를 받고, 자동으로 리다이렉트하면서 백엔드로 authorization code를 전달
  3. 백엔드에서 authorization code를 이용해서 MS에서 access token 발급
    1. 필요한 경우 access token을 이용하여 사용자 정보 획득
  4. 백엔드에서 프론트엔드로 redirect를 걸어서 반환 (w/ url parameter로 자체 발급한 access token 추가)

 

그냥 이 시퀀스대로만 했으면, 문제가 없었을 텐데요.

 

그런데 access token을 url에 포함해서 주는 게 맘에 안 들어서 두 가지를 시도했는데 잘 안되는거에요.

 

  1. 백엔드에서 access token을 response body에 넣어서 Content-Type: application/json으로 반환
  2. 백엔드에서 access token을 response header에 넣어서 반환

결국 계속 시도해보다가 실패하고 기존의 시퀀스대로 url parameter에 access token을 넣어서 redirect 해주니, 그제서야 문제가 해결이 됐습니다.

 

여기에는 SPA가 브라우저와 인터렉션 할 때 생기는 구체적인 상황을 이해해야 하는 부분이 있는데요.

 

그 원인은 결국 'SPA(Javascript)에서 브라우저가 리디렉션으로 인해 생성한 HTTP 요청/응답을 조작할 수 없다'에 있습니다.

 

  1. Javascript에서 사용자에게 로그인 요구
    1. 로그인은 성공했다고 가정
  2. 로그인이 성공하면, Authorization Server는 사전 합의된 Redirect URI로 브라우저를 리다이렉트
    1. 만약 Redirect URI가 사전에 주어진 것과 다르면 에러 발생
  3. 브라우저는 HTTP Status Code 300번대를 받으면, 기존 요청은 끝내고 Location 헤더에 주어진 위치로 새로운 HTTP 요청

 

브라우저에서 새로 시작한 HTTP 요청은 JS의 제어 흐름을 타지 않고, HTTP 규격에 근거한 브라우저 자체 동작이므로 JS에서 이 요청에 대한 조작이 불가능합니다.

 

언뜻 보기엔 복잡하지만, 생각해보면 당연한 것입니다.

 

HTTP 요청은 client와 server간 handshake를 해서 이루어지는 통신인데, redirect 된 곳이 다른 ip를 가지고 있을 수도 있으니 브라우저에서 Location 헤더를 보고 새로운 요청을 하는 것이 이치에 맞습니다.

 

그리고 이 요청은 XMLHttpRequest fetch 같은 JS API를 이용해서 이루어진 것이 아니므로, JS 제어 흐름에서 벗어나 있습니다.

 

그러므로 Web Application에서는 이러한 흐름에 대해서 알지 못하므로 URL만 알 수 있고, 그래서 URL Parameter로 달아줘야 Web Application이 가져다 쓸 수 있는 것입니다.

Redirect URI가 백엔드여야 한다고 생각하는 입장에 대해서

 

위에서 논의한 것에 기반하여 생각해보면, Redirect URI가 백엔드여야 한다고 생각하는 근거 중 2번과 3번이 말이 되긴 합니다.

 

  1. 백엔드로 Redirect 하는 게 더 일반적인 시퀀스이다. -> 이 부분은 뒤에서 더 다루겠습니다.
  2. 프론트엔드에서 Authorization Code를 몰라도 되기 때문에 보안상 더 안전하다. -> HTTP 규격에 의한 동작이므로 프론트엔드의 제어 흐름에서 벗어납니다. 따라서 프론트엔드는 백엔드로 가는 요청에 대해서 모르고, url을 조회해서 오직 token 요청 결과만 받아볼 수 있습니다.
  3. 2번과 비슷하게, 프론트엔드에서는 Access Token을 몰라야 보안상 더 안전하다. -> 백엔드로 redirect 되므로, 백엔드에서 Authorization Server와의 모든 인터렉션을 처리합니다. 따라서 이 경우에도 프론트엔드에서는 Access Token을 모르게 됩니다.

그렇지만 이 시퀀스에서 access token을 url parameter에 붙여서 나가는 게 계속 마음에 걸렸습니다.

 

TLS/SSL을 적용한 HTTPS 프로토콜에서는 url parameter를 도감청하는 것이 사실상 어렵다고는 합니다.

일반적인 트랜잭션 수준에서는 HTTPS 프로토콜을 준수하면 사실상 안전하다고 봐도 무관합니다.

 

그럼에도 불구하고 민감한 정보는 url에 남기지 않고 최대한 body나 header에 넣는 게 좋고, 추가적으로 암호화를 적용하거나 JWE같은 규격을 따르는 게 좋다고 생각이 됩니다.

 

왜냐면 url에 access token이 포함되어 있으면, 이 url 자체가 브라우저나, 프록시 서버나, nginx 같은 웹 서버 등의 로그에 그대로 남거나 할 수 있으니까요.

 

그리고 결국은 'JS 단에서 access token을 알아야 resource server에 요청을 보낼 수 있다' 는 부분이 계속 마음에 걸렸습니다.

 

프론트엔드를 우회해서 브라우저에서 백엔드에서 토큰을 직접 받아왔다고 하더라도, 결국 프론트엔드가 Access Token을 알아야 resource server에 요청을 보낼 수 있습니다.

 

그러면 결국 웹 브라우저라고 가정하면 JS 단에서 access token 값을 로컬 스토리지 등에 저장을 해야 합니다.

 

JS가 access token 값을 알아야 클라이언트가 동작할 수 있으면 브라우저 단에서 따로 요청해서 받아올 이유가 있나? 하는 생각이 들었습니다.

 

결국 access token 값을 JS가 알아야 하면 굳이 브라우저 통해서 요청 안하고, JS 단에서 POST 등의 요청을 이용해서 body로 받아오면 추가적인 암호화 과정 등도 넣을 수 있고, 그러면 HTTPS + 추가적인 보안 조치가 되는거니까 차라리 그게 더 안전하지 않을까요?

 

Redirect URI가 프론트엔드여야 한다고 생각하는 입장에 대해서

 

그래서 저는 Redirect URI가 프론트엔드여야 한다고 생각하게 되었습니다.

 

어차피 백엔드로 redirect 해야 한다는 입장에서 프론트엔드에서 access token을 모르는게 좋다고 하지만, 결국 요청을 하기 위해선 access token을 알아야 하니까요.

 

이에 대해서는 'MS Entra ID 등 서드파티에서 발급한 authorization code와 access token으로는 이와 연계된 여러 정보나 다른 애플리케이션에 영향을 미칠 수 있으므로, 프론트엔드에서는 모르는 게 낫다' 고 이야기 할 수도 있겠지만요.

 

또는 '백엔드는 프론트엔드를 신뢰하면 안된다' 같은 일반론을 얘기하는 경우도 있었습니다.

 

그렇지만 이 부분도 동의할 수 없었습니다.

 

일단 브라우저에서 직접 호출하든, JS의 XMLHttpRequest fetch 같은 API를 통해서 호출하든 보안 부분은 HTTPS의 TLS/SSL에 의존하고 있습니다.

 

둘의 보안 수준은 전혀 다르지 않습니다.

 

authorization code에 대해서 프론트엔드에서 모르면 더 좋을 수는 있겠지만, authorization code의 유효기간은 매우 짧고 이걸 로컬 스토리지 등에 보관하는 코드 관행은 실질적인 보안 위협이라기보다 보안 가이드를 적절히 따르지 않은 경우라고 생각됩니다.

 

어떤 아키텍처나 시퀀스 설계를 충실히 따랐는데 보안 위협이 있는 경우가 아니라면, 이 부분을 지적하는 건 적절하지 않다고 생각합니다.

 

RSA private key를 public하게 노출한 경우가 존재한다고 해서 RSA 알고리즘 자체가 보안에 취약한 알고리즘은 아니잖아요.

 

또한 authorization code는 외부에 노출되더라도 client secret을 모르면 사용할 수 없기 때문에 이것이 노출되어도 아주 큰 보안 위협은 아닙니다. (PKCE 등을 도입하는 경우에는 더 그렇습니다.)

 

그러면 결국 브라우저에서 GET 요청을 해서 url 파라미터로 받을 거냐, JS 단에서 POST 요청을 해서 body 또는 header로 받을거냐인데요.

 

저는 이 중에 고르라면 압도적으로 후자를 선호합니다.

 

게다가 url에 access token을 노출하는 경우는 그게 어떤 경우든 간에 권장되지 않는 패턴입니다.

 

아직 draft긴 합니다만, 아래의 문서를 봐주시면 좀 더 이해가 쉬울 것 같아요.

 

https://www.ietf.org/archive/id/draft-ietf-oauth-security-topics-15.txt

 

그러나 계속 조사하면서 또 새로운 사실을 알게 되었는데요.

 

다시 처음의 결론으로: 프론트엔드와 백엔드 모두 상관없다

 

만약에 백엔드로 redirect 하는 것의 이치가 맞으려면, 프론트엔드에서 access token 값을 아예 안 들고 있어야 합니다.

 

그런데 이게 가능할까요?

 

어떤 경우에는 이게 가능하고, 사실 이게 더 권장되는 패턴입니다.

 

백엔드에서 웹페이지에 대한 모든 로직을 들고 있고, 브라우저는 정적 리소스만 제공하는 경우입니다.

 

Java의 JSP 같은 경우를 생각해보면, 백엔드가 웹페이지에 대한 모든 책임을 갖고 있으므로 백엔드로 redirect 하면 세션별로 access token을 매칭시켜놓고요.

 

이후에 들어온 요청에 대해서 세션에 매칭된 access token이 있으면 정상 응답을 주고 없으면 login 페이지로 redirect 시키면 됩니다.

 

Spring 기준으로 말씀드리면, Tomcat에서 발급한 JSESSIONID로 요청을 구분하고 처리하면 되겠습니다. (물론 이 경우에는 CSRF 방지 조치가 필요합니다.)

 

그러면 프론트엔드(물론 프론트엔드라는 말이 여기선 좀 어색하긴 합니다만)에서는 아무것도 몰라도 안전하게 인증/인가가 진행되게 됩니다.

 

과거에는 이런 식의 서비스 제공을 많이 했었죠.

 

그래서 다시 백엔드로 redirect 해야 하는 경우의 근거를 살펴보면요.

 

  1. 백엔드로 Redirect 하는 게 더 일반적인 시퀀스이다. -> 프론트엔드를 따로 구성하지 않는 경우에 대해서 사실입니다. 1~3번 모두요.
  2. 프론트엔드에서 Authorization Code를 몰라도 되기 때문에 보안상 더 안전하다. -> HTTP 규격에 의한 동작이므로 프론트엔드의 제어 흐름에서 벗어납니다. 따라서 프론트엔드는 백엔드로 가는 요청에 대해서 모르고, url을 조회해서 오직 token 요청 결과만 받아볼 수 있습니다.
  3. 2번과 비슷하게, 프론트엔드에서는 Access Token을 몰라야 보안상 더 안전하다. -> 백엔드로 redirect 되므로, 백엔드에서 Authorization Server와의 모든 인터렉션을 처리합니다. 따라서 이 경우에도 프론트엔드에서는 Access Token을 모르게 됩니다.

2번과 3번에 대해서는 지속적으로 변경되는 JESSIONID와 CSRF 방지 토큰만 값이 맞으면 요청을 허용하면서 서버에서 모든 토큰 값을 직접 관리하면 됩니다.

 

그러면 이제 백엔드 쪽으로 redirect 해야 하는 이유에 대해서 모두 이해할 수 있게 됩니다.

 

다만, 이 경우에 프론트엔드라는 말을 쓰는게 조금 어색해지기는 하죠.

 

프론트엔드라는 말을 사용해서 더 혼동이 오는 것 같기는 합니다.

 

왜냐면 보통은 프론트엔드라고 하면, 백엔드에서는 CRUD 동작을 기초로 하는 REST API를 제공하고 웹 브라우저에서 여러 로직을 제공하는 React, Next.js 같은 SPA를 떠올리니까요.

 

그런데 만약에 React, Next.js 같은 SPA를 사용하게 되면 프론트엔드에서 결국은 access token을 들고 여러 백엔드 API를 호출하면서 서비스를 제공해야 합니다.

 

이 경우에는 백엔드로 redirect 해야 하는 이유가 모두 사라지게 됩니다.

 

왜냐면 기존 웹 애플리케이션에서는 세션 관리가 일반적이어서 브라우저에서 시크릿 값을 하나도 들고 있지 않아도 됐는데, SPA에서는 세션 관리 대신에 JWT 등을 이용해서 REST API에 접근하는 게 일반적이기 때문입니다.

 

따라서 백엔드에서 유저 상태 관리를 하지 않게 되면서 결국 SPA가 access token을 들고 있어야 하구요. 추가적으로 백엔드에서 CSRF 검증도 불필요하게 됩니다. (모든 요청이 stateless하고, JWT 토큰 등으로 유효성이 확인됨)

 

여기에 대해서 MS에서 정리해준 페이지가 있는데요.

 

 

실제로 MS에서는 다음과 같이 '대부분의 애플리케이션 로직이 서버에서 수행되는 기존 웹 애플리케이션'은 redirect uri를 웹, 그러니까 백엔드에서 받으라고 권장하고 있구요.

 

'주로 웹 API를 사용하여 웹 서버와 통신하는 웹 브라우저에서 대부분의 사용자 인터페이스 로직이 수행되는 단일 페이지 애플리케이션' 그러니까 우리가 주로 SPA라고 부르는 애플리케이션에서는 SPA의 엔드포인트로 redirect uri를 지정하라고 권장하고 있습니다.

 

더 자세한 내용은 아래 링크를 참고해주세요.

https://learn.microsoft.com/ko-kr/entra/identity-platform/reply-url?utm_source=chatgpt.com

 

나가며: 나는 왜 헷갈렸을까?

사실 위에 있는 MS 글을 빨리 봤더라면, 그냥 바로 보고 이해했을텐데 왜 이렇게까지 헤맸을까? 그런 생각을 하게 되더라구요.

 

그리고 돌이켜보니 그건, 제가 '대부분의 애플리케이션 로직이 서버에서 수행되는 기존 웹 애플리케이션'을 진지하게 만들어 본 적이 없어서 그랬습니다.

 

당연하게 CRUD 기반의 REST API를 제공하는 백엔드 서버나 만들어봤지, JSP 같은 건 예제 페이지 만들 때나 해봤거든요.

 

세션 기반으로 유저관리하는 로직도 만들어봤습니다만, 인증/인가 로직은 JWT로 하고 세션 관리가 필요한 부분만 따로 관리한다든지 하는게 대부분이었습니다.

 

세션으로 로그인 관리한다는 거 자체가 좀 낯설고, 결국 사용자와 가까이 있는 로직 자체를 많이 작성을 안해봤던거라고 생각이 됩니다.

 

회사에서 일 할 때나, 사이드 프로젝트 할 때나 다 프론트 담당해주신 분들이 있었구요.

 

결론적으로 SPA 기반의 프론트엔드와, REST API 기반의 백엔드로 확실하게 역할이 나뉘어진 경우에 너무 익숙해져 있었다고 할 수 있겠습니다.

 

시니어 분들은 기존 웹 애플리케이션 로직에도 익숙하니 당연히 redirect uri는 백엔드로 해야된다고 생각하셨을 듯 합니다.

 

'프론트엔드를 신뢰하지 말라'는 관념에서 나온 관성도 있었을 듯 하구요.

 

그렇지만 약속된 규격이 허용하는 한에서는 실용적인 방법을 계속 찾아가고, 모든 개발을 글로벌 스탠다드에 맞춰서 하는 게 좋다고 생각합니다.

 

그런 의미에서 redirect uri를 백엔드로 해야만 한다거나, 프론트엔드로 해야만 한다고 생각할 필요는 없습니다.

 

상황에 맞게 가면 되는 것 같아요.

 

이 과정에서 RFC 문서도 정독하고, 각 액터에 대해서 깊게 고민하면서 OAuth 2.0에 대해서 제가 헷갈리게 될 일은 없을 듯 합니다.

 

여러모로 느낀 점이 많은 그런 토픽이었습니다.

 

이 글을 읽으시는 분들은 OAuth 2.0의 컨셉을 정확하게 이해하시고, 효율적이면서 보안 취약점이 없는 애플리케이션을 간단하게 구성하시길 바랍니다.

'개발 - Coding > Backend' 카테고리의 다른 글

OpenTelemetry 1편 - 개요  (2) 2024.09.16