콘텐츠로 이동

임베드 서명

<bf-signing>은 Bona Fide의 서명 페이지를 페이지 안의 샌드박스 iframe에 렌더링하고, 문서에 맞게 크기를 조정하며, 서명자의 동작을 DOM 이벤트로 알려 줍니다. 프레임워크에 의존하지 않으며, 가벼운 React 및 Vue 래퍼가 포함되어 있습니다.

  1. delivery: "embedded"로 봉투를 만들어 수신자에게 이메일이 가지 않도록 합니다.

  2. 서명자가 페이지를 열면 서버에서 세션을 발급하고, 사이트의 출처를 allowedOrigins에 넣습니다. 임베드 페이지는 여기에 없는 상위 페이지와는 통신하지 않습니다.

    // Your backend (never expose the API key to the browser)
    const res = await fetch(`https://api.bonafidesign.com/v1/envelopes/${envelopeId}/sessions`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.BONA_FIDE_API_KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({ recipient: recipientId, mode: 'embedded', allowedOrigins: ['https://app.example.com'] }),
    });
    const { token } = await res.json(); // 'bfs_…', single-use, 10 minutes by default
  3. 토큰으로 요소를 렌더링합니다.

    <script type="module" src="https://js.bonafidesign.com/v1"></script>
    <bf-signing session="bfs_…" theme="auto" min-height="480" max-height="90vh"></bf-signing>
    <script>
    const el = document.querySelector('bf-signing');
    el.addEventListener('completed', (e) => {
    // e.detail = { type: 'completed', envelope: 'env_…' }
    window.location.href = '/onboarding/next';
    });
    el.addEventListener('session_expiring', () => refreshSession());
    el.addEventListener('error', (e) => console.error(e.detail.code, e.detail.message));
    </script>
  4. 서버에서 확인합니다. 브라우저 이벤트는 UI 신호로만 취급하고, 결과는 envelope.completed 웹훅(또는 GET /v1/envelopes/{id})으로 판단하세요.

속성(React / Vue prop) 기본값 설명
session bfs_… 토큰. 변경하면 프레임을 다시 로드합니다
base-url(baseUrl) https://sign.bonafidesign.com/s/ 배포 환경의 호스팅 서명 경로
theme auto auto, light, dark 중 하나
locale 서명 페이지에 전달됩니다
min-height, max-height(minHeight, maxHeight) 480, 90vh 픽셀 또는 vh. 프레임은 두 값 사이에서 문서에 맞춰 커지고, 그 이상은 내부에서 스크롤됩니다
timeout 30000 페이지를 기다리는 밀리초. 넘으면 코드가 load_timeout인 error가 발생합니다
frame-title Document signing iframe의 접근성 제목

요소에는 reload() 메서드도 있습니다. 예를 들어 새 세션을 발급한 후에 사용합니다.

이벤트는 버블링되고, 섀도 루트를 넘어 전파되며, 페이로드를 event.detail에 담습니다. bf-event는 모든 이벤트에서 발생합니다.

이벤트 detail
ready { type: 'ready' }: 서명 페이지가 로드되었습니다
field_completed { type, field }: 필드가 채워졌습니다
signed { type, recipient }: 이 수신자가 제출했습니다
completed { type, envelope }: 봉투가 완료되었습니다
declined { type, reason? }
session_expiring { type, expiresAt }: 곧 새 세션을 발급하세요
error { type, code, message }. load_timeout과 invalid_base_url 포함

React prop은 onReady, onFieldCompleted, onSigned, onCompleted, onDeclined, onSessionExpiring, onError, onEvent입니다. Vue는 이벤트 이름(@completed, @session_expiring 등)과 event를 emit합니다.

  • 토큰은 iframe의 URL 프래그먼트(#session=…)로 전달되므로 서버나 Referer 헤더에 절대 도달하지 않습니다. 서명 페이지는 토큰을 읽은 뒤 URL과 기록에서 지우고, 메모리 내 액세스 토큰으로 교환합니다. 쿠키는 사용하지 않습니다.
  • iframe은 샌드박스 처리되며(allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-downloads) referrerpolicy="strict-origin"이 설정됩니다.
  • 페이지는 메시지가 요소 자체의 iframe에서 왔고, 그리고 base-url 출처에서 왔으며, 그리고 네임스페이스가 지정된 bona-fide.embed/1 메시지로 파싱될 때만 받아들입니다. 그 밖의 메시지는 모두 무시됩니다.
  • 서명 페이지는 정확한 출처로만(*는 절대 사용하지 않음), 그리고 그 출처가 세션의 allowedOrigins에 있을 때만 메시지를 보냅니다. API도 허용되지 않은 출처에서 오는 임베드 세션의 호출을 거부합니다.