E-posta sağlayıcı (düzenleyen) uygulaması

Daha fazla bilgi için sahte e-posta sağlayıcı demo kodunu inceleyebilir ve E-posta Doğrulama API'si ile E-posta Doğrulama Protokolü önerilerindeki veren adımlarına bakabilirsiniz.

Tarayıcı davranışını tetikleyen taraf güvenen taraf sitesi olduğundan, kart sağlayıcı olarak, kaynak denemesine kaydolmanız veya jeton sağlamanız gerekmez. Uç noktalarınızın bu isteklere yanıt verecek şekilde yapılandırıldığından emin olun.

Kart sağlayıcı keşfini yapılandırma

Tarayıcıların, alanınıza ait bir e-posta adresi seçildiğinde doğrulama uç noktalarınızı otomatik olarak keşfetmesine izin vermek için DNS ve .well-known HTTP uç noktası kullanarak yapılandırmanızı kullanıma sunun.

DNS temsilci kaydını yapılandırma

E-posta alanınızda, doğrulama yetkisini veren kimlik sağlayıcınıza devreden bir DNS TXT kaydı yapılandırın. Bu tanımlayıcılar, altyapınıza bağlı olarak aynı alanı kullanabilir.

Kayıt Biçimi: _email-verification.<email-domain>

Örnek alan dosyası:

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

.well-known/email-verification uç noktası barındırma

Düzenleyen alanınızda /.well-known/ yolu altında bir JSON meta veri dosyası barındırın. Bu dosyada, düzenleme özellikleriniz ve altyapınızın desteklediği kriptografik imzalama algoritmaları özetlenir.

Uç nokta: https://<issuer-domain>/.well-known/email-verification

Örnek yanıt:

