오리진 트라이얼로 이메일 확인 프로토콜 테스트

게시일: 2026년 7월 8일

가입, 로그인, 구독, 결제, 계정 복구 또는 기타 프로세스의 일부로 이메일 주소를 수집할 때 이메일 주소를 입력하는 사람이 소유하고 있는지 확인하는 것이 일반적인 관행입니다. 일회용 비밀번호 (OTP) 또는 이메일 인증 링크 (매직 링크)와 같은 기존 인증 방법에서는 사용자가 사이트를 벗어나야 합니다. 이러한 방해되는 프로세스는 사람 또는 에이전트인 사용자가 세션을 완전히 포기하고 인증 프로세스를 완료하지 않을 위험을 높일 수 있습니다.

이메일 인증 API는 브라우저가 이메일 제공업체와 직접 통신하여 사용자가 이메일 주소를 소유하고 있는지 확인할 수 있도록 하는 제안입니다. 사용자는 브라우저의 자동 완성 또는 자동 완성 추천에서 이메일을 선택하고 양식을 제출하면 사이트에서 이메일을 보내거나 사용자 흐름을 방해하지 않고 제공업체에 이메일 주소를 확인합니다.

이메일 인증 API 사용자 프롬프트 데모
이메일 인증 API 사용자 프롬프트 데모

이메일 수집은 사용자 여정에서 중요한 전환점이며 Chrome 은 이메일을 확인하려는 사이트, 인증을 실행할 수 있는 이메일 제공업체, 프로세스를 경험하는 사용자로부터 제안에 관한 의견을 듣고 싶습니다. 지금 바로 오리진 트라이얼에 가입하고 여기의 구현 안내를 따르세요. 일반적인 오리진 트라이얼 구성은 오리진 트라이얼 시작하기를 참고하세요.

데모 계정으로 흐름을 시도해 볼 수 있습니다.

이메일 인증 흐름

다음 섹션에서는 사용자와 사용자가 이메일 인증 흐름을 시작하는 데 필요한 사항과 이메일 인증 프로토콜을 사용할 때의 전체 워크플로를 설명합니다.

핵심 용어

이메일 인증 API의 핵심 용어는 다음과 같습니다.

  • 검증 도구: 이메일 주소를 수집하고 확인하려는 사이트입니다. 검증 도구를 신뢰 당사자라고도 합니다.
  • 이메일 제공업체: 사용자의 이메일 주소를 제공하는 서비스입니다( 예: gmail.com).
  • 발급기관: 사용자의 이메일 계정을 관리하는 서비스입니다( 예: accounts.google.com). 발급기관을 Identity Provider라고도 합니다.

경우에 따라 이메일 제공업체와 발급기관이 동일한 도메인에서 운영될 수 있습니다. 하지만 이메일 주소를 보유하는 것과 연결된 계정에 활성 세션이 있는 것을 구분하는 것이 중요합니다.

이메일 확인 흐름 아키텍처
이메일 인증 흐름 아키텍처

