keycloak

keycloak 구글/네이버 로그인

몽게구름 2025. 12. 7. 22:01

버전 : keycloak:26.4.7

 

구글 연동 로그인은 간단하다.

https://console.cloud.google.com/apis/dashboard

 

Google 클라우드 플랫폼

로그인 Google 클라우드 플랫폼으로 이동

accounts.google.com

 

에서 프로젝트 및 client id  secret 을 발급 받습니다. 이 부분은 구글링을 참조 합니다.

 

 

 

keycloak에 들어가서

Identity providers -> add provider -> google 을 클릭 합니다.

 

Client ID : 발급 받은 ID

Client Secret : 발급 받은 시크릿 키

Redirect URI -> 구글 클라우드 플랫폼에 등록을 합니다.

 

 

2. NAVER 로그인

 처음 Keycloak을 24버전을 받으니 oauth2가 없어서

spi로 작업을 진행 하려고 하였으나 이 부분도 spi-server:24 버전일 경우 ocid를 사용할수가 없다고 나와있었습니다.

그래서 26.4.7 버전으로 oauth2를 제공하는 버전으로 올려서 작업을 진행했습니다.

버전이 낮은 경우 구글링을 통해 작업을 진행 하시면 되고

저는 26.4.7 버전 기점으로 정리를 하였습니다.

 

oauthv2를 클릭 

 

 

 

Authorization URL : https://nid.naver.com/oauth2.0/authorize

Token URL : https://nid.naver.com/oauth2.0/token

User Info URL : http://localhost:1111/~/~

Client ID : 네이버에서 발급 받은 ID

Client Secret : 네이버에서 발급 받은 Secret

 

OAuth2 settings 

Use discovery endpoint -> off

 

ID Claim : id

Username Claim : id

Email Claim : email

 

이렇게 작업을 진행 합니다.

Redirect URI 는 구글과 동일하게 네이버 API 사이트에 Callback에 적어 줍니다.

 

여기서 User Info URL 을 왜 로컬로 했는가?..

https://openapi.naver.com/v1/nid/me

keycloak에서 네이버 url 호출 시에

java.lang.RuntimeException: No identifier provider for identity.
        at org.keycloak.broker.provider.BrokeredIdentityContext.<init>(BrokeredIdentityContext.java:58)
        at org.keycloak.authentication.authenticators.broker.util.SerializedBrokeredIdentityContext.deserialize(SerializedBrokeredIdentityContext.java:274)
        at org.keycloak.services.resources.LoginActionsService.brokerLoginFlow(LoginActionsService.java:902)
        at org.keycloak.services.resources.LoginActionsService.firstBrokerLoginGet(LoginActionsService.java:841)
        at org.keycloak.services.resources.LoginActionsService$quarkusrestinvoker$firstBrokerLoginGet_8353b960487f493f608861c3c713f082b792516d.invoke(Unknown Source)
        at org.jboss.resteasy.reactive.server.handlers.InvocationHandler.handle(InvocationHandler.java:29)
        at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:183)
        at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:147)
        at io.quarkus.vertx.core.runtime.VertxCoreRecorder$15.runWith(VertxCoreRecorder.java:645)
        at org.jboss.threads.EnhancedQueueExecutor$Task.doRunWith(EnhancedQueueExecutor.java:2651)
        at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2630)
        at org.jboss.threads.EnhancedQueueExecutor.runThreadBody(EnhancedQueueExecutor.java:1622)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1589)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:11)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:11)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:1583)

 

No identifier provider for identity 라고 오류가 나옵니다.

이 부분이 

naver에서 내려주는 JSON 을 keycloak에서 변환할때 값이 맞지 않아서 id,name 등등을 찾지 못하는 에러 입니다.

그래서 내 서버에 proxy 서버를 거친 후에 네이버 를 호출 하는 형식으로 수정을 진행 해주어야 합니다.

 

 

implementation 'org.springframework.boot:spring-boot-starter-webflux'

 

package com.mockio.auth_service.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.util.LinkedHashMap;
import java.util.Map;

@RestController
public class NaverUserInfoProxyController {

    private final WebClient webClient;

    public NaverUserInfoProxyController(WebClient.Builder builder) {
        this.webClient = builder
                .baseUrl("https://openapi.naver.com")
                .build();
    }

    @GetMapping("/naver/userinfo")
    public Mono<Map<String, Object>> userInfo(@RequestHeader(HttpHeaders.AUTHORIZATION) String authorization) {
        // Keycloak → 서버로 들어온 Authorization: Bearer {accessToken}
        // → 이걸 그대로 네이버 userinfo 에 전달
        return webClient.get()
                .uri("/v1/nid/me")
                .header(HttpHeaders.AUTHORIZATION, authorization)
                .retrieve()
                .bodyToMono(Map.class)
                .map(this::flattenResponse);
    }

    /**
     * 네이버 응답:
     * {
     *   "resultcode": "00",
     *   "message": "success",
     *   "response": { ... 실제 데이터 ... }
     * }
     *
     * → 아래처럼 평탄화해서 Keycloak 에 전달:
     * {
     *   "id": "...",
     *   "email": "...",
     *   "name": "...",
     *   "nickname": "..."
     * }
     */
    @SuppressWarnings("unchecked")
    private Map<String, Object> flattenResponse(Map<String, Object> original) {
        Object responseObj = original.get("response");

        Map<String, Object> response = responseObj instanceof Map
                ? (Map<String, Object>) responseObj
                : Map.of();

        Map<String, Object> result = new LinkedHashMap<>();
        result.put("id",        response.get("id"));
        result.put("email",     response.get("email"));
        result.put("name",      response.get("name"));
        result.put("nickname",  response.get("nickname"));

        return result;
    }
}

 

 

이렇게 값을 변경 해주면 정상적으로 오류가 나지 않고 네이버 로그인이 진행 됩니다.

 

※ 이번 주말 keycloak을 이용해서 로그인,회원가입,비밀번호 변경, 네이버 로그인 등 을 진행 하였는데

예전에는 jwt , refresh-token 등등 신경을 많이 써야 하는 작업을 내가 하지 않고

오픈 소스를 통해 작업을 진행하니 편한거 같지만 아직 적응이 되지 않아 많은 시행착오가 있습니다.

그래도 jwt 등 처음부터 작업을 해보고 keycloak 을 사용 해보니  모든 유효성도 다 keycloak에 처리...

참 편하다고 생각이 듭니다.

'keycloak' 카테고리의 다른 글

keycloak - 커스텀 회원가입  (0) 2025.12.06
[keycloak] 로그인 화면 꾸미기  (0) 2025.12.06