guides

문제 해결

SSO 연동 시 흔한 문제와 해결 방법

문제 해결

흔한 오류

리다이렉트 루프

증상: 로그인 후 /auth/callback -> /auth/login이 반복됩니다.

원인과 해결:

원인 확인 방법 해결
redirect_uri 불일치 Connect 등록 URI와 앱 URI 비교 Connect에 정확한 콜백 URL 등록
쿠키 미설정 브라우저 DevTools > Application > Cookies Secure, SameSite 속성 확인
미들웨어 순서 오류 auth 미들웨어가 redirect 전에 실행되는지 확인 sequence() 순서 조정

CORS 문제

증상: 브라우저 콘솔에 Access-Control-Allow-Origin 관련 에러가 나타납니다.

해결: SSO 플로우는 서버 사이드 리다이렉트로 동작하므로 CORS 설정이 필요하지 않습니다. 이 에러가 발생한다면 클라이언트에서 fetch()로 직접 Connect 서버를 호출하고 있는지 확인하세요. 토큰 교환은 반드시 서버 사이드에서 이루어져야 합니다.

쿠키 미설정

증상: 로그인 성공 후에도 locals.user가 null입니다.

원인과 해결:

  • 도메인 불일치: 쿠키의 도메인 설정이 앱 도메인과 일치하는지 확인합니다.
  • Secure 플래그: 프로덕션에서는 HTTPS가 필수입니다. HTTP에서는 Secure 쿠키가 설정되지 않습니다.
  • SameSite 속성: SameSite=Lax가 기본값입니다. cross-origin 리다이렉트 시 정상 동작합니다.

디버그 체크리스트

SSO 연동이 동작하지 않을 때, 다음 5단계를 순서대로 확인하세요.

1단계: Connect 서버 상태 확인

curl -s https://connect.modfolio.io/health | jq .

정상 응답:

{
  "status": "ok",
  "version": "1.0.0"
}

2단계: OIDC Discovery 확인

curl -s https://connect.modfolio.io/.well-known/openid-configuration | jq .

authorization_endpoint, token_endpoint, jwks_uri가 모두 포함되어야 합니다.

3단계: client_id 확인

앱의 clientId가 Connect에 등록된 값과 정확히 일치하는지 확인합니다. 대소문자를 구분하며, 오타가 있으면 authorization 단계에서 실패합니다.

// 올바른 예시 — 레포 이름과 동일
export const auth = createAstroAuth({
  clientId: "your-app-name", // Connect에 등록된 이름
});

4단계: 콜백 URL 확인

로컬 개발과 프로덕션에서 콜백 URL이 다릅니다. Connect에 두 URL 모두 등록되어 있어야 합니다.

  • 로컬: http://localhost:4321/auth/callback
  • 프로덕션: https://your-app.com/auth/callback

5단계: 네트워크 요청 추적

브라우저 DevTools > Network 탭에서 다음 순서로 요청이 진행되는지 확인합니다.

1. GET /auth/login               → 302 → connect.modfolio.io/sso/authorize
2. connect.modfolio.io 로그인 처리
3. 302 → /auth/callback?code=... → 200 (쿠키 설정)
4. 302 → / (또는 원래 페이지)

3번에서 쿠키가 설정되지 않거나 4번으로 진행되지 않으면 콜백 핸들러를 점검하세요.

로컬 개발 팁

포트 매핑

각 프레임워크의 기본 포트:

프레임워크 기본 포트 명령어
Astro 4321 bun run dev
SvelteKit 5173 bun run dev
SolidStart 3000 bun run dev

콜백 URL에 포트 번호를 포함해야 합니다. 예: http://localhost:4321/auth/callback

HTTPS 로컬 설정

프로덕션 환경을 정확히 재현하려면 로컬에서도 HTTPS를 사용하세요.

# mkcert로 로컬 인증서 생성
mkcert -install
mkcert localhost

# Astro에서 HTTPS로 실행
bun run dev --host --https --cert localhost.pem --key localhost-key.pem

단, 대부분의 경우 HTTP 로컬 개발로도 충분합니다. SDK는 로컬 환경에서 Secure 쿠키 플래그를 자동으로 비활성화합니다.

Health Check 엔드포인트

운영 중 Connect 서버 상태를 모니터링할 때 사용합니다.

# 기본 상태 확인
curl -sf https://connect.modfolio.io/health

# JWKS 공개키 확인 (JWT 서명 검증용)
curl -s https://connect.modfolio.io/.well-known/jwks.json | jq '.keys | length'

# OIDC Discovery 엔드포인트 수 확인
curl -s https://connect.modfolio.io/.well-known/openid-configuration | jq 'keys | length'

에러 응답 형식

Connect 서버의 에러 응답은 일관된 JSON 형식을 따릅니다.

interface ConnectErrorResponse {
  error: string;        // 에러 코드 (OAuth 2.0 표준)
  error_description: string; // 사람이 읽을 수 있는 설명
}

주요 에러 코드:

코드 HTTP 상태 설명
invalid_client 401 client_id가 등록되지 않음
invalid_grant 400 authorization code가 만료되었거나 이미 사용됨
invalid_request 400 필수 파라미터 누락
invalid_scope 400 요청한 scope를 지원하지 않음
server_error 500 Connect 서버 내부 오류
access_denied 403 사용자가 동의를 거부함

에러 응답 처리 예시:

const response = await fetch("https://connect.modfolio.io/sso/token", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ code, code_verifier, redirect_uri }),
});

if (!response.ok) {
  const error = await response.json() as ConnectErrorResponse;
  console.error(`SSO 토큰 교환 실패: [${error.error}] ${error.error_description}`);
}

SDK를 사용하면 위 에러 처리가 자동으로 수행됩니다. 수동으로 API를 호출하는 경우에만 이 형식을 참고하세요.

ESC

검색어를 입력하세요