# 직접 만든 인증 화면

> 사용자 화면과 서비스 서버의 구성 예제

문서: https://sendwich.kr/docs/examples/custom-ui/

## 구성

화면은 인증 안내와 사용자 입력을 담당하고, 서버는 sendwich API 호출과 결과 처리를 담당합니다.

| 단계 | 서비스 서버 | 화면 |
| --- | --- | --- |
| 시작 | 로그인한 사용자의 인증 시도 생성 | 인증 시작 버튼 |
| 생성 | API 호출, 사용자와 인증 ID 연결 저장 | 받는 번호·인증 문자·남은 시간 표시 |
| 대기 | 웹훅 수신 또는 결과 조회 | 전송 안내, 확인·취소 버튼 |
| 완료 | 결과 검증, 서비스 작업 처리 | 완료 화면 |

## 서버 경로

서비스 서버에 구현할 경로의 예시입니다.

| 경로 | 처리 |
| --- | --- |
| `POST /api/phone-verifications` | 사용자 인증·요청 제한, 시도 ID·state 생성, sendwich 생성 API 호출 |
| `GET /api/phone-verifications/{attempt}` | 사용자 소유 확인, 저장된 상태 반환 또는 sendwich 조회 |
| `POST /api/phone-verifications/{attempt}/cancel` | 사용자 소유 확인 후 취소 API 호출 |
| `POST /webhooks/sendwich` | 원본 본문으로 서명 검증, 연결된 시도 갱신 |

조회·취소 요청마다 시도의 소유자를 확인하고, 브라우저에는 화면에 필요한 값만 반환합니다. 쿠키 기반 로그인에서는 CSRF 방어도 적용합니다.

## 화면 데이터

```javascript
// 내 서버가 저장하고 전달한 생성 응답의 일부예요.
const instructions = {
  attempt: localAttemptId,
  destination: session.destination,
  sms_text: session.sms_text,
  expires_at: session.expires_at,
  server_time: session.server_time
};
```

받는 번호와 인증 문자를 선택·복사할 수 있도록 표시합니다. 사용자가 직접 문자를 전송하는 절차와 통신사 요금제에 따른 발송 요금을 안내합니다. 문자 앱 연결을 지원하지 않는 기기에서도 복사 기능으로 전송할 수 있어야 합니다.

## 상태 처리

`verified`, `expired`, `cancelled`를 받거나 만료 시각이 지나면 주기적인 조회를 중단합니다. 통신 오류는 결과 미확인 상태로 표시하고 다시 조회할 수 있도록 합니다. 새 인증 시도에는 새 `Idempotency-Key`를 사용합니다.

웹훅으로 데이터베이스를 갱신하면 화면은 서비스 서버에 저장된 상태를 조회할 수 있습니다. sendwich API를 직접 조회할 때마다 [사용량](https://sendwich.kr/docs/usage/)에 반영됩니다.

서버 호출은 [Node.js·Python 클라이언트](https://sendwich.kr/docs/examples/node-python/), 이벤트 수신은 [웹훅 서명 검증 예제](https://sendwich.kr/docs/webhooks/)를 참고합니다.
