contexa-identity

상태 관리

인증 후 상태 관리 전략입니다. Session(서버 메모리/Redis) 또는 OAuth2(JWT Stateless) 중 선택할 수 있습니다. 각 인증 방식은 서로 다른 상태로 독립적으로 구성할 수 있습니다.

개요

DSL에서 인증 방식 뒤에 .session() 또는 .oauth2()를 호출하여 상태를 구성합니다. AbstractFlowRegistrar.StateSetter는 가장 최근에 추가된 플로우에 상태를 적용합니다.

registry
    .form(f -> f.loginPage("/login"))
    .session(Customizer.withDefaults())      // form -> Session

    .rest(r -> r.loginProcessingUrl("/api/auth"))
    .oauth2(Customizer.withDefaults())        // rest -> OAuth2

    .mfa(m -> m.primaryAuthentication(...).passkey(...))
    .session(Customizer.withDefaults())        // mfa -> Session

    .build();

Session vs OAuth2 비교

항목SessionOAuth2
상태 저장소기본은 서버 메모리이며, 분산 배포에서는 Redis 기반 공유 저장소를 선택적으로 사용할 수 있음JWT 토큰 (Stateless)
적합한 용도전통적인 웹 앱, SSRSPA, API, 마이크로서비스
확장성기본적으로는 인메모리 세션 상태로 동작하며, 다중 인스턴스 공유가 필요할 때 Redis 연동을 선택할 수 있습니다Stateless (수평 확장 용이)
내장 보안세션 고정 공격 보호 (sessionFixation().changeSessionId())JWT + OIDC + Zero Trust Filter
CSRF필수 (쿠키 기반)불필요 (토큰 기반)
로그아웃세션 무효화 + 쿠키 삭제CompositeLogoutHandlerDeviceAwareOAuth2AuthorizationService를 통한 인가 정보 무효화

Session 기반

.session(Customizer.withDefaults())로 구성합니다. 전통적인 웹 애플리케이션 및 서버 사이드 렌더링에 적합합니다.

자동 적용 항목

  • sessionFixation().changeSessionId() -- 세션 고정 공격 보호
  • 로그아웃 시 세션 무효화 + 쿠키 삭제
  • CompositeLogoutHandler 통합 (Strategy 패턴)

rawHttp를 통한 추가 구성

.form(f -> f
    .rawHttp(http -> http.sessionManagement(s -> s
        .maximumSessions(1)
        .maxSessionsPreventsLogin(true)))
)
.session(Customizer.withDefaults())

OAuth2 기반

.oauth2(Customizer.withDefaults())로 구성합니다. SPA, 마이크로서비스, API 서버에 적합합니다.

자동 적용 항목

  • Resource Server: JWT 인증 컨버터, 인증 실패/접근 거부 핸들러, SessionCreationPolicy.STATELESS
  • Authorization Server: AuthorizationService, ClientRepository, 토큰 엔드포인트, authenticated_user grant type, OIDC 지원
  • OAuth2 CSRF: spring.auth.oauth2-csrf 설정으로 제어

authenticated_user Grant Type

Identity 인증(Form, REST, MFA)을 완료한 사용자에게 OAuth2 토큰을 발급하는 커스텀 grant type입니다. 전통적인 인증과 OAuth2 토큰 발급을 연결하는 브릿지 역할을 합니다.


  authenticated_user Grant Flow
  ===============================

  [Form/REST/MFA Authentication Complete]
           |
           v
  [AuthenticatedUserGrantAuthenticationProvider]
           |
           +-- Client Verification
           +-- User Lookup (UserRepository)
           +-- Scope Resolution
           +-- Access Token Generation (JWT)
           +-- Refresh Token Generation (optional)
           +-- Authorization Persistence (transactional)
           |
           v
  [JWT Token Issuance Complete]

설정 속성

AuthContextProperties (spring.auth.*)의 핵심 설정입니다.

핵심 설정 (spring.auth.*)

속성타입기본값설명
state-typeenumOAUTH2인증 상태 타입 (OAUTH2, SESSION)
token-transport-typeenumHEADER토큰 전송 방식 (HEADER, COOKIE, HEADER_COOKIE)
token-issuerenumINTERNAL토큰 발급자 (INTERNAL, AUTHORIZATION_SERVER)
factor-selection-typeenumSELECTMFA 인증 요소 선택 전략
access-token-validitylong (ms)3600000 (1시간)Access 토큰 유효 기간
refresh-token-validitylong (ms)604800000 (7일)Refresh 토큰 유효 기간
refresh-rotate-thresholdlong (ms)43200000 (12시간)Refresh 토큰 회전 임계값
enable-refresh-tokenbooleantrueRefresh 토큰 활성화
allow-multiple-loginsbooleanfalse동시 다중 로그인 허용
max-concurrent-loginsint3최대 동시 로그인 수
cookie-securebooleantrueCookie Secure 플래그
token-persistenceString"memory"생성된 로그인/MFA 페이지와 SDK에 전달되는 기본 토큰 저장 방식
token-prefixString"Bearer "토큰 접두사
roles-claimString"roles"JWT roles claim
scopes-claimString"scopes"JWT scopes claim
oauth2-csrfbooleanfalseOAuth2 CSRF 보호

