Mall StoryDevelopers
인증회원 토큰

회원 로그인

쇼핑몰이 직접 만든 화면 · 앱이 자기 로그인 폼의 아이디 · 비밀번호로 회원 토큰을 바로 받습니다. 동의 화면이 없습니다.

업데이트됨 10.13 — 회원 로그인에 회원 IP · User-Agent 를 넘길 수 있습니다

언제 쓰나

쇼핑몰이 직접 만든 화면(헤드리스 스토어프론트 · 자체 모바일 앱)이 자기 로그인 폼으로 회원을 로그인시킬 때 씁니다. 회원이 넣은 아이디 · 비밀번호를 앱의 서버가 넘기면 회원 토큰이 바로 나옵니다 — 동의 화면 · 쇼핑몰 주소로 넘어가는 일이 없습니다.

text
회원        → 앱의 로그인 폼에 아이디 · 비밀번호
앱 서버     → POST https://api.mallstory.kr/v1/member/login  (client_id · client_secret · login_id · password)
            ← access_token · refresh_token · subject=member · member_unique
앱 서버     → GET https://api.mallstory.kr/v1/me  (Authorization: Bearer access_token)
회원 로그인회원 동의
쓰는 곳쇼핑몰 자신의 화면 · 앱남의 서비스
비밀번호를 받는 곳그 앱의 로그인 폼(앱 서버)쇼핑몰 동의 화면만
동의 화면없음있음
앱 종류서버 앱(비밀 키)서버 앱 · 브라우저 · 모바일 앱
남의 서비스에는 쓰지 않습니다
이 방식은 앱이 회원 비밀번호를 직접 받습니다. 쇼핑몰 운영자가 만든 앱에만 쓰고, 다른 회사의 서비스가 회원 정보를 쓰려면 회원 동의를 쓰게 하세요.

앱 준비

  • 앱 종류는 서버 앱입니다. 비밀 키가 실리므로 반드시 서버에서 부릅니다. 브라우저 · 모바일 앱(비밀 키 없음)은 거절됩니다(unauthorized_client).
  • 권한에 회원 본인 권한(me:read · me:write)을 켭니다. 관리 권한과 한 앱에 함께 켜도 됩니다 — 이 요청으로 나가는 토큰에는 회원 권한만 실립니다.
  • 앱을 등록한 그 쇼핑몰의 회원만 로그인할 수 있습니다.

요청

POSThttps://api.mallstory.kr/v1/member/login

본문은 application/json 또는 application/x-www-form-urlencoded 입니다.

이름형식설명
client_id필수stringClient ID
client_secret필수string비밀 키. Authorization: Basic 헤더로 보내도 됩니다
login_id필수string회원이 넣은 아이디
password필수string회원이 넣은 비밀번호
scopestring공백으로 나눈 회원 권한. 없으면 앱의 회원 권한 전부(예: me:read)
bash
curl -X POST 'https://api.mallstory.kr/v1/member/login'   -H 'Content-Type: application/json'   -d '{
    "client_id": "ms_xxxxxxxxxxxx",
    "client_secret": "mss_xxxxxxxxxxxx",
    "login_id": "hong",
    "password": "회원이 넣은 비밀번호"
  }'

회원 IP 넘기기

이 API 는 앱 서버가 부르므로, 그냥 두면 쇼핑몰의 회원 로그인 기록(쇼핑몰 관리자 > 회원 > 로그인 기록)에 회원 기기가 아니라 앱 서버의 IP · 단말이 남습니다. 낯선 곳에서의 로그인 · 무차별 대입을 가리려면 회원의 값을 헤더로 넘기세요.

