OIDC - Spring Security OAuth2 Client (실전 설정)

Elena·2026년 2월 12일
post-thumbnail

지금까지 수동으로 코드를 짜며 배웠던 Authorization Code 교환, JWKS 조회, ID Token 검증 등의 복잡한 과정을 Spring Security는 단 몇 줄의 설정으로 자동화 해준다.

1. 프로젝트 설정

build.gradle

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
    implementation 'org.springframework.boot:spring-boot-starter-security'
    implementation 'org.springframework.boot:spring-boot-starter-web'
}

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

2. 핵심 설정

application.yml

spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: ${GOOGLE_CLIENT_ID}
            client-secret: ${GOOGLE_CLIENT_SECRET}
            scope:
              - openid
              - profile
              - email
        provider:
          google:
            # Tip: issuer-uri만 적으면 스프링이 /.well-known/...을 자동으로 호출해 모든 정보를 가져옴
            issuer-uri: https://accounts.google.com

application.properties

# Google OAuth2 Registration
spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID}
spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET}
spring.security.oauth2.client.registration.google.scope=openid,profile,email

# Google OAuth2 Provider
spring.security.oauth2.client.provider.google.issuer-uri=https://accounts.google.com

3. Security Config 설정

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/", "/login/**").permitAll()
                .anyRequest().authenticated()
            )
            .oauth2Login(oauth2 -> oauth2
                // 로그인 성공 후 후처리 로직을 담당할 서비스 등록
                .userInfoEndpoint(userInfo -> userInfo.userService(customOAuth2UserService()))
            );
        
        return http.build();
    }
}

4. 백엔드 개발자가 구현해야 할 로직은?

스프링이 인증을 다 해주더라도, 인증된 사용자 정보를 나의 서비스의 DB에 저장하거나 추가 권한을 부여하는 작업을 해야함

@Service
public class CustomOAuth2UserService extends OidcUserService {

    @Override
    public OidcUser loadUser(OidcUserRequest userRequest) 
    	throws OAuth2AuthenticationException 
   {
        // 1. 스프링이 이미 검증 완료한 OIDC 사용자 정보를 가져옴
        OidcUser oidcUser = super.loadUser(userRequest);
        
        // 2. ID Token의 클레임들을 확인 (sub, email 등)
        String email = oidcUser.getEmail();
        String name = oidcUser.getFullName();
        String registrationId = userRequest.getClientRegistration()
        						.getRegistrationId(); // "google"

        // 3. DB 저장 또는 업데이트 로직 (나의 서비스 회원가입 처리)
        // User user = userRepository.findByEmail(email)
        //              .orElseGet(() -> userRepository.save(new User(name, email, registrationId)));

        return oidcUser;
    }
}

내가 news-summary 프로젝트에서 썼던 OAuth2.0과 OIDC의 다른 점은 무엇일까?

  1. scope에 openid가 없음
"&scope=profile email"

-> OIDC를 사용하려면 반드시 scope에 openid라는 값이 들어가야 한다. 나의 요청문에는 profile과 email만 포함되어 있으므로, 구글은 이를 "사용자 정보에 접근할 권한을 얻으려는 OAuth 2.0 요청"으로 인식

  1. ID Token을 받지 않음
Map<String, Object> tokenResponse = resp.getBody();
// ...
return (String) tokenResponse.get("access_token");

-> OIDC 방식이라면 구글은 access_token과 함께 id_token을 준다. 하지만 내 코드는 오직 access_token만 꺼내서 사용하고 있다.

  1. 사용자 정보를 따로 요청함 (requestGoogleUserInfo)
private Map<String, Object> requestGoogleUserInfo(String accessToken) {
    // ...
    headers.setBearerAuth(accessToken);
    ResponseEntity<Map<String, Object>> resp = restTemplate.exchange(GOOGLE_USERINFO_URL, ...);
}

-> 이 부분이 가장 결정적인 차이

  • OAuth 2.0 방식: Access Token을 들고 다시 구글의 API 서버(UserInfo API)에 "이 열쇠 줄 테니까 프로필 정보 좀 줘"라고 한 번 더 물어본다 (현재 나의 방식)

  • OIDC 방식: 앞 단계에서 이미 ID Token이라는 신분증을 받았기 때문에, 이 단계 자체가 필요 없음. 토큰만 뜯으면 그 안에 이름과 이메일이 다 들어있다.

profile
一切唯心造

0개의 댓글