Skip to content

핵심 개념

역할

OAuth 2.0logi 이름역할
Identity Providerlogi인증, 토큰 발급
Relying Party제휴사 앱redirect, userinfo 조회
Resource Owner사용자자격 증명 입력, Consent

users.role: user | developer | admin.

식별자

User

필드설명
apple_sub / google_subSSO provider stable ID. 1순위 lookup.
email_addressNOT NULL, active user 사이 unique (partial index deleted_at IS NULL). 익명: anon+<sha256(platform:device_uuid)[0..16]>@1pass.internal. SSO 시 provider 이메일이 없으면 apple+<hash>@1pass.internal 또는 google+<hash>@1pass.internal 합성.
device_uuidDeviceCredential row (user_id, device_uuid, platform). 멀티 디바이스용, user 식별자 아님.

Client (RP)

필드형식비고
client_idlogi_ + 32 hex공개
client_secretlogi_secret_ + 64 hex1회 노출, DB는 bcrypt digest

Token / Key

  • jti — Access Token JWT 고유 ID, revoke 조회용.
  • kid — 서명 키 식별자, JWKS rotation 지원.

Apple Bundle ID

플랫폼Bundle IDTeamID
iOScom.dcodelabs.logi74PTNNLD4P
App Clipcom.dcodelabs.logi.Clip74PTNNLD4P
macOScom.dcodelabs.logi.mac74PTNNLD4P

AASA appID 와 일치해야 함.

익명-우선 (v0.4)

단계user 상태식별자
첫 실행anonymous=true, sub=nil, email_address=anon+<hash>@1pass.internal, password=randomDeviceCredential
첫 SSOanonymous=false, sub 채움, email 교체provider sub
30일 grace 재로그인find_restorable_within_grace 로 deleted user 복구 (account-deletion)provider sub / email

⚠️ Cross-provider 충돌 (비대칭):

  • Apple 경로: 동일 이메일 Google-only user 에 apple_sub link. 다른 apple_sub 보유 시 email_linked_to_other_apple_account 거부.
  • Google 경로: 사전 검사 없이 User.create!ActiveRecord::RecordNotUnique 가능 (임시).

익명 user OAuth 동의

기본 거부. 예외:

  • self-RP (1pass console): console:read 익명 허용, console:manage 는 developer 필요.
  • per-RP opt-in: oauth_applications.allow_anonymous_grants=true RP 는 익명 grant 수락.

Scope

scopeuserinfo 반환 키
profile:basicsub, nickname, name (profile alias 허용, profile:basic 권장)
emailsub, email, email_verified
phonesub, phone_number
openidid_token 발급 + sub (OIDC 활성화)

공백 구분 (콤마 아님). 전체 목록·필드는 Scope 레퍼런스.

신원은 userinfo 에서

email·nickname·name 등 프로필 claim 은 /oauth/userinfo 응답에 담깁니다. id_tokensub 등 OIDC 표준 claim 만 담으므로, 프로필이 필요하면 access_token 으로 userinfo 를 호출하세요.

  • 동일 scope 재인증 → UI 스킵, 즉시 code 발급
  • scope 확장 → "NEW" 배지 + 추가 동의
  • /settings revoke → 다음 인증 시 Consent 재표시

토큰 수명

토큰만료Revocation
Authorization Code10분, 1회자동 (consume!)
Access Token (JWT)15분jwt_jti DB 조회
Refresh Token30일, rotation재사용 시 체인 전체 revoke
Personal API Key무기한 (설정 가능)last_used_at + 수동 revoke
Soft-deleted user grace30일SSO/email 재로그인 자동 복구, 30일 후 PurgeUserJob (상세)

JWT 구조

Header:   { alg: "RS256", kid: "<active>", typ: "JWT" }
Payload:  { iss: "logi", sub: "<user_id>", aud: "<client_id>",
            exp: <15min>, iat: <now>, jti: "<uuid>", scope: "openid profile:basic email" }
Signature: RS256 over header.payload

공개 키: /.well-known/jwks.json

인증 메커니즘

메커니즘용도전달
세션 쿠키웹 UIsession_id=...; Secure; HttpOnly; SameSite=Lax
OAuth AT (JWT)userinfo 조회Authorization: Bearer <JWT>
PAKCLI/MCPAuthorization: Bearer logi_pak_...
Client Basic/oauth/tokenAuthorization: Basic <client_id:secret>
Passkey (WebAuthn)패스워드리스ASAuthorization* / navigator.credentials
device_secret익명 1차 자격증명 (POST /api/v1/devices 1회 발급, keychain)body { "device_secret": "<urlsafe_base64>" } (prefix 없음)

2FA 상태 머신

[비활성] --setup_otp!--> [키 생성됨] --enable_otp!(code)--> [활성]
[활성] --disable_otp!(current_code)--> [비활성]
[활성] --login_with(otp_code)--> session.otp_verified_at = Time.current
[활성] --login_with(backup_code)--> 백업 1개 소진

Passkey + User Verification → OTP 동등, otp_verified_at 자동 설정.

Sub Stability & canonical_sub

  • sub — grant 시점 user.id 영구 박힘. OIDC stable.
  • canonical_sub — 현재 살아있는 user.id. 통합 시 갱신. RP 가 토큰 검증 시 참조.
  • linked_subs — 흡수된 user.id 목록. survivor userinfo 에 포함.

상세: Sub 정책, RP Migration Guide.

primary_user_id  (survivor canonical)
linked_user_id   (흡수, UNIQUE)
merged_via       ("t1_device_link" | "t2_email_match" | "t3_otp")

DB 트리거가 chain/cycle 차단 → canonical 해석 1-hop. T1/T2/T3 동작: Account Merge.

다음 단계

Identity가 제품의 신뢰를 만듭니다.