Programming-[Backend]/Keycloak

[TIL] Keycloak logout

컴퓨터 탐험가 찰리 2024. 9. 9. 16:42
728x90
반응형

 

Ref.) https://developers.redhat.com/articles/2022/12/07/how-implement-single-sign-out-keycloak-spring-boot#single_sign_on_and_single_sign_out

 

 

 


1. front vs back

 

back channel 방식이 front channel 방식에 비해 더 간소하다

back channel 방식은 browser가 반드시 필요하지 않다.

 

1.1 Back channel 작동방식

(Single Sign On으로 여러 client에 로그인이 되어있는 상황이라 가정)

각 client에 logout endpoint를 만들어놓는다.

1개의 client에서 logout 후 keycloak에 logout을 알린다.

keycloak은 세션을 보고, 유저가 로그인되어 있는 모든 클라이언트의 logout endpoint로 요청을 보낸다.

 

 

 

1.2 Front channel 작동 방식

Front channel 방식의 경우, user가 직접 keycloak의 logout 페이지에 접근하도록 하여 logout 버튼을 누르게 한다. 이를 위해 browser가 필요하다.

참조 글에서는 back channel 방식만 다루는데, front channel 방식의 경우 user가 keycloak의 logout 페이지에 접근하는 것을 browser가 막을 수도 있기 때문이다.

 

 

 

2. 구현

 

logout 구현은 간단하다. Keycloak에서 제공하는 OIDC 표준 스펙의 logout endpoint로 post 요청을 보내면 된다. 이 때 로그아웃 후 돌아갈 redirect_uri와 어떤 client, 사용자에 대해 로그아웃을 할지를 결정하기 위한 client_id, refresh_token을 보내면 된다.

 

대략 아래처럼 코드를 작성하여 보내면 된다!

 

//...생략

static final String OIDC_AUTH_SUFFIX_LOGOUT = "/protocol/openid-connect/logout";


//...중략

RestTemplate restTemplate = new RestTemplate();
String logoutEndpoint = KEYCLOAK_URL + realmId + OIDC_AUTH_SUFFIX_LOGOUT;

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

StringBuilder bodyBuilder = new StringBuilder();
bodyBuilder.append("redirect_uri=").append(URLEncoder.encode(logoutPayload.getRedirectUri(),
    StandardCharsets.UTF_8));
bodyBuilder.append("&refresh_token=").append(URLEncoder.encode(logoutPayload.getRefreshToken(),
    StandardCharsets.UTF_8));

String clientId = logoutPayload.getClientId();
if (clientId != null && !clientId.isEmpty()) {
  bodyBuilder.append("&client_id=").append(URLEncoder.encode(clientId, StandardCharsets.UTF_8));
}

String body = bodyBuilder.toString();
HttpEntity<String> requestEntity = new HttpEntity<>(body, headers);
ResponseEntity<?> response = restTemplate.exchange(
    logoutEndpoint, HttpMethod.POST, requestEntity, String.class);

return ResponseEntity.ok().body(response.getBody());

 

728x90
반응형