문서로 건너뛰기
Go

웹훅 검증

전달의 내용을 신뢰하기 전에 서명을 확인하세요.

전달 검증하기

webhook.go
package main import (	"io"	"log"	"net/http"	"os" 	"github.com/bfzli/openemail-go") func main() {	secret := os.Getenv("OPENEMAIL_WEBHOOK_SECRET") 	http.HandleFunc("/webhooks/openemail", func(writer http.ResponseWriter, request *http.Request) {		payload, err := io.ReadAll(http.MaxBytesReader(writer, request.Body, 1<<20))		if err != nil {			writer.WriteHeader(http.StatusBadRequest) 			return		} 		event, err := openemail.VerifyWebhookSignature(payload, request.Header, secret)		if err != nil {			writer.WriteHeader(http.StatusBadRequest) 			return		} 		log.Println(event.String("type"), event.ID())		writer.WriteHeader(http.StatusNoContent)	}) 	log.Fatal(http.ListenAndServe(":8080", nil))}

openemail.VerifyWebhookSignature는 X-OpenEmail-Signature 헤더를 읽고, 타임스탬프와 본문에 대한 HMAC을 상수 시간에 확인한 뒤 이벤트를 openemail.Object로 반환합니다. 시크릿은 client.Webhooks.Create가 반환한 것입니다.

도착한 그대로의 원본 본문을 전달하세요. 파싱한 뒤 다시 인코딩한 본문은 더 이상 서명과 일치하지 않습니다.

오래된 전달

tolerance.go
payload := []byte(`{"id":"evt_1","type":"email.received"}`)headers := http.Header{"X-OpenEmail-Signature": {"t=1767225600,v1=5f2d"}} _, err := openemail.VerifyWebhookSignature(payload, headers, "whsec_example", openemail.WithTolerance(time.Minute)) if errors.Is(err, openemail.ErrWebhookSignature) {	fmt.Println("refused:", err)}

5분보다 오래된 전달은 거부되므로, 가로챈 요청을 나중에 재전송할 수 없습니다. openemail.WithTolerance로 이 5분을 바꿀 수 있고, 0이면 얼마나 오래된 전달이든 받습니다.

  • 헤더가 없거나 형식이 잘못된 경우, 서명이 일치하지 않는 경우, 전달이 너무 오래된 경우 모두 openemail.ErrWebhookSignature와 일치하는 오류를 반환합니다.
  • 시크릿을 교체한 뒤에는 전달에 서명이 둘 이상 붙을 수 있으며, 그중 하나만 일치하면 통과합니다.
  • 빠르게 2xx 상태로 응답하세요. 다른 응답을 받은 전달은 나중에 다시 시도됩니다.