ⓑ 호스팅 로그인 페이지
제휴사 로그인 페이지에서 인증한 뒤 쏠브 콜백을 호출하는 방식입니다. 소셜 로그인을 운영하는 제휴사용입니다.
쏠브 앱이 제휴사의 로그인 페이지를 열면, 회원은 평소처럼 제휴사 사이트에서 로그인합니다. 로그인이 끝나면 제휴사 서버가 쏠브 콜백 API 를 호출하고, 받은 redirect_url 로 회원을 보내면 연동이 완료됩니다. 카카오·네이버·구글·Apple 같은 소셜 로그인을 운영하거나, 자체 ID/PW 와 소셜 로그인을 함께 운영하는 제휴사는 이 방식을 사용합니다.
쏠브가 전달해 드리는 값
계약 후 쏠브가 콜백 API URL, 제휴사의 platform_type(숫자), 콜백 인증 시크릿을 전달합니다. 제휴사는 쏠브 전용 로그인 페이지 URL 을 쏠브에 알려주세요.
흐름
회원
쏠브 앱
제휴사
사이트·서버
쏠브
서버
회원이 제휴사 사이트에서 책을 삽니다. 여기까지는 지금과 같습니다.
- 회원 → 제휴사: 책 구매. 회원이 제휴사 사이트에서 책을 삽니다. 여기까지는 지금과 같습니다.
- 회원 → 제휴사: 로그인 화면 열기. 쏠브 앱에서 "제휴사 연동하기"를 누르면, 앱 안에 제휴사 로그인 화면이 열립니다.
- 회원 → 제휴사: 평소처럼 로그인. 회원은 아이디나 카카오·네이버·구글 등 평소 쓰던 방법으로 로그인합니다.
- 제휴사 → 쏠브: "100023번 회원 로그인했어요". 로그인이 끝나면 제휴사 서버가 쏠브에 회원 번호를 알려 줍니다. 쏠브는 돌아갈 주소를 답해 줍니다.
- 제휴사 → 회원: 받은 주소로 이동. 제휴사가 회원 화면을 그 주소로 보내면 연동이 끝납니다. 같은 화면 안에서 이동해야 합니다.
- 쏠브 → 제휴사: "이 회원 뭐 샀어요?". 쏠브가 제휴사에 이 회원이 지금 볼 수 있는 상품을 물어봅니다.
- 제휴사 → 쏠브: 상품코드 목록. 제휴사는 구매한 상품의 코드 목록으로 답합니다. 환불된 상품은 빼고 보냅니다.
- 쏠브 → 회원: 책장에 책 추가. 쏠브가 상품코드로 전자책을 찾아 회원의 책장에 넣습니다. 상품코드는 파트너 어드민에 미리 등록해 둡니다.
1단계. 쏠브 전용 로그인 페이지 준비
- 쏠브 앱은 등록된 URL 을 그대로 엽니다. 쿼리 파라미터를 붙이지 않습니다.
- 일반 로그인과 구분할 수 있도록 쏠브 전용 URL(예:
https://www.partner.example.com/solve/login)을 따로 두세요. 이 URL 로 들어온 로그인만 쏠브 콜백으로 이어집니다. - 화면 구성과 인증 방식은 자유입니다. 기존 로그인 화면을 그대로 써도 됩니다.
- 소셜 로그인처럼 외부 사이트를 다녀오는 경우, 세션에 "쏠브 연동 중" 표시를 남겨 두었다가 로그인이 끝나는 시점에 2단계를 진행하세요.
2단계. 로그인 성공 후 쏠브 콜백 호출
로그인에 성공했을 때만 제휴사 서버에서 호출합니다. 콜백 인증 시크릿이 들어가므로 브라우저에서 호출하면 안 됩니다.
curl -X POST '<쏠브가 전달한 콜백 API URL>' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <쏠브가 발급한 콜백 인증 시크릿>' \
-d '{"id": "100023", "platform_type": <쏠브가 부여한 platform_type>}'| 헤더 | 값 | 설명 |
|---|---|---|
Authorization | Bearer <시크릿> | 쏠브가 제휴사별로 발급한 콜백 인증 시크릿. 서버 설정(환경변수 등)에만 두고 로그·브라우저에 노출하지 마세요. |
| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
id | string | 필수 | 회원의 불변·유일 식별자(= user_key), 최대 255자 |
platform_type | number | 필수 | 쏠브가 부여한 제휴사 식별자 |
solve_sso_verify_token | string | 선택 | 과거 버전 호환용입니다. 보내도 무시하며 생략해도 됩니다. |
id 에는 소셜 계정 ID·이메일을 넣지 마세요
카카오·네이버 등으로 로그인했더라도 제휴사 내부 회원의 불변 식별자(회원번호 등)를 보내야 합니다. 값이 바뀌면 회원은 연동과 책장의 책을 잃고, 탈퇴한 회원의 값을 다른 회원에게 다시 주면 안 됩니다.
응답
| 상태 코드 | 본문 | 의미와 처리 |
|---|---|---|
200 | { "redirect_url": "https://..." } | 3단계로 진행합니다. |
400 | { "error": "BadRequest", "message": "..." } | platform_type 이 틀렸거나 비활성 상태입니다. 쏠브에 문의해 주세요. |
401 | { "error": "Unauthorized", "message": "..." } | 인증 시크릿이 없거나 틀렸습니다. 재시도하지 말고 설정을 확인하세요. |
429 | 쏠브 콜백은 분당 600회까지 받습니다. 호출 한도를 넘었습니다. 응답의 Retry-After 헤더(초)만큼 기다린 뒤 다시 시도하세요. | |
500 | { "error": "InternalServerError", "message": "..." } | 쏠브 일시 오류입니다. 회원에게 잠시 후 다시 시도하도록 안내하세요. |
3단계. 같은 웹뷰에서 redirect_url 로 이동
받은 redirect_url 로 회원의 브라우저를 그대로 이동시킵니다(HTTP 302 또는 window.location.href). URL 에는 쏠브가 위변조 방지용 서명 파라미터를 함께 담아 보내므로, 파라미터를 빼거나 순서를 바꾸는 등 어떤 수정도 하지 마세요.
새 창·다른 브라우저로 열면 연동이 실패합니다
쏠브는 연동을 시작한 웹뷰에 1회용 토큰을 발급해 두고, redirect_url 로 돌아왔을 때 확인합니다. 로그인부터 이동까지 쏠브 앱이 연 같은 웹뷰 안에서 이어져야 합니다. target="_blank", 외부 브라우저 열기, 팝업 로그인 뒤 부모 창 이동 등을 쓰지 마세요.
재생 공격·CSRF 방지는 이 1회용 토큰으로 쏠브가 처리하므로, 제휴사가 state·nonce 를 따로 구현할 필요는 없습니다.
구현 예시
제휴사 로그인이 성공한 직후 호출하는 함수입니다. 일반 로그인 핸들러와 소셜 로그인 콜백 핸들러 양쪽에서, "쏠브 연동 중"인 세션일 때만 호출하세요.
// 제휴사 로그인 성공 직후, 쏠브 연동 중인 세션에서만 호출
async function completeSolveLink(req, res, member) {
const response = await fetch(process.env.SOLVE_CALLBACK_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.SOLVE_CALLBACK_SECRET}`, // 쏠브가 발급한 콜백 인증 시크릿
},
body: JSON.stringify({
id: String(member.memberNo), // 소셜 ID 가 아닌 내부 회원번호
platform_type: Number(process.env.SOLVE_PLATFORM_TYPE),
}),
signal: AbortSignal.timeout(10_000),
});
if (!response.ok) {
console.error('solve callback failed', response.status);
return res.status(502).send('쏠브 연동 중 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.');
}
const { redirect_url } = await response.json();
delete req.session.solveLinking;
return res.redirect(302, redirect_url); // 같은 웹뷰에서 이동
}콜백을 미리 시험하기
콜백 주소와 시크릿은 계약 뒤에 받지만, 그 전에도 제휴사 로그인 페이지가 콜백을 규약대로 보내는지 확인할 수 있습니다. solve-callback-mock.mjs 내려받기로 자기 PC 에 "쏠브 콜백 API 흉내"를 띄우세요. 파일 하나이며 Node.js 18 이상만 있으면 설치할 것이 없고, 받기만 할 뿐 밖으로는 아무것도 보내지 않습니다. 쏠브 서버와는 아무 관계가 없습니다.
시험용 시크릿과 platform_type 을 환경변수로 넘겨 실행합니다. 시크릿은 직접 정하되 쏠브가 받아 주는 값과 같은 조건이어야 합니다 — 32자 이상 4096자 이하, 영문·숫자·기호(공백 포함)만, 앞뒤 공백 없이. 쏠브는 32자 미만의 콜백 시크릿을 쓸 수 없는 값으로 보고 모든 콜백을 401 로 거절하므로, 짧은 값으로는 도구가 시작하지 않습니다. platform_type 은 쏠브가 부여하는 양의 정수입니다(0 이나 소수는 안 됩니다).
SOLVE_MOCK_CALLBACK_SECRET=<시험용 값> SOLVE_MOCK_PLATFORM_TYPE=<숫자> node solve-callback-mock.mjs$env:SOLVE_MOCK_CALLBACK_SECRET = "<시험용 값>"; $env:SOLVE_MOCK_PLATFORM_TYPE = "<숫자>"; node solve-callback-mock.mjs도구가 시작하면 http://127.0.0.1:4310/solve-callback 처럼 콜백 주소를 알려 줍니다. 제휴사 서버의 "쏠브 콜백 URL" 을 그 주소로, 콜백 시크릿을 위에서 정한 시험용 값으로, platform_type 을 같은 숫자로 바꾼 뒤 자기 로그인 페이지에서 로그인해 보세요. 쏠브가 계약 뒤에 전달하는 진짜 콜백 시크릿은 이 도구에 넣지 마세요.
| 확인하는 것 | 결과 |
|---|---|
| 정상 요청 | 200 과 redirect_url |
| 시크릿이 없거나 틀림 | 401 |
id 가 문자열이 아니거나 비었거나 256자 이상, platform_type 이 양의 정수가 아니거나 없거나 다름, solve_sso_verify_token 이 있는데 문자열이 아님(null 포함), Content-Type 이 JSON 이 아님 | 400 |
platform_type 이 숫자 모양의 문자열 | 200, 단 콘솔에 "숫자로 보내세요" 주의 |
POST 가 아닌 요청 | 405 |
본문이 틀리면 시크릿이 틀려도 400 입니다 — 쏠브도 인증보다 본문을 먼저 보기 때문이며, 콘솔 줄에는 시크릿 문제도 함께 나옵니다. 요청마다 콘솔에 점검 결과가 한 줄씩 나옵니다. 시크릿 값은 찍지 않고 "일치"·"불일치"만 알려 줍니다. 받은 요청의 본문·헤더·주소 원문도 화면에 싣지 않고, id 는 길이만, 필드는 이름이 아닌 통과 여부만 알려 줍니다. --next 429 또는 --next 500 을 붙이면 다음 정상 요청 한 번에 그 응답(429 는 Retry-After: 1)을 돌려주므로 제휴사의 오류 처리도 시험할 수 있습니다. --port·--host 로 주소를 바꿀 수 있고, --host 를 127.0.0.1 밖으로 바꾸면 같은 네트워크의 다른 기기에서도 접근됩니다.
도구가 돌려준 redirect_url 은 /done 주소입니다. 제휴사 서버가 이 주소로 회원의 브라우저를 수정 없이 보내면 "연동 흉내가 끝났습니다" 화면에 PASS 가 나오고, 쿼리를 하나라도 바꾸면 FAIL 과 달라진 값의 개수(빠짐·값이 바뀜·추가됨)가 나옵니다. 이름과 값은 화면에 싣지 않습니다. 쏠브가 만든 연동 주소의 서명은 10분 뒤 만료되므로, 도구도 redirect_url 을 받은 지 10분이 지나서 열면 FAIL 로 알립니다. 주소의 sig 같은 값은 서명처럼 보이게 만든 임의 값이며 진짜 서명이 아닙니다.
구현 체크리스트
- 쏠브 전용 로그인 URL 을 쏠브에 전달했다 (쿼리 파라미터 없이 동작)
- 로그인에 성공했을 때만, 제휴사 서버에서
Authorization: Bearer <시크릿>을 담아 콜백을 호출한다 - 콜백 인증 시크릿이 브라우저·로그에 노출되지 않는다
-
id로 소셜 계정 ID·이메일이 아닌 내부 회원의 불변 식별자를 보낸다 -
redirect_url을 수정 없이, 같은 웹뷰에서 연다 - 소셜 로그인으로 외부를 다녀와도 "쏠브 연동 중" 상태가 유지된다