이 페이지는 기계 번역되었습니다. 잘못된 부분을 발견하셨나요?개선을 도와주세요.
Skip to content

OIDC / Single Sign-On ​

SnapOtter는 싱글 사인온을 위해 OpenID Connect(OIDC)를 지원합니다. 사용자는 로컬 사용자 이름/비밀번호 인증 대신(또는 이와 함께) Keycloak, Authentik, Google, Microsoft Entra ID와 같은 외부 ID 공급자로 로그인할 수 있습니다.

Quick start ​

docker-compose.yml에 다음 환경 변수를 추가하세요:

yaml
services:
  SnapOtter:
    image: snapotter/snapotter:latest
    environment:
      EXTERNAL_URL: "https://photos.example.com"
      OIDC_ENABLED: "true"
      OIDC_ISSUER_URL: "https://auth.example.com/realms/myrealm"
      OIDC_CLIENT_ID: "snapotter"
      OIDC_CLIENT_SECRET: "your-secret-here"

공급자의 리디렉션 URI는 항상 다음과 같습니다:

${EXTERNAL_URL}/api/auth/oidc/callback

예를 들어 EXTERNAL_URL가 https://photos.example.com라면, 공급자의 리디렉션 URI를 https://photos.example.com/api/auth/oidc/callback으로 구성하세요.

Configuration reference ​

VariableDefaultDescription
OIDC_ENABLEDfalseOIDC 로그인을 활성화합니다. 로그인 페이지에 "Sign in with SSO" 버튼이 나타납니다.
OIDC_ISSUER_URL공급자의 issuer URL. OIDC Discovery(/.well-known/openid-configuration)를 지원해야 합니다.
OIDC_CLIENT_ID공급자에 등록된 OAuth 클라이언트 ID.
OIDC_CLIENT_SECRETOAuth 클라이언트 시크릿.
OIDC_SCOPESopenid profile email요청할 스코프의 공백으로 구분된 목록.
OIDC_AUTO_CREATE_USERStrue첫 OIDC 로그인 시 로컬 사용자 계정을 자동으로 생성합니다.
OIDC_DEFAULT_ROLEuser자동 생성된 OIDC 사용자에게 할당되는 역할. admin, editor, user 중 하나.
OIDC_AUTO_LINK_USERSfalse이메일 주소가 일치하면 OIDC ID를 기존 로컬 사용자에 연결합니다.
OIDC_PROVIDER_NAME로그인 버튼에 표시되는 이름(예: "Keycloak", "Google"). 비어 있으면 버튼에 "SSO"라고 표시됩니다.
OIDC_CLOCK_TOLERANCE30토큰 검증을 위한 시계 오차 허용 범위(초 단위).
OIDC_USERNAME_CLAIMpreferred_username새 계정의 사용자 이름으로 사용되는 ID 토큰 클레임.
EXTERNAL_URLSnapOtter에 접근할 수 있는 공개 URL. OIDC가 올바른 리디렉션 URI를 구성하려면 필요합니다.
COOKIE_SECRETauto-generated세션 쿠키 서명을 위한 시크릿. 여러 레플리카를 실행할 때 명시적으로 설정하세요.

Provider guides ​