기본 요건

  • 사용자는 동일한 브라우저 프로필에서 이메일 제공업체 또는 발급기관에 로그인해야 합니다. 예를 들어 Gmail을 사용하는 경우 Google 계정에 로그인해야 합니다.
  • 참여 검증 도구 사이트로서 오리진 트라이얼에 가입 하고 이메일 양식과 동일한 페이지에 토큰을 제공해야 합니다.
  • 사용자는 자동 완성 또는 자동 완성 드롭다운에서 이메일 주소를 선택해야 합니다.

    • 사용자가 이전에 필드에 이메일 주소를 입력한 경우 자동 완성을 사용하여 제공됩니다.
    • 사용자가 Chrome 설정 '자동 완성 및 비밀번호'(chrome://settings/autofill)를 사용하여 이메일 주소를 추가한 경우 자동 완성을 사용하여 제공됩니다.

  • 사용자가 인증을 위해 이메일 주소를 처음 제공할 때 권한 프롬프트가 표시됩니다. 이는 이메일 주소당 한 번만 발생합니다.

사용자가 브라우저에서 활성 세션을 보유하면 프로세스를 시작할 수 있습니다.

  1. 이메일 필드가 있는 양식에서 사용자는 자동 완성 드롭다운에서 이메일 주소를 선택합니다. 검증 도구 사이트는 이 요청을 검증하기 위해 인스턴스별 nonce가 있는 숨겨진 필드를 양식에 제공합니다.
  2. 그러면 브라우저가 이메일 도메인의 이메일 인증 DNS 레코드를 가져옵니다. 이렇게 하면 브라우저가 발급기관을 가리킵니다. 그러면 발급기관에서 해당 이메일 주소에 활성 세션이 있는지 확인합니다.

  3. 그러면 발급기관에서 주소의 이메일 인증 토큰 (EVT)을 제공합니다. 브라우저는 이를 EVT, 사이트 출처, 입력 양식의 nonce와 함께 키 바인딩 JWT로 결합합니다.

  4. 양식이 제출되면 EVT 패키지가 숨겨진 필드에 추가되고 사이트로 전송됩니다.

  5. 그러면 검증 도구 사이트에서 예상 이메일 주소, nonce, 브라우저 및 발급기관의 서명과 같은 세부정보를 각각 확인합니다.

  6. 사용자에게 이메일 제공업체에서 주소를 확인했다는 작은 알림이 표시됩니다.

이 프로세스는 검증 도구 사이트에 이메일 주소가 유효하고 현재 사용자의 소유임을 확인해 주므로 사이트에서 인증 이메일을 보내지 않아도 됩니다.

사용자는 설정 > 자동 완성 및 비밀번호 > 연락처 정보 > 인증된 이메일 (또는 chrome://settings/contactInfo 열기)에서 인증된 이메일을 관리할 수 있습니다.

사용 사례 고려사항

이메일 인증은 사용자가 OTP를 가져오거나 링크를 클릭하기 위해 사이트를 벗어나지 않아도 되는 기존 흐름의 점진적 개선입니다. 사이트는 로그인, 뉴스레터 가입, 계정 생성, 비밀번호 복구와 같은 모든 관련 양식에 이메일 인증 필드를 추가할 수 있습니다. EVP는 브라우저에서 지원하는 경우에만 트리거됩니다. 제출 시 코드가 수신되지 않거나 인증 단계 중 하나라도 실패하면 기본 이메일 확인 흐름으로 돌아갈 수 있습니다. 이는 API에 기능 감지가 없다는 의미이기도 합니다. 검증 도구 사이트는 EVT를 선택사항으로 처리하며 요청에 있는 경우 처리합니다.

이메일 인증은 사용자에게 이메일 주소 제공업체와 활성 세션이 있는지 확인합니다. 이메일이 사용자에게 도달했는지 확인하지 않습니다. 기존 환영 또는 온보딩 이메일을 계속 보내고 사용자에게 스팸 설정을 확인하라는 메시지를 표시할 수 있습니다.

검증 도구 사이트 구현

자세한 내용은 엔드 투 엔드 데모 코드 를 살펴보고 이메일 인증 API이메일 인증 프로토콜 제안의 인증 단계를 참고하세요.

양식 필드 구성

양식 필드에 올바른 속성이 있는지 확인합니다.

<input
  name="email-address"
  type="email"
  autocomplete="email">
<input
  type="hidden"
  name="token"
  nonce="rAnD0m-VaLuE"
  autocomplete="email-verification-token">

email 입력의 typeautocomplete 속성을 email로 설정하여 브라우저에서 이메일 주소의 자동 완성을 제공하도록 합니다.

hidden 필드는 양식 제출 시 이메일 인증 토큰으로 채워집니다. 필수 속성은 다음과 같습니다.

  • 이 필드에는 사용자 입력이 필요하지 않으므로 type="hidden"을 설정합니다.
  • nonce="rAnD0m-VaLuE"를 설정합니다. 사이트는 양식 제출을 확인하기 위해 고유한 세션 바인딩 nonce를 제공해야 합니다.
  • autocomplete="email-verification-token"을 설정합니다. 브라우저는 이 속성을 사용하여 채울 필드를 식별합니다.

DevTools의 네트워크 패널을 확인하여 양식 요소를 검증합니다. 이메일 주소를 선택하면 브라우저가 이메일 제공업체 및 발급기관의 DNS와 후속 계정 조회 쿼리를 트리거하는 것을 볼 수 있습니다. 이러한 요청은 내부 브라우저 요청이며 양식이 제출될 때까지 사이트에서 아무것도 수신하지 않습니다.

EVT 검증

EVT 패키지의 각 구성요소를 검증하는 데는 5단계가 있습니다.

  1. 토큰을 파싱합니다.
  2. 예상 값을 검증합니다.
  3. 키 바인딩을 검증합니다.
  4. DNS 레코드를 검증합니다.
  5. 발급기관을 검색하고 EVT 서명을 확인합니다.

1. 토큰 파싱

양식 제출의 원시 데이터에는 물결표 (~ 문자)로 구분된 선택적 공개 JSON 웹 토큰 (SD-JWT+KB)의 EVT 및 서명된 클레임이 포함되어 있습니다. 이러한 항목을 분리하고 자바스크립트 객체 서명 및 암호화 (JOSE) 헤더와 페이로드를 디코딩해야 합니다 (예: Node.js용 jose 사용).

example.comdemo@gmail.com을 확인하는 경우 디코딩된 페이로드는 다음 예와 유사합니다.

{
  "evtJwtDecodedPayload": {
    "cnf": {
      "jwk": {
        "crv": "Ed25519",
        "kty": "OKP",
        "x": "pUbLiCkEy123pUbLiCkEy123pUbLiCkEy123"
      }
    },
    "email": "demo@gmail.com",
    "email_verified": true,
    "iat": 1782911685,
    "iss": "https://accounts.google.com"
  },
  "kbJwtDecodedPayload": {
    "aud": "https://example.com",
    "iat": 1782911685,
    "nonce": "rAnDoM123rAnDoM123rAnDoM123rAnDoM123",
    "sd_hash": "hAsH456hAsH456hAsH456hAsH456hAsH456"
  }
}

2. 예상 값 검증

페이로드의 기본 값이 제공된 값과 일치하는지 확인합니다.

  • email_verifiedtrue로 설정되어 있는지 확인합니다.
  • email이 양식에 제공된 이메일 주소와 일치하는지 확인합니다.
  • nonce가 양식에 제공된 nonce와 일치하는지 확인합니다.
  • aud가 사이트의 출처와 일치하는지 확인합니다.
  • iat에 비교적 최근 타임스탬프가 있는지 확인합니다(예: 양식이 렌더링된 후).

3. 키 바인딩 검증

브라우저는 트랜잭션의 임시 키를 만들어 토큰에 서명했는지 확인합니다. EVT의 cnf (확인) 클레임에서 이 키를 추출한 후 키 바인딩 JWT를 확인하는 데 사용합니다.

그런 다음 예상 해시를 계산하고 sd_hash 클레임과 비교합니다. 다음 Node.js 예에서는 이 계산을 실행하는 방법을 보여줍니다.

const calculatedHash = createHash("sha256")
        .update(evtJwt + "~")
        .digest("base64url");

4. DNS 레코드 검증

이메일 주소 도메인의 _email-verification DNS 레코드를 확인합니다. 예를 들어 demo@gmail.com의 경우 _email-verification.gmail.com TXT 레코드를 쿼리합니다. 이 제공업체의 경우 쿼리는 계정 제공업체의 위치, 즉 accounts.google.com을 반환합니다.

$ dig +short TXT _email-verification.gmail.com
"iss=accounts.google.com"

5. 발급기관 검색 및 EVT 서명 확인

발급기관이 토큰 발급 엔드포인트, 사이트의 JSON 웹 키 (JWK), 지원되는 서명 알고리즘을 제공하는 /.well-known/email-verification 리소스를 제공하는지 확인합니다.

$ curl https://accounts.google.com/.well-known/email-verification
{
  "issuance_endpoint": "https://accounts.google.com/gsi/email-verification/issue",
  "jwks_uri": "https://verifiablecredentials-pa.googleapis.com/.well-known/vc-public-jwks",
  "signing_alg_values_supported": ["EdDSA"]
}

JWK를 사용하여 토큰에서 추출한 EVT JWT를 확인합니다. 대부분의 JOSE 라이브러리는 이 인증을 처리하는 함수를 제공합니다.

5단계가 모두 성공하면 제공업체에 대해 이메일 주소를 확인한 것입니다. 그렇지 않은 경우 일반적인 흐름에 따라 사용자에게 확인 이메일을 보내는 것으로 돌아갑니다.

이메일 제공업체 및 발급기관 서비스 구현

자세한 내용은 모의 이메일 제공업체 데모 코드 를 살펴보고 이메일 인증 API이메일 인증 프로토콜 제안의 발급기관 단계를 참고하세요.

발급기관으로서 오리진 트라이얼에 가입하거나 토큰을 제공할 필요가 없습니다. 브라우저 동작은 신뢰 당사자 사이트에 의해 트리거되기 때문입니다. 이러한 요청에 응답하려면 예상 엔드포인트가 있어야 합니다.

발급기관 검색 구성

도메인에 속한 이메일 주소가 선택될 때 브라우저가 인증 엔드포인트를 자동으로 검색하도록 하려면 DNS 및 .well-known HTTP 엔드포인트를 사용하여 구성을 노출합니다.

DNS 위임 레코드 구성

발급기관 식별자에 인증 권한을 위임하는 이메일 도메인에 DNS TXT 레코드를 구성합니다. 이러한 식별자는 인프라에 따라 동일한 도메인을 사용할 수 있습니다.

레코드 형식: _email-verification.<email-domain>

영역 파일 예:

_email-verification.example.com IN TXT "iss=accounts.issuer.example"

.well-known/email-verification 엔드포인트 호스팅

/.well-known/ 경로 아래 발급기관 도메인에 JSON 메타데이터 파일을 호스팅합니다. 이 파일은 발급 기능과 인프라에서 지원하는 암호화 서명 알고리즘을 간략하게 설명합니다.

엔드포인트: https://<issuer-domain>/.well-known/email-verification

응답 예:

{
  "issuance_endpoint": "https://accounts.issuer.example/email-verification/issuance",
  "jwks_uri": "https://accounts.issuer.example/.well-known/vc-public-jwks",
  "signing_alg_values_supported": ["EdDSA", "ES256"]
}

.well-known/web-identity 엔드포인트 호스팅

연합 사용자 인증 정보 (FedCM) API의 일부로 이미 구현했을 수 있는 추가 .well-known JSON 리소스입니다. 계정 엔드포인트 및 로그인 URL로 연결되는 링크를 제공합니다.

엔드포인트: https://<domain>/.well-known/web-identity

응답 예:

{
  "accounts_endpoint": "https://accounts.issuer.example/accounts",
  "login_url": "https://accounts.issuer.example/login"
}

계정 엔드포인트 사용

FedCM API의 계정 엔드포인트는 현재 로그인된 계정 목록을 제공합니다. 다음 예에서는 최소 응답을 보여줍니다. 자세한 내용은 ID 제공업체 구현 가이드를 참고하세요.

엔드포인트: .well-known/web-identity에 지정된 대로

다음은 응답 예시입니다.

{
  "accounts": [
    {
      "id": "demo-example",
      "name": "Demo User",
      "email": "demo@example.com",
      "given_name": "Demo"
    }
  ]
}

로그인 상태 API와 통합

사용자는 제공업체와 활성 세션을 보유해야 하며 로그인 상태 API를 사용하여 브라우저에 이를 알려야 합니다.

사용자가 성공적으로 로그인하거나 로그아웃하면 일치하는 HTTP 응답 헤더를 제공합니다.

Set-Login: logged-in
Set-Login: logged-out

또는 웹 애플리케이션 컨텍스트에서 JavaScript를 사용하여 상태를 업데이트합니다.

navigator.login.setStatus("logged-in");
navigator.login.setStatus("logged-out");

발급 요청 처리

issuance_endpointrequest_token이 포함된 application/x-www-form-urlencoded POST 요청을 수신합니다.

다음 섹션에서는 발급 요청을 처리하는 전체 프로세스를 보여줍니다.

1. 발급 요청 검증

수신 브라우저 페이로드를 파싱하고 검증합니다.

  • 메서드: POST
  • 세션 인증: 활성 인증된 ID 컨텍스트가 있는지 확인하기 위해 요청과 함께 전송된 사용자의 퍼스트 파티 session/authentication 쿠키를 검증합니다.
  • 매개변수 인증: request_token 매개변수 (브라우저에서 생성한 서명된 JWT)를 추출합니다. 예상되는 임시 공개 키, 대상 이메일, 올바른 잠재고객, 유효한 타임스탬프가 포함되어 있는지 확인합니다.

디코딩된 토큰은 다음과 같이 표시됩니다.

{
  "decodedHeader": {
    "alg": "ES256",
    "typ": "JWT",
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "pUbLiCKeY123pUbLiCKeY123pUbLiCKeY123",
      "y": "pUbLiCKeY456pUbLiCKeY456pUbLiCKeY456"
    }
  },
  "decodedPayload": {
    "iss": "https://accounts.issuer.example",
    "sub": "demo@example.com",
    "email": "demo@example.com",
    "iat": 1780272000,
    "exp": 1780272300
  },
  "signature": "SIGnatURE-123_SIGnatURE-123_SIGnatURE-123"
}

2. 토큰으로 응답

세션 및 요청 토큰이 성공적으로 검증되면 페이로드를 사용하여 서명된 선택적 공개 JWT (SD-JWT)를 생성합니다.

{
  "iss": "https://accounts.issuer.example",
  "iat": 1780272000,
  "exp": 1780272300,
  "cnf": {
    "jwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "pUbLiCKeY123pUbLiCKeY123pUbLiCKeY123",
      "y": "pUbLiCKeY456pUbLiCKeY456pUbLiCKeY456"
    }
  },
  "email": "demo@example.com",
  "email_verified": true
}