{
  "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 uç noktası barındırma

Federated Credentials (FedCM) API'nin bir parçası olarak ek bir .well-known JSON kaynağı uygulamış olabilirsiniz. Bu kaynak, hesap uç noktanıza ve giriş URL'nize bağlantılar sağlar.

Uç nokta: https://<domain>/.well-known/web-identity

Örnek yanıt:

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

Hesap uç noktası kullanma

FedCM API'deki hesaplar uç noktası, şu anda oturum açılmış hesapların listesini sağlar. Aşağıdaki örnekte minimum düzeyde bir yanıt gösterilmektedir. Daha fazla bilgi için kimlik sağlayıcı uygulama kılavuzuna bakın.

Uç nokta: .well-known/web-identity içinde belirtildiği gibi

Aşağıda örnek bir yanıt verilmiştir:

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

Login Status API ile entegrasyon

Kullanıcının sağlayıcıyla etkin bir oturumu olmalı ve Login Status API'yi kullanarak bunu tarayıcıya bildirmeniz gerekir.

Bir kullanıcı başarılı bir şekilde oturum açtığında veya oturumu kapattığında eşleşen HTTP yanıt başlığını yayınlayın:

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

Alternatif olarak, web uygulamanızda JavaScript kullanarak durumu güncelleyin:

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

Yayınlama isteklerini işleme

issuance_endpoint, application/json POST isteği alıyor. Bu istekte email anahtarı ve Signature, Signature-Input ve Signature-Key için HTTP mesajı imzaları üst bilgileri yer alıyor.

Ortamınız için yapılandırılmış üstbilgileri ve HTTP mesaj imzalarını destekleyen bir kitaplık kullanın. Node.js'de structured-headers ve http-message-sig kullanabilirsiniz.

Tam istek biçimi:

POST /email-verification/issuance HTTP/1.1
Host: provider.example
Accept: application/json
Content-Digest: sha-256=:aBc123aBc123aBc123aBc123aBc123=:
Content-Type: application/json
Sec-Fetch-Dest: email-verification
Signature: sig=:+dEf567dEf567/dEf567dEf567dEf567/dEf567==:
Signature-Input: sig=("@method" "@authority" "@path" "content-digest" "signature-key");created=1786455840
Signature-Key: sig=hwk;crv="Ed25519";kty="OKP";x="gHi890_gHi890_gHi890"

{email: "demo@example.com"}

İsteği ayrıştırın ve doğrulayın:

  • Oturum kimlik doğrulaması: İstekle birlikte gönderilen birinci taraf oturum çerezlerinizi doğrulayın. Kullanıcının kimliği doğrulanmalıdır.
  • Sec-Fetch-Dest üstbilgisi: email-verification olarak ayarlayın.
  • HTTP Mesaj İmzaları: Signature-Key içindeki kısa ömürlü ortak anahtarı kullanarak istek imzasını doğrulayın ve Content-Digest öğesini onaylayın.
  • Yük: JSON gövdesi, doğrulama için istenen email dizesini içerir.

Verilme yanıtı

Oturum ve istek jetonu başarıyla doğrulandıktan sonra, platformunuz için uygun kitaplıkları kullanarak JSON olarak döndürülen imzalı bir Selective Disclosure JWT (SD-JWT) oluşturun. Örneğin, Node için @sd-jwt/core ve jose kullanabilirsiniz.

Ham yük biçimi şu şekilde görünmelidir:

{
  "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
}

Jetonu oluşturun, imzalayın ve döndürün:

import { importJWK, CompactSign } from "jose";
import { SDJwtInstance } from "@sd-jwt/core";
import crypto from "node:crypto";
// Issuer private key from secure storage
const privateKey = await importJWK(PRIVATE_KEY_JWK, "EdDSA");
const origin = url.origin;
const currentTime = Math.floor(Date.now() / 1000);
const evtPayload = {
  iss: origin,
  iat: currentTime,
  exp: currentTime + 300, // 5 minutes
  cnf: {
    jwk: browserJwk,
  },
  email: payload.email, // exactly as received in payload
  email_verified: true,
};
const sdJwt = new SDJwtInstance({
  signer: async (data) => {
    const [headerB64, payloadB64] = data.split(".");
    const header = JSON.parse(Buffer.from(headerB64, "base64url").toString());
    const payload = Buffer.from(payloadB64, "base64url");
    const signed = await new CompactSign(payload).setProtectedHeader(header).sign(privateKey);
    return signed.split(".").pop()!;
  },
  signAlg: "EdDSA",
  hasher: async (data, alg) => {
    const nodeAlg = alg.replace("-", "");
    return new Uint8Array(crypto.createHash(nodeAlg).update(data).digest());
  },
  hashAlg: "sha-256",
  saltGenerator: async () => crypto.randomBytes(16).toString("base64url"),
});
const issuanceToken = await sdJwt.issue(evtPayload, undefined, {
  header: {
    alg: "EdDSA",
    kid: PRIVATE_KEY_JWK.kid,
    typ: "evt+jwt",
  },
});
return sendResponse({ issuance_token: issuanceToken, }, 200);

Elde edilen yanıt gövdesi şuna benzer:

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

E-posta doğrulama jetonunu oluşturup imzaladıktan sonra tarayıcı, bunu doğrulama için doğrulayıcı siteye iletir.

Sorun giderme

Tarayıcı, uç noktalarınıza ulaşmıyorsa veya verilen jetonları reddediyorsa aşağıdaki yaygın sorunları kontrol edin:

Tarayıcı hiçbir zaman accounts_endpoint veya issuance_endpoint işlevini çağırmaz.

  • Oturum açma durumu ayarlanmadı: Chrome, yalnızca kullanıcının oturum açtığını biliyorsa uç noktalarınıza sorgu gönderir. Oturum açma akışınızın Set-Login: logged-in HTTP üstbilgisini ayarladığından veya navigator.login.setStatus("logged-in") işlevini çağırdığından emin olun.
  • Oturum çerezleri engellendi (SameSite=None): Tarayıcı, accounts_endpoint ve issuance_endpoint öğelerinizi farklı bir sitedeki güvenilen taraftan getiriyor. Bunlar siteler arası istekler olduğundan oturum çereziniz SameSite=None; Secure içermelidir. SameSite=Lax çerezi, aynı site doğrulayıcıda test edilirken çalışır ancak siteler arası isteklerde atlanır.
  • Keşif veya hesap eşleşmemesi: _email-verification.<email-domain>'nin tek bir TXT kaydı (iss=<issuer-domain>, https:// olmadan) döndürdüğünü, her iki .well-known uç noktasının Content-Type: application/json döndürdüğünü ve accounts_endpoint yanıtının, email'si girilen adresle eşleşen bir hesap içerdiğini doğrulayın.

Düzenleme isteği doğrulanamadı

  • Sec-Fetch-Dest üstbilgi yazımı: Chrome 154 ve sonraki sürümlerinde Sec-Fetch-Dest: email-verification (tireli) gönderilirken Chrome 153'te emailverification (tiresiz) gönderiliyordu. Kullanıma sunma sırasında her iki değeri de kabul edin.
  • Proxy'nin arkasında HTTP mesaj imzası (@authority) eşleşmemesi: RFC 9421 imzası doğrulanırken @authority bileşeni, herkese açık ana makineyi yansıtır. Sunucunuz bir ters proxy'nin veya yük dengeleyicinin arkasında bulunuyorsa doğrulama URL'sini dahili ana makine adı yerine X-Forwarded-Host (veya herkese açık kaynağınız) kullanarak yeniden oluşturun ve JSON ayrıştırmadan önce ham istek gövdesi baytları üzerinde Content-Digest hesaplayın.

Tarayıcı, döndürülen issuance_token öğesini reddediyor

  • Değiştirilmiş veya kanonikleştirilmiş email talebi: Chrome 156'dan itibaren tarayıcı, EVT email talebinin istenen email ile bire bir eşleşip eşleşmediğini kontrol eder. Arka uçunuz adresi kanonik bir hesap biçimine normalleştirirse (ör. First.Last@example.com istendiğinde first.LAST@example.com döndürülürse) Chrome, jetonu bırakır. İsteği kullanıcının hesabıyla eşleştirin ancak istek gövdesinde alınan tam email dizesini döndürün.
  • Sondaki tilde (~) eksik: Hiç açıklama olmasa bile tarayıcının <KB-JWT> ekleyebilmesi için issuance_token, sondaki tilde (<Issuer-signed-JWT>~) ile biten geçerli bir SD-JWT olmalıdır.
  • Eşleşmeyen iss veya cnf.jwk: EVT iss talebinin, .well-known/email-verification meta verilerinizle eşleşen tam HTTPS kaynağı (https://<issuer-domain>, sondaki eğik çizgi yok) olduğundan ve cnf.jwk'nin Signature-Key üstbilgisinden tarayıcının kısa ömürlü ortak anahtarını yerleştirdiğinden emin olun.