Keycloak ​

  1. 새 realm을 생성합니다(또는 기존 realm 사용).
  2. Clients로 이동하여 새 클라이언트를 생성합니다:
    • Client ID: snapotter
    • Client authentication: On (confidential)
    • Authentication flow: Standard flow (Authorization Code)
  3. 클라이언트의 Settings 탭에서 Valid redirect URIs를 콜백 URL로 설정합니다(예: https://photos.example.com/api/auth/oidc/callback).
  4. Credentials 탭에서 Client secret을 복사합니다.
  5. OIDC_ISSUER_URL을 https://keycloak.example.com/realms/your-realm로 설정합니다.

Authentik ​

  1. 관리자 인터페이스에서 Applications > Providers로 이동하여 새 OAuth2/OpenID Provider를 생성합니다.
    • Client type: Confidential
    • Redirect URIs: 콜백 URL
    • Signing key: 기존 키를 선택하거나 새로 생성
  2. Application을 생성하고 공급자에 연결합니다.
  3. 공급자 설정에서 Client ID와 Client Secret을 복사합니다.
  4. OIDC_ISSUER_URL을 https://authentik.example.com/application/o/snapotter/으로 설정합니다(끝의 슬래시가 중요합니다).

Google ​

  1. Google Cloud Console로 이동합니다.
  2. 프로젝트를 생성합니다(또는 기존 프로젝트 선택).
  3. APIs & Services > OAuth consent screen으로 이동하여 구성합니다.
  4. APIs & Services > Credentials로 이동하여 OAuth 2.0 Client ID를 생성합니다:
    • Application type: Web application
    • Authorized redirect URIs: 콜백 URL
  5. Client ID와 Client secret을 복사합니다.
  6. OIDC_ISSUER_URL을 https://accounts.google.com로 설정합니다.
  7. OIDC_USERNAME_CLAIM을 email으로 설정합니다(Google은 preferred_username을 제공하지 않습니다).

Azure AD / Entra ID ​

  1. Azure 포털에서 Microsoft Entra ID > App registrations > New registration으로 이동합니다.
  2. 앱 이름을 "SnapOtter"로 지정합니다. Redirect URI에서 Web 플랫폼을 선택하고 콜백 URL을 입력합니다(예: https://photos.example.com/api/auth/oidc/callback). Single-page application을 선택하지 마세요. SnapOtter는 클라이언트 시크릿으로 인증하는데, Entra ID는 SPA 등록에서 이를 거부합니다.
  3. Overview 페이지에서 Application (client) ID와 Directory (tenant) ID를 복사합니다.
  4. Certificates & secrets > New client secret으로 이동하여 시크릿 Value를 바로 복사합니다. 이 값은 한 번만 표시되며, 옆에 있는 Secret ID는 시크릿이 아닙니다.
  5. 3단계에서 복사한 Directory (tenant) ID를 사용하여 OIDC_ISSUER_URL을 https://login.microsoftonline.com/<tenant-id>/v2.0으로 설정합니다.
  6. OIDC_USERNAME_CLAIM은 기본값 그대로 둡니다. Entra ID는 preferred_username을 제공하므로, Google 가이드의 email 재정의는 여기서 필요하지 않습니다.

issuer URL에는 common이나 organizations가 아니라 항상 사용자의 테넌트 ID를 사용하세요. 이러한 멀티 테넌트 엔드포인트는 리터럴 템플릿 {tenantid}를 issuer로 제시하므로 OIDC discovery 검증에 실패합니다.

WARNING

Entra ID의 preferred_username은 사용자 프린시펄 이름(user principal name)을 따르며, 이 값은 사용자 이름이 변경되거나 사용자가 다른 테넌트로 이동할 때 바뀝니다. SnapOtter는 첫 로그인 시 이 클레임을 한 번만 읽으므로, 그 후에도 계정은 원래 사용자 이름을 유지합니다. 어느 쪽이든 로그인은 계속 동작합니다. 재방문 사용자는 사용자 이름이 아니라 토큰의 안정적인 subject로 매칭되기 때문입니다.

Entra ID로 전환해도 비밀번호 로그인이 꺼지지 않습니다. Disabling local login을 참고하세요.

Okta 및 기타 공급자 ​

OIDC Discovery를 지원하는 공급자라면 어떤 것이든 같은 방식으로 동작합니다. 콜백 URL로 confidential 웹 클라이언트를 생성한 다음, OIDC_ISSUER_URL이 issuer를 가리키도록 하세요. Okta의 경우 OIDC - OpenID Connect 로그인 방식과 Web Application 유형으로 앱을 생성한 다음, Okta 도메인을 issuer로 사용하세요(예: https://your-company.okta.com).

SnapOtter는 ID 공급자의 그룹을 역할에 매핑하지 않습니다. 새 SSO 사용자는 OIDC_DEFAULT_ROLE을 받고, 관리자는 Settings > Users에서 역할을 변경하며, OIDC_SCOPES를 통해 그룹 클레임을 요청해도 아무 효과가 없습니다.

User provisioning ​

Auto-create ​

OIDC_AUTO_CREATE_USERS가 true일 때(기본값), 누군가 OIDC로 처음 로그인하면 로컬 사용자 계정이 생성됩니다. 사용자 이름은 OIDC_USERNAME_CLAIM로 지정된 클레임에서 가져오며, 역할은 OIDC_DEFAULT_ROLE로 설정됩니다.

사용자 이름 충돌이 발생하면 숫자 접미사가 추가됩니다(예: jane이 jane_2이 됨).

OIDC_AUTO_LINK_USERS가 true일 때, SnapOtter는 이메일 주소가 일치하면 OIDC ID를 기존 로컬 계정에 연결합니다. 사용자 계정을 미리 생성해 두고, 데이터를 잃지 않으면서 SSO를 사용하기 시작하도록 하려는 경우에 유용합니다.

WARNING

OIDC 공급자가 이메일 주소를 검증한다고 신뢰하는 경우에만 auto-link를 활성화하세요. 검증되지 않은 이메일은 누군가가 다른 사용자의 계정을 탈취하도록 허용할 수 있습니다.

Disabling local login ​

OIDC는 로컬 사용자 이름/비밀번호 로그인을 비활성화하지 않습니다. 두 방식 모두 계속 사용할 수 있습니다. OIDC 공급자에 접근할 수 없는 경우에도 관리자는 로컬 자격 증명으로 로그인할 수 있습니다.

Self-signed certificates ​

OIDC 공급자가 자체 서명 또는 사설 CA 인증서를 사용하는 경우, CA 번들을 컨테이너에 마운트하고 NODE_EXTRA_CA_CERTS이 이를 가리키도록 하세요:

yaml
services:
  SnapOtter:
    image: snapotter/snapotter:latest
    volumes:
      - ./my-ca.pem:/etc/ssl/certs/custom-ca.pem:ro
    environment:
      NODE_EXTRA_CA_CERTS: /etc/ssl/certs/custom-ca.pem
      OIDC_ENABLED: "true"
      OIDC_ISSUER_URL: "https://auth.internal.example.com/realms/myrealm"
      OIDC_CLIENT_ID: "snapotter"
      OIDC_CLIENT_SECRET: "your-secret-here"

DANGER

NODE_TLS_REJECT_UNAUTHORIZED=0을 설정하지 마세요. 이는 모든 TLS 검증을 비활성화하며 보안 위험입니다.

암호화되지 않은 http 발급자 ​

SnapOtter는 EXTERNAL_URL도 암호화되지 않은 http일 때만 http:// 발급자 URL을 허용하며, 이는 로컬 또는 LAN 테스트 환경에 적합합니다. 이 경우 디스커버리, 로그인 코드 교환, 토큰이 모두 암호화되지 않은 상태로 네트워크를 지나가므로, SnapOtter는 시작할 때 발급자 호스트를 명시한 경고를 로그에 남깁니다. EXTERNAL_URL이 https://이면 http 발급자는 로그인 시 거부되며, 시작 경고에도 그렇게 표시됩니다. 어느 경우든 해결 방법은 ID 공급자를 https로 제공하는 것입니다.

Troubleshooting ​

Redirect URI mismatch ​

가장 흔한 오류입니다. 공급자가 기대하는 것과 SnapOtter가 보내는 것 사이에서 다음 차이를 확인하세요:

  • http 대 https - 스킴이 정확히 일치해야 합니다
  • 끝의 슬래시 - 일부 공급자는 이에 대해 엄격합니다
  • 포트 번호 - 비표준인 경우 포트를 포함하세요
  • 경로 - /api/auth/oidc/callback여야 합니다

EXTERNAL_URL를 다시 확인하세요. 사용자가 브라우저에 입력하는 URL과 일치해야 합니다.

UNABLE_TO_VERIFY_LEAF_SIGNATURE ​

OIDC 공급자가 Node.js가 신뢰하지 않는 인증서를 사용하고 있습니다. 위의 Self-signed certificates를 참고하세요.

Clock skew errors ​

서버 시계와 OIDC 공급자 시계가 동기화되지 않으면 토큰 검증이 실패할 수 있습니다. OIDC_CLOCK_TOLERANCE을 늘리세요(기본값은 30초). 더 나은 해결책은 두 머신 모두에서 NTP를 실행하는 것입니다.

"OIDC provider unreachable" ​

SnapOtter는 시작 시점과 로그인 중에 공급자의 discovery 문서를 가져옵니다. 다음을 확인하세요:

  • Docker 컨테이너 내부에서의 DNS 확인(docker exec snapotter nslookup auth.example.com)
  • 컨테이너와 공급자 사이의 방화벽 규칙
  • OIDC_ISSUER_URL 값 - 브라우저뿐만 아니라 서버에서도 접근할 수 있어야 합니다

Missing claims ​

로그인 후 사용자 이름이나 이메일이 비어 있다면, 공급자가 기대하는 클레임을 반환하지 않을 수 있습니다. 다음을 확인하세요:

  • OIDC_SCOPES에 구성된 스코프에 profile과 email이 포함되어 있는지
  • ID 토큰에 OIDC_USERNAME_CLAIM로 지정된 클레임을 포함하도록 공급자가 구성되어 있는지
  • 일부 공급자는 클레임을 릴리스하기 위해 명시적인 매퍼/스코프 구성이 필요합니다