TokenTransportType 상세

accessTokenrefreshToken
HEADERHTTP HeaderHTTP Header
COOKIECookieCookie
HEADER_COOKIE (권장)HTTP HeaderCookie

OAuth2 설정 (spring.auth.oauth2.*)

속성기본값설명
client-iddefault-clientOAuth2 클라이언트 ID
client-secret173f8245-5f7d-4623-a612-aa0c68f6da4a클라이언트 시크릿
issuer-urihttp://localhost:9000토큰 발급자 URI
token-endpoint/oauth2/tokenAuthorization Server 토큰 엔드포인트
scoperead기본 요청 scope
redirect-urihttp://localhost:8080클라이언트 리다이렉트 URI
authorized-uri미설정선택적 사전 승인 리다이렉트 URI
jwk-key-store-path미설정JWK 키스토어 경로
jwk-key-store-password미설정키스토어 비밀번호
jwk-key-alias미설정키 별칭
jwk-key-password미설정키 비밀번호

MFA 설정 (spring.auth.mfa.*)

속성기본값설명
session-timeout-ms600000 (10분)MFA 세션 타임아웃
challenge-timeout-ms300000 (5분)챌린지 타임아웃
inactivity-timeout900000 (15분)비활성 MFA 세션 타임아웃
cache-ttl300000 (5분)MFA 상태 캐시 TTL
session-refresh-interval-ms30000 (30초)활성 MFA 세션 갱신 주기
state-machine-timeout-ms10000 (10초)상태 머신 실행 타임아웃
max-retry-attempts5최대 재시도 횟수
account-lockout-duration-ms900000 (15분)계정 잠금 기간
minimum-delay-ms500민감한 MFA 동작 사이의 최소 지연
otp-token-validity-seconds300OTP 유효 기간 (초)
otp-token-length6OTP 코드 길이
sms-resend-interval-seconds60SMS 재전송 최소 간격
email-resend-interval-seconds120이메일 재전송 최소 간격
device-remember-duration-ms2592000000 (30일)기기 신뢰 유지 기간
state-machine-pool-size100상태 머신 작업 풀 크기
state-machine-cache-ttl-ms300000 (5분)상태 머신 캐시 TTL
circuit-breaker-failure-threshold5서킷 브레이커 실패 임계값
circuit-breaker-timeout-seconds30서킷 브레이커 타임아웃
detailed-logging-enabledfalse상세 MFA 디버그 로그 활성화
metrics-enabledtrueMFA 메트릭 활성화
audit-logging-enabledtrueMFA 감사 로그 활성화
session-storage-typehttp-sessionMFA 세션 저장소 기본 유형
auto-select-repositoryfalse세션 저장소 자동 선택 여부
repository-priorityredis,memory,http-session저장소 선택 우선순위
fallback-repository-typehttp-session대체 저장소 유형

MFA 하위 설정 그룹

Prefix설명대표 기본값
spring.auth.mfa.http-session.*HTTP Session 기반 MFA 저장소 설정enabled=true, session-attribute-name=MFA_SESSION_ID
spring.auth.mfa.redis.*분산 배포용 Redis 기반 MFA 저장소 설정key-prefix=mfa:session:, cookie-name=MFA_SID, same-site=Strict
spring.auth.mfa.memory.*인메모리 MFA 저장소 튜닝cleanup-interval-minutes=5, max-sessions=10000
spring.auth.mfa.sms-factor.*SMS 요소 전송 설정provider=default, template-id=mfa_sms_template, enabled=true
spring.auth.mfa.email-factor.*이메일 요소 전송 설정from-address=noreply@company.com, template-id=mfa_email_template, enabled=true

application.yml 예제

spring:
  auth:
    state-type: OAUTH2
    token-transport-type: header_cookie
    access-token-validity: 3600000
    enable-refresh-token: true
    oauth2:
      client-id: my-client
      issuer-uri: https://auth.example.com
      jwk-key-store-path: classpath:keystore.jks
    mfa:
      session-timeout-ms: 600000
      otp-token-validity-seconds: 300
      session-storage-type: redis
      redis:
        key-prefix: mfa:session:
        cookie-name: MFA_SID