API 스펙: 가입 & 로그인 V3 medic-mydata
요약
변경 배경
- 마이데이터 가입이 필수로 변경됨
- 회원가입 + 중계시스템 가입을 하나의 플로우로 통합
- WebView 제거, 프론트 서버가 플로우를 주도하는 구조로 전환
신규 API
| # |
엔드포인트 |
설명 |
| 1 |
POST /v3/mydata/certifications/request |
중계시스템 인증 요청 (UUID 발급 + 인증창 데이터 반환) |
| 2 |
POST /v3/auth/sign-up |
회원가입 (디스탯 + 마이데이터 동시 가입) |
| 3 |
POST /v3/auth/sign-in |
통합 로그인 (EMAIL / SOCIAL / ONE_TIME_UUID) |
회원 가입 흐름
(SNS 인증 선택) → 이메일/비밀번호 입력 → 약관 동의 → 중계시스템 인증창 호출 → PASS 인증
→ 중계시스템 → 백엔드 서버로 콜백 (certResultData) → 프론트 서버로 리다이렉트 (certResultData 전달)
→ 프론트에서 회원가입 API 호출 (certUuid + certResultData)
→ 중계시스템 인증 결과 조회 (CI, 개인정보 획득) → 디스탯 회원 생성 → 마이데이터 가입 (MYMD_COMPLETED)
→ oneTimeLoginUuid로 로그인 → 전송요구권 등록 (전자서명) → 회원 상태 업데이트 (COMPLETED)
프론트 호출 순서 (회원가입)
① POST /v3/mydata/certifications/request → certUuid, apiUrl, encryptData 수신
② form submit (apiUrl + encryptData) → 중계시스템 인증 페이지 이동
③ 중계시스템 인증 완료 → 콜백 → 프론트 서버로 리다이렉트 (certResultData 수신)
④ POST /v3/auth/sign-up → nextAction에 따라 분기
⑤ POST /v3/auth/sign-in (ONE_TIME_UUID, oneTimeLoginUuid) → 토큰 수신
1. 중계시스템 인증 요청
POST /v3/mydata/certifications/request
요청
| 필드 |
타입 |
회원가입 (토큰 없음) |
마이데이터만 (토큰 있음) |
설명 |
socialLoginUuid |
String |
소셜 시 필수 |
- |
소셜 로그인 uuid |
email |
String |
필수 |
- |
|
password |
String |
필수 |
- |
|
dstatTermsSeqArr |
Long[] |
필수 |
- |
동의한 디스탯 약관 SEQ 배열 |
mydataTermsSeqArr |
Long[] |
필수 |
필수 |
동의한 마이데이터 약관 SEQ 배열 |
인증
Authorization 헤더 유무로 가입 케이스를 판별한다.
| Authorization 헤더 |
동작 |
설명 |
| 없음 |
디스탯 + 마이데이터 가입 |
비로그인 상태의 신규 회원가입 |
Bearer {token} |
마이데이터만 가입 |
로그인 상태의 기존 회원 (상태: NONE) |
Authorization 헤더에 토큰이 있으면 기존 회원의 마이데이터 가입, 없으면 신규 회원가입으로 처리한다. 별도의 type 필드는 받지 않는다.
응답
{
"certUuid": "발급된 UUID",
"apiUrl": "중계시스템 인증 페이지 URL",
"encryptData": "암호화된 인증 요청 데이터"
}
프론트 처리
certUuid를 저장 (이후 회원가입에서 사용)
apiUrl + encryptData로 동적 form 생성 후 submit → 중계시스템 인증 페이지로 이동
sessionStorage.setItem('certUuid', certUuid);
const form = document.createElement('form');
form.method = 'POST';
form.action = apiUrl;
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'encryptData';
input.value = encryptData;
form.appendChild(input);
document.body.appendChild(form);
form.submit();
encryptData는 민감 데이터이므로 반드시 POST body로 전달해야 한다.
2. 중계시스템 인증 결과 콜백
GET /v1/mydata/certifications/result/cert?certResultData={certResultData}
- 기존 V1 엔드포인트 재활용
- 중계시스템이 인증 완료 후 호출
- 서버가
certResultData를 포함하여 프론트 서버 URL로 302 리다이렉트
브라우저 흐름
프론트 서버 → (form submit) → 중계시스템 인증 → (콜백) → medic-mydata → (302) → 프론트 서버
프론트는 리다이렉트로 수신한 certResultData를 저장한다.
3. 회원가입
POST /v3/auth/sign-up
요청
| 필드 |
타입 |
필수 |
설명 |
certUuid |
String |
O |
1번 API에서 발급받은 UUID |
certResultData |
String |
O |
콜백으로 수신한 중계시스템 인증 결과 |
응답 — nextAction
nextAction에 따라 프론트의 다음 동작이 결정된다.
| nextAction |
발생 조건 |
프론트 처리 |
| SIGN_IN_ONE_TIME_UUID |
가입 성공 |
oneTimeLoginUuid로 로그인 API 호출 (ONE_TIME_UUID) |
| DUPLICATED_USER |
CI 중복 (이메일/애플만 발생) |
로그인 페이지로 이동 (기존 계정으로 로그인 유도) |
| LINK_SOCIAL_ACCOUNT |
기가입 + 애플 미연동 |
socialLoginUuid로 애플 계정 연동 → 로그인 |
응답 예시
SIGN_IN_ONE_TIME_UUID — 정상 가입 완료
{
"nextAction": "SIGN_IN_ONE_TIME_UUID",
"user": {
"seq": 1,
"email": "[email protected]",
"socialAccounts": [
{ "seq": 1, "provider": "APPLE", "linkedDtm": "2026-03-18T12:00:00" }
]
},
"oneTimeLoginUuid": "xxx"
}
DUPLICATED_USER — CI 중복
{
"nextAction": "DUPLICATED_USER",
"user": {
"seq": 2,
"email": "[email protected]",
"socialAccounts": [
{ "seq": 1, "provider": "APPLE", "linkedDtm": "2025-01-01T00:00:00" }
]
}
}
LINK_SOCIAL_ACCOUNT — 애플 미연동
{
"nextAction": "LINK_SOCIAL_ACCOUNT",
"user": {
"seq": 2,
"email": "[email protected]",
"socialAccounts": [
{ "seq": 1, "provider": "KAKAO", "linkedDtm": "2025-01-01T00:00:00" }
]
},
"socialLoginUuid": "yyy"
}
DUPLICATED_USER, LINK_SOCIAL_ACCOUNT는 언제 발생하나?
카카오/네이버는 로그인 시점에 CI를 수신하여 가입 전에 회원 여부를 판별할 수 있다.
하지만 이메일 가입과 애플 로그인은 CI를 미리 알 수 없어, 중계시스템 인증 후에야 CI 중복이 확인된다.
| nextAction |
발생 케이스 |
| DUPLICATED_USER |
이메일 가입 — CI로 조회 시 기가입 회원 존재 |
| DUPLICATED_USER |
애플 로그인 — CI로 조회 시 기가입 회원 존재 + 이미 다른 애플 계정 연동됨 |
| LINK_SOCIAL_ACCOUNT |
애플 로그인 — CI로 조회 시 기가입 회원 존재 + 애플 미연동 (연동 가능) |
에러 케이스
| 에러 |
상황 |
처리 |
ALREADY_EXISTED_USER_EMAIL |
다른 CI의 사용자가 동일 이메일 사용 중 |
이메일 변경 안내 |
NOT_ALLOWED_SIGN_UP_UNDER_14 |
14세 미만 |
가입 불가 안내 |
4. 로그인
POST /v3/auth/sign-in
기존 POST /v2/auth/sign-in (이메일)과 POST /v2/oauth2/sign-in (소셜)을 통합하고, ONE_TIME_UUID 타입을 추가한다.
요청
| 필드 |
타입 |
EMAIL |
SOCIAL |
ONE_TIME_UUID |
설명 |
type |
SignInType |
필수 |
필수 |
필수 |
|
email |
String |
필수 |
- |
- |
|
password |
String |
필수 |
- |
- |
|
socialLoginUuid |
String |
- |
필수 |
- |
|
oneTimeLoginUuid |
String |
- |
- |
필수 |
회원가입 시 발급된 1회성 로그인 UUID |
clientType |
ClientType |
기본 WEB |
기본 WEB |
기본 WEB |
|
deviceId |
String |
- |
- |
- |
|
SignInType
| 값 |
설명 |
V2 대응 |
| EMAIL |
이메일 + 비밀번호 로그인 |
POST /v2/auth/sign-in |
| SOCIAL |
소셜 로그인 (uuid 기반) |
POST /v2/oauth2/sign-in |
| ONE_TIME_UUID |
회원가입 후 1회성 로그인 (certUuid 기반) |
신규 |
응답
{
"accessToken": "JWT 액세스 토큰",
"accessTokenExpirationDtm": "2026-03-18T12:00:00",
"refreshToken": "JWT 리프레시 토큰",
"refreshTokenExpirationDtm": "2026-04-18T12:00:00"
}
type별 서버 처리
| type |
처리 |
| EMAIL |
email/password 인증 → UserToken 생성 |
| SOCIAL |
socialLoginUuid로 SocialLoginResult 조회 → 검증 → UserToken 생성 |
| ONE_TIME_UUID |
certUuid로 MydataCertRequest 조회 → 만료/사용 여부 검증 → user_seq로 회원 조회 → UserToken 생성 → 사용 처리 (used_dtm) |
전체 플로우 시퀀스
소셜 회원가입
sequenceDiagram participant User as 사용자 participant Front as 프론트 서버 participant MM as medic-mydata participant DB as DB participant SNS as SNS 제공자 participant Relay as mydata-relay Note over User,Relay: ── Step 1. 소셜로그인 ── User->>Front: SNS 가입 선택 Front->>SNS: OAuth2 인증 요청 SNS-->>User: 로그인 및 권한 동의 SNS->>MM: 콜백 (socialId, email, accessToken) alt 카카오/네이버 MM->>SNS: accessToken으로 userinfo API 호출 SNS-->>MM: CI 반환 Note over MM: CI 기반 회원 여부 확인 alt CI 없음 (미가입) MM->>MM: nextAction = SIGN_UP else CI 있음 + SNS 미연동 MM->>MM: nextAction = LINK_SOCIAL_ACCOUNT else CI 있음 + SNS 연동됨 MM->>MM: nextAction = SIGN_IN end else 애플 (CI 미제공) Note over MM: socialId 기반 회원 여부 확인 alt socialId 연동 없음 MM->>MM: nextAction = SIGN_UP else socialId 연동 있음 MM->>MM: nextAction = SIGN_IN end end MM->>DB: SocialLoginResult 저장 (uuid 발급) MM-->>Front: 리다이렉트 (socialLoginUuid, nextAction) Note over User,Relay: ── Step 2. 이메일/비밀번호 입력 + 약관 동의 ── Note over Front: nextAction = SIGN_UP인 경우 User->>Front: 이메일/비밀번호 입력 User->>Front: 약관 동의 Note over User,Relay: ── Step 3. 중계시스템 인증 요청 ── Front->>MM: POST /v3/mydata/certifications/request MM->>MM: cert_uuid 생성 + DB 저장 MM->>Relay: 중계시스템 인증 요청 Relay-->>MM: apiUrl + encryptData MM-->>Front: {certUuid, apiUrl, encryptData} Note over User,Relay: ── Step 4. 중계시스템 인증 ── Front->>Relay: form submit (POST apiUrl + encryptData) Relay-->>User: 중계시스템 로그인 화면 User->>Relay: PASS 인증 Note over User,Relay: ── Step 5. 인증 결과 콜백 ── Relay->>MM: GET /v1/.../result/cert?certResultData=xxx MM-->>Front: 302 Redirect (certResultData) Note over User,Relay: ── Step 6. 회원가입 ── Front->>MM: POST /v3/auth/sign-up MM->>Relay: 중계시스템 인증 결과 조회 (certResultData) Relay-->>MM: CI, 이름, 성별, 생년월일, 휴대폰번호 MM->>DB: 검증 + User 생성 + SNS 연동 + 약관 저장 MM->>Relay: 마이데이터 가입 (platformUserSeq, CI, ...) Relay-->>MM: patientSeq MM-->>Front: {nextAction, user, oneTimeLoginUuid} Note over User,Relay: ── Step 7. 로그인 ── Front->>MM: POST /v3/auth/sign-in (ONE_TIME_UUID, oneTimeLoginUuid) MM-->>Front: {accessToken, refreshToken}
이메일 회원가입
sequenceDiagram participant User as 사용자 participant Front as 프론트 서버 participant MM as medic-mydata participant DB as DB participant Relay as mydata-relay Note over User,Relay: ── Step 1. 이메일/비밀번호 입력 + 약관 동의 ── User->>Front: 이메일로 가입 선택 User->>Front: 이메일/비밀번호 입력 User->>Front: 약관 동의 Note over User,Relay: ── Step 2. 중계시스템 인증 요청 ── Front->>MM: POST /v3/mydata/certifications/request MM->>MM: cert_uuid 생성 + DB 저장 MM->>Relay: 중계시스템 인증 요청 Relay-->>MM: apiUrl + encryptData MM-->>Front: {certUuid, apiUrl, encryptData} Note over User,Relay: ── Step 3. 중계시스템 인증 ── Front->>Relay: form submit (POST apiUrl + encryptData) Relay-->>User: 중계시스템 로그인 화면 User->>Relay: PASS 인증 Note over User,Relay: ── Step 4. 인증 결과 콜백 ── Relay->>MM: GET /v1/.../result/cert?certResultData=xxx MM-->>Front: 302 Redirect (certResultData) Note over User,Relay: ── Step 5. 회원가입 ── Front->>MM: POST /v3/auth/sign-up MM->>Relay: 중계시스템 인증 결과 조회 (certResultData) Relay-->>MM: CI, 이름, 성별, 생년월일, 휴대폰번호 MM->>DB: 검증 + User 생성 + 약관 저장 MM->>Relay: 마이데이터 가입 (platformUserSeq, CI, ...) Relay-->>MM: patientSeq MM-->>Front: {nextAction, user, oneTimeLoginUuid} Note over User,Relay: ── Step 6. 로그인 ── Front->>MM: POST /v3/auth/sign-in (ONE_TIME_UUID, oneTimeLoginUuid) MM-->>Front: {accessToken, refreshToken}