요청 헤더형식설명
X-Member-IPstring회원 기기의 IP 하나(IPv4 · IPv6). 앱 서버가 회원 브라우저에서 받은 요청의 접속 IP 를 넣습니다. 쉼표 목록 · 포트를 넣으면 400 invalid_request
X-Member-User-Agentstring회원 브라우저 · 앱의 User-Agent 그대로(512자까지). 기록의 운영체제 · 기기 · 브라우저가 이 값으로 정해집니다
// Express — 회원 브라우저가 앱 서버의 /login 으로 아이디 · 비밀번호를 보냈을 때
// 앱 서버가 프록시(nginx · 로드밸런서) 뒤라면 app.set("trust proxy", 1) 을 켜야 req.ip 가 회원 IP 입니다.
app.post("/login", async (req, res) => {
  const response = await fetch("https://api.mallstory.kr/v1/member/login", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Member-IP": req.ip,                                  // 회원 기기 IP
      "X-Member-User-Agent": req.get("user-agent") ?? "",     // 회원 브라우저
    },
    body: JSON.stringify({
      client_id: process.env.MALLSTORY_CLIENT_ID,
      client_secret: process.env.MALLSTORY_CLIENT_SECRET,
      login_id: req.body.login_id,
      password: req.body.password,
    }),
  });
  // … 토큰은 서버 세션에 두고 비밀번호는 버린다
});
  • 회원 IP 는 앱 서버가 직접 받은 연결에서 꺼냅니다. 회원 브라우저가 보낸 X-Forwarded-For 를 그대로 옮기면 회원이 아무 IP 나 적을 수 있습니다 — 앱 서버 앞의 내 프록시가 넣은 값(또는 소켓의 접속 IP)만 씁니다.
  • 이 헤더는 비밀 키로 앱을 확인한 뒤에만 읽습니다(서버 앱만 넘길 수 있음). X-Forwarded-For 는 쇼핑몰 앞단이 덧붙이는 칸이라 회원 IP 로 쓰지 않습니다 — 반드시 X-Member-IP 로 보냅니다.
  • 기록에는 넘긴 회원 IP 와 함께 실제로 부른 앱 서버의 IP · 앱(Client ID)이 따로 남습니다. 관리자는 로그인 기록 상세에서 '경유 앱 · 앱 서버 IP' 를 봅니다.
  • 넘기지 않아도 로그인은 됩니다 — 그때 기록의 IP 는 앱 서버의 것이고, 상세에 '회원 IP 를 넘기지 않음' 으로 보입니다.

응답

토큰 발급과 같은 모양입니다. 갱신 · 폐기도 같은 엔드포인트(/api/oauth/token · /api/oauth/revoke)를 씁니다.

json200 OK
{
  "subject": "member",
  "member_unique": "6accb17807e52ce89536610b",
  "access_token": "msat_…",
  "refresh_token": "msrt_…",
  "token_type": "Bearer",
  "expires_in": 7200,
  "scope": "me:read me:write",
  "shop_unique": "6a9515bdcb3ab5179ba767ad"
}
json400 — 비밀번호가 틀림
{
  "error": "invalid_grant",
  "error_description": "아이디 또는 비밀번호가 올바르지 않습니다."
}
상태error언제
400invalid_grant아이디 또는 비밀번호가 틀림(둘을 나누어 알려 주지 않습니다) · 정지 · 탈퇴 · 연속 실패로 잠김 · 소셜 로그인 전용 회원
400invalid_scope앱에 회원 권한이 없음 · 회원 권한이 아닌 scope 를 요청함
400unauthorized_client브라우저 · 모바일 앱(비밀 키 없음)으로 부름
400invalid_requestlogin_id · password 가 없음 · X-Member-IP 가 IP 모양이 아님
401invalid_clientClient ID · 비밀 키가 틀렸거나 앱이 중지됨

error_description 에 회원에게 보여 줄 수 있는 문구가 실립니다(예: "로그인에 여러 번 실패해 잠시 잠긴 계정입니다.").

지킬 것

  • 비밀번호를 저장하지 않습니다. 받은 즉시 이 API 로 넘기고 버립니다. 이후로는 토큰만 씁니다.
  • 토큰은 서버(HttpOnly 쿠키 · 서버 세션)에 둡니다. 브라우저 자바스크립트가 읽는 곳에 두지 않습니다.
  • 쇼핑몰 로그인과 같은 규칙이 걸립니다 — 연속 실패 잠금 · 정지 · 탈퇴 · 접속 기록. 잠긴 회원은 잠시 뒤 다시 시도해야 합니다. 접속 기록에 회원 IP 가 남게 X-Member-IP 를 넘기세요.
  • 소셜 로그인으로만 가입한 회원은 비밀번호가 없어 이 방식으로 로그인할 수 없습니다. 그 회원은 회원 동의를 씁니다.
  • 로그인한 회원은 쇼핑몰 관리자 > 설정 > 외부연동 설정 > 연결된 앱에 앱별 '회원 N명' 으로 보이고, 거기서 해지할 수 있습니다.