비공개 키와 지원되는 알고리즘을 사용하여 페이로드에 서명합니다. 예를 들어 Node.js에서 jose를 사용합니다.

const evtJwt = await new SignJWT(evtPayload)
   .setProtectedHeader({
     alg: "EdDSA",
     kid: PRIVATE_KEY_JWK.kid, // Key ID corresponding to our JWKS keys
     typ: "evt+jwt", // Standard Token Type for EVTs
   })
   .sign(privateKey);

 // Standard SD-JWT compatibility requires appending a trailing tilde "~"
 // to separate the signed token from the key binding section.
 const issuanceToken = `${evtJwt}~`;

성공 응답 예 (HTTP 200):

{
  "issuance_token": "tOkEn123tOkEn123tOkEn123...~"
}

오리진 트라이얼 고려사항

오리진 트라이얼은 의견을 수집하는 실험이므로 신뢰 당사자 또는 ID 제공업체로 참여하는 경우 의견이 중요합니다. 문제를 신고하려면 다음 GitHub 저장소를 사용하세요.

Chrome 구현에서 버그가 발생하면 구성요소에 대해 버그를 신고합니다.

오리진 트라이얼 기능 사용 설정은 OT 토큰 포함에 따라 응답별로 제어됩니다. 즉, 기능을 일부 사용자에게만 제한하려는 경우 세부적으로 제어할 수 있습니다. 예를 들어 이미 A/B 테스트 프레임워크가 있는 경우 오리진 트라이얼을 통합하여 제어된 실험 집단을 만들 수 있습니다. 또는 베타 테스트 또는 조기 미리보기 사용자 그룹이 있는 경우 이 그룹에 기능을 사용 설정해야 할 수 있습니다. 이 경우 토큰을 발급하거나 검증하기 전에 제공된 이메일 주소를 확인합니다.

오리진 트라이얼에는 출시 전에 기능에 의존하는 사이트를 최소화하기 위한 트래픽 한도도 있습니다. 발급기관 API는 개발 중이며 Chrome UX 업데이트와 함께 이전 버전과 호환되지 않는 변경사항이 있을 것으로 예상됩니다.

개발이 진행됨에 따라 블로그와 evp-announce@chromium.org 메일링 리스트에 추가 업데이트를 게시할 예정입니다.