사용자 데이터 구조
사용자는 아이덴티티 서비스의 핵심 엔티티입니다. Logto에서는 OpenID Connect 프로토콜을 기반으로 한 기본 인증 (Authentication) 데이터와 사용자 정의 데이터를 포함합니다.
사용자 프로필
각 사용자는 모든 사용자 정보를 포함하는 프로필을 가집니다.
이는 다음과 같은 유형의 데이터로 구성됩니다:
- 기본 데이터: 사용자 프로필의 기본 정보입니다. 소셜
identities
및custom_data
를 제외한 모든 사용자 속성을 저장합니다. 예를 들어 사용자 ID, 사용자 이름, 이메일, 전화번호, 마지막 로그인 시간 등이 있습니다. - 소셜 아이덴티티: Facebook, GitHub, WeChat 등 소셜 커넥터로 소셜 로그인 시 가져온 사용자 정보를 저장합니다.
- 사용자 정의 데이터: 미리 정의된 사용자 속성에 포함되지 않은 추가 사용자 정보를 저장합니다. 예를 들어 사용자가 선호하는 색상과 언어 등이 있습니다.
다음은 Facebook으로 로그인하여 가져온 사용자 데이터 샘플입니다:
{
"id": "iHXPuSb9eMzt",
"username": null,
"primaryEmail": null,
"primaryPhone": null,
"name": "John Doe",
"avatar": "https://example.com/avatar.png",
"customData": {
"preferences": {
"language": "en",
"color": "#f236c9"
}
},
"identities": {
"facebook": {
"userId": "106077000000000",
"details": {
"id": "106077000000000",
"name": "John Doe",
"email": "[email protected]",
"avatar": "https://example.com/avatar.png"
}
}
},
"lastSignInAt": 1655799453171,
"applicationId": "admin_console"
}
Logto Console 또는 Logto Management API, 예를 들어 GET /api/users/:userId
를 사용하여 사용자
프로필을 조회할 수 있습니다.
기본 데이터
사용자의 기본 데이터에 포함된 모든 속성을 살펴보겠습니다.
id
id는 Logto에서 사용자를 식별하는 고유 자동 생성 키입니다.
username
username은 username과 비밀번호로 로그인할 때 사용됩니다.
값은 사용자가 처음 등록할 때 입력한 사용자 이름에서 가져옵니다. null
일 수 있습니다. null이 아닌 값은 128자 이하여야 하며, 영문자, 숫자, 밑줄(_
)만 포함할 수 있고 숫자로 시작할 수 없습니다. 대소문자를 구분합니다.
primary_email
primary_email은 사용자의 이메일 주소로, 이메일과 비밀번호 / 인증 코드로 로그인할 때 사용됩니다.
값은 사용자가 처음 등록할 때 입력한 이메일 주소에서 가져옵니다. null
일 수 있습니다. 최대 길이는 128자입니다.
primary_phone
primary_phone은 사용자의 전화번호로, 전화번호와 비밀번호 / SMS 인증 코드로 로그인할 때 사용됩니다.
값은 사용자가 처음 등록할 때 입력한 전화번호에서 가져옵니다. null
일 수 있습니다. null이 아닌 값은 국가 전화 코드로 시작하는 숫자여야 하며, 플러스 기호 +
는 제외합니다.
name
name은 사용자의 전체 이름입니다. 최대 길이는 128자입니다.
avatar
avatar는 사용자의 아바타 이미지 URL입니다. 최대 길이는 2048자입니다.
Google, Facebook 등 소셜 커넥터로 가입한 경우, 해당 소셜 사용자 정보에서 값을 가져올 수 있습니다.
이 속성은 OpenID Connect 표준의 picture
클레임 (Claim)에 매핑됩니다.
profile
profile은 사용자의 속성에 포함되지 않은 추가 OpenID Connect 표준 클레임 (Claim)을 저장합니다.
타입 정의는 이 파일에서 확인할 수 있습니다. 아래는 타입 정의 복사본입니다:
type UserProfile = Partial<{
familyName: string;
givenName: string;
middleName: string;
nickname: string;
preferredUsername: string;
profile: string;
website: string;
gender: string;
birthdate: string;
zoneinfo: string;
locale: string;
address: Partial<{
formatted: string;
streetAddress: string;
locality: string;
region: string;
postalCode: string;
country: string;
}>;
}>;
Partial
은 모든 속성이 선택적임을 의미합니다.
다른 표준 클레임 (Claim)과의 차이점은, profile
의 속성 값이 비어 있지 않을 때만 ID 토큰 또는 userinfo 엔드포인트 응답에 포함된다는 점입니다. 반면, 다른 표준 클레임 (Claim)은 값이 비어 있으면 null
을 반환합니다.
application_id
application_id의 값은 사용자가 처음 로그인한 애플리케이션에서 가져옵니다. null
일 수 있습니다.
last_sign_in_at
last_sign_in_at은 사용자가 마지막으로 로그인한 시점의 타임존이 포함된 타임스탬프입니다.
created_at
created_at은 사용자가 계정을 등록한 시점의 타임존이 포함된 타임스탬프입니다.
updated_at
updated_at은 사용자의 프로필 정보가 마지막으로 업데이트된 시점의 타임존이 포함된 타임스탬프입니다.
has_password
has_password는 사용자가 비밀번호를 가지고 있는지 여부를 나타내는 불리언 값입니다. Console > 사용자 관리의 상세 페이지에서 이 상태를 확인하고 새 비밀번호 설정 또는 비밀번호 재설정이 가능합니다.
password_encrypted
password_encrypted는 사용자의 암호화된 비밀번호를 저장합니다.
값은 사용자가 처음 등록할 때 입력한 비밀번호에서 가져옵니다. null
일 수 있습니다. null이 아닌 경우, 암호화 전 원본 내용은 최소 6자 이상이어야 합니다.
password_encryption_method
password_encryption_method는 사용자의 비밀번호를 암호화하는 데 사용됩니다. 사용자가 사용자 이름과 비밀번호로 등록할 때 초기화됩니다. null
일 수 있습니다.
Logto는 기본적으로 Argon2의 구현체인 node-argon2를 암호화 방식으로 사용합니다. 자세한 내용은 참고 자료를 확인하세요.
비밀번호가 123456
인 사용자의 password_encrypted 및 password_encryption_method 샘플:
{
"password_encryption_method": "Argon2i",
"password_encrypted": "$argon2i$v=19$m=4096,t=10,p=1$aZzrqpSX45DOo+9uEW6XVw$O4MdirF0mtuWWWz68eyNAt2u1FzzV3m3g00oIxmEr0U"
}
is_suspended
is_suspended는 사용자가 정지되었는지 여부를 나타내는 불리언 값입니다. 값은 Logto Management API 호출 또는 Logto Console을 통해 관리할 수 있습니다.
사용자가 정지되면, 사전에 부여된 리프레시 토큰 (Refresh token)은 즉시 폐기되며, 더 이상 Logto를 통해 인증 (Authentication)받을 수 없습니다.
mfa_verification_factors
mfa_verification_factors는 사용자의 계정에 연결된 다단계 인증 (MFA) 방법 목록입니다. 가능한 값에는 Totp (인증 앱 OTP), WebAuthn (패스키), BackupCode가 있습니다.
mfaVerificationFactors: ("Totp" | "WebAuthn" | "BackupCode")[];
소셜 아이덴티티
identities는 소셜 로그인 (즉, 소셜 커넥터로 로그인)에서 가져온 사용자 정보를 포함합니다. 각 사용자의 identities는 개별 JSON 객체로 저장됩니다.
사용자 정보는 소셜 아이덴티티 제공자(즉, 소셜 네트워크 플랫폼)에 따라 다르며, 일반적으로 다음을 포함합니다:
- 아이덴티티 제공자의 target (예: "facebook" 또는 "google")
- 해당 제공자에서의 사용자의 고유 식별자
- 사용자의 이름
- 사용자의 인증된 이메일
- 사용자의 아바타
사용자 계정은 소셜 로그인으로 여러 소셜 아이덴티티 제공자와 연결될 수 있으며, 각 제공자로부터 가져온 사용자 정보는 identities 객체에 저장됩니다.
Google과 Facebook으로 모두 로그인한 사용자의 identities 샘플:
{
"facebook": {
"userId": "5110888888888888",
"details": {
"id": "5110888888888888",
"name": "John Doe",
"email": "[email protected]",
"avatar": "https://example.com/avatar.png"
}
},
"google": {
"userId": "111000000000000000000",
"details": {
"id": "111000000000000000000",
"name": "John Doe",
"email": "[email protected]",
"avatar": "https://example.com/avatar.png"
}
}
}
SSO 아이덴티티
sso_identities는 엔터프라이즈 SSO (즉, 엔터프라이즈 커넥터로 싱글 사인온 (SSO) 로그인](/connectors/enterprise-connectors))에서 가져온 사용자 정보를 포함합니다. 각 사용자의 ssoIdentities는 개별 JSON 객체로 저장됩니다.
SSO 아이덴티티 제공자로부터 동기화된 데이터는 엔터프라이즈 커넥터에서 요청하도록 구성된 스코프에 따라 다릅니다. 아래는 TypeScript 타입 정의 복사본입니다:
type SSOIdentity = {
issuer: string;
identityId: string;
detail: JsonObject; // See https://github.com/withtyped/withtyped/blob/master/packages/server/src/types.ts#L12
};
사용자 정의 데이터
custom_data는 미리 정의된 사용자 속성에 포함되지 않은 추가 사용자 정보를 저장합니다.
custom_data를 사용하여 다음과 같은 작업을 할 수 있습니다:
- 사용자가 특정 작업(예: 환영 페이지를 본 적이 있는지 등)을 했는지 기록
- 애플리케이션별로 사용자 프로필에 데이터 저장 (예: 사용자가 선호하는 언어, 애플리케이션별 테마 등)
- 사용자와 관련된 기타 임의의 데이터 관리
Logto의 관리자 사용자의 custom_data 샘플:
{
"adminConsolePreferences": {
"language": "en",
"appearanceMode": "system",
"experienceNoticeConfirmed": true
},
"customDataFoo": {
"foo": "foo"
},
"customDataBar": {
"bar": "bar"
}
}
각 사용자의 custom_data는 개별 JSON 객체로 저장됩니다.
custom_data에 민감한 데이터를 저장하지 마세요.
사용자 로그인 후 커스텀 JWT 토큰 클레임 (Claim)을 통해 사용자 정의 데이터에 접근할 수 있으며, JWT 토큰은 base64로 인코딩(암호화 아님)되어 네트워크를 통해 자주 전송되므로 민감한 데이터가 쉽게 노출될 수 있습니다.
Management API를 통해 custom_data가 포함된 사용자 프로필을 조회하여 프론트엔드 앱이나 외부 백엔드 서비스로 전송할 수 있습니다. 따라서 custom_data에 민감한 정보를 넣으면 데이터 유출 위험이 있습니다.
그래도 custom_data에 민감한 정보를 저장해야 한다면, 먼저 암호화할 것을 권장합니다. 암호화/복호화는 백엔드 서비스 등 신뢰할 수 있는 파티에서만 수행하고, 프론트엔드 앱에서는 피하세요. 이렇게 하면 사용자의 custom_data가 실수로 유출되더라도 피해를 최소화할 수 있습니다.
사용자 정의 데이터 수집 및 업데이트 방법
- 사용자 프로필 수집 기능을 사용하여 회원가입 시 사용자 정의 데이터를 수집하세요.
- Account API를 사용하여 최종 사용자 프로필 또는 계정 설정을 구현하세요.
GET /api/my-account
로 모든 사용자 데이터를 조회하세요.PATCH /api/my-account
로 사용자의 custom_data를 업데이트하세요.
- Management API를 사용하여 사용자 관리 또는 고급 커스텀 플로우를 구현하세요:
GET /api/users/{userId}
로 모든 사용자 데이터를 조회하세요.PATCH /api/users/{userId}/custom-data
로 사용자의 custom_data를 업데이트하세요.
- 지원팀은 Console > 사용자 관리에서 직접 사용자 custom_data를 업데이트할 수 있습니다. 사용자 프로필 조회 및 업데이트에서 자세히 알아보세요.
업데이트 시 주의하세요. 사용자의 custom_data를 업데이트하면 기존 저장된 내용이 완전히 덮어써집니다.
예를 들어, custom_data 업데이트 API 호출 입력이 다음과 같고(기존 custom_data는 앞서 제시한 샘플 데이터라고 가정):
{
"customDataBaz": {
"baz": "baz"
}
}
업데이트 후 새로운 custom_data 값은 다음과 같습니다:
{
"customDataBaz": {
"baz": "baz"
}
}
즉, 업데이트된 필드 값은 이전 값과 무관합니다.
속성 참조
다음 DB 사용자 테이블 컬럼(password_encrypted 및 password_encryption_method 제외)은 사용자 프로필에서 확인할 수 있으며, Management API로 조회할 수 있습니다.
이름 | 타입 | 설명 | 고유 | 필수 |
---|---|---|---|---|
id | string | 고유 식별자 | ✅ | ✅ |
username | string | 로그인용 사용자 이름 | ✅ | ❌ |
primary_email | string | 기본 이메일 | ✅ | ❌ |
primary_phone | string | 기본 전화번호 | ✅ | ❌ |
name | string | 전체 이름 | ❌ | ❌ |
avatar | string | 사용자 아바타 이미지 URL | ❌ | ❌ |
profile | object | 사용자 프로필 | ❌ | ✅ |
identities | object | 소셜 로그인에서 가져온 사용자 정보 | ❌ | ✅ |
custom_data | object | 커스터마이즈 가능한 속성의 추가 정보 | ❌ | ✅ |
application_id | string | 사용자가 처음 등록한 애플리케이션 ID | ❌ | ✅ |
last_sign_in_at | date time | 사용자가 마지막으로 로그인한 시점의 타임스탬프 | ❌ | ✅ |
password_encrypted | string | 암호화된 비밀번호 | ❌ | ❌ |
password_encryption_method | string | 비밀번호 암호화 방식 | ❌ | ❌ |
is_suspended | bool | 사용자 정지 여부 표시 | ❌ | ✅ |
mfa_verifications | object[] | MFA 인증 (Authentication) 요소 | ❌ | ✅ |
- 고유: 데이터베이스 테이블 속성 값의 고유성을 보장합니다.
- 필수: 데이터베이스 테이블 속성 값이
null
이 될 수 없음을 보장합니다.
관련 리소스
이동 중인 사용자 데이터를 위한 보안 허브