OIDC UserInfo 엔드포인트의 역할과 구현 메커니즘
1. UserInfo 엔드포인트의 필요성
OAuth2 인증 흐름에서 클라이언트는 두 가지 토큰을 수신합니다:| 토큰 종류 | 용도 | 주요 특징 |
|---|---|---|
| Access Token | 리소스 서버 접근용 | 사용자 식별자만 포함 |
| ID Token | 신원 확인용 | JWT 형식의 사용자 정보 포함 |
/userinfo 엔드포인트는 다음과 같은 핵심 역할을 수행합니다:
- 실시간 사용자 정보 제공
- 클라이언트의 스코프 기반 데이터 필터링
- 단기 유효 ID 토큰의 보완
2. ID 토큰과 UserInfo 엔드포인트 비교
┌──────────────────────┬────────────────────────┐ │ ID Token 특성 │ UserInfo 엔드포인트 특성 │ ├──────────────────────┼────────────────────────┤ │ 단회성, 짧은 유효기간 │ 실시간 정보 제공 가능 │ │ 정적 클레임 정보 │ 동적 사용자 상태 반영 │ │ 민감 정보 포함 가능성 │ 스코프 기반 필터링 지원 │ └──────────────────────┴────────────────────────┘
3. Spring Security 구현 분석
3.1 엔드포인트 처리 흐름
- Bearer 토큰 포함한
GET /userinfo요청 수신 OidcUserInfoEndpointFilter의 토큰 검증- Redis를 통한 인증 정보 검색:
- 액세스 토큰 → 인증 ID 매핑 조회
- 인증 ID →
OAuth2Authorization객체 복원
- ID 토큰 클레임 추출 및 스코프 기반 필터링
- JSON 응답 생성 및 반환
3.2 주요 코드 구조
// 커스텀 토큰 생성기 구현
@Bean
public OAuth2TokenCustomizer<JwtEncodingContext> customJwtTokenCustomizer() {
return context -> {
if ("id_token".equals(context.getTokenType().getValue())) {
Authentication auth = context.getPrincipal();
if (auth.getPrincipal() instanceof CustomUser user) {
Map<String, Object> claims = context.getClaims().build();
// 필수 클레임 설정
claims.put("sub", user.getId());
claims.put("name", user.getDisplayName());
// 스코프 기반 선택적 클레임 추가
Set<String> scopes = context.getAuthorizedScopes();
if (scopes.contains("email")) {
claims.put("email", user.getEmail());
claims.put("email_verified", true);
}
}
}
};
}
4. 흔한 문제와 해결 방법
4.1 클레임 누락 문제
원인: ID 토큰의 필수 클레임(sub) 삭제
해결: 엑세스 토큰 커스터마이징 시 OIDC 필수 클레임 보존
4.2 사용자 정보 확장
스코프 기반 클레임 동적 추가 예시:
private void addScopedClaims(Map<String, Object> claims, CustomUser user, Set<String> scopes) {
if (scopes.contains("profile")) {
claims.put("given_name", user.getFirstName());
claims.put("family_name", user.getLastName());
}
if (scopes.contains("phone")) {
claims.put("phone_number", user.getMobile());
}
}
5. 최적의 사용 사례
| 사용 시나리오 | 권장 방식 |
|---|---|
| 모바일 앱 | ID 토큰만 사용 |
| 실시간 데이터 요구 시스템 | UserInfo 엔드포인트 우선 |
| 민감 정보 관리 | UserInfo 엔드포인트 + 스코프 제어 |