Digital Credentials API ile e-posta doğrulamasını uygulama

Bu kılavuzda, OpenID for Verifiable Presentations (OpenID4VP) isteği aracılığıyla Digital Credentials Verifier API kullanılarak doğrulanmış e-posta almanın nasıl uygulanacağı açıklanmaktadır.

Bağımlılık ekleme

Uygulamanızın build.gradle dosyasına Credential Manager için aşağıdaki bağımlılıkları ekleyin:

Kotlin

dependencies {
    implementation("androidx.credentials:credentials:1.7.0-alpha01")
    implementation("androidx.credentials:credentials-play-services-auth:1.7.0-alpha01")
}

Groovy

dependencies {
    implementation "androidx.credentials:credentials:1.7.0-alpha01"
    implementation "androidx.credentials:credentials-play-services-auth:1.7.0-alpha01"
}

Kimlik Bilgisi Yöneticisi'ni başlatma

CredentialManager nesnesi oluşturmak için uygulamanızı veya etkinlik bağlamınızı kullanın.

// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)

Dijital kimlik bilgisi isteğini oluşturma

Doğrulanmış e-posta adresi istemek için GetDigitalCredentialOption içeren bir GetCredentialRequest oluşturun. Bu seçenek için requestJson Doğrulanabilir Sunumlar için OpenID (OpenID4VP) isteği olarak biçimlendirilmiş bir dize gerekir.

OpenID4VP isteği JSON'u belirli bir yapıda olmalıdır. Mevcut sağlayıcılar, dış "digital": {"requests": [...]} sarmalayıcısı olan bir JSON yapısını destekler.

        val nonce = generateSecureRandomNonce()

// This request follows the OpenID4VP spec
        val openId4vpRequest = """
    {
      "requests": [
        {
          "protocol": "openid4vp-v1-unsigned",
          "data": {
            "response_type": "vp_token",
            "response_mode": "dc_api",
            "nonce": "$nonce",
            "dcql_query": {
              "credentials": [
                {
                  "id": "user_info_query",
                  "format": "dc+sd-jwt",
                   "meta": { 
                      "vct_values": ["UserInfoCredential"] 
                   },
                  "claims": [ 
                    {"path": ["email"]}, 
                    {"path": ["name"]},  
                    {"path": ["given_name"]},
                    {"path": ["family_name"]},
                    {"path": ["picture"]},
                    {"path": ["hd"]},
                    {"path": ["email_verified"]}
                  ]
                }
              ]
            }
          }
        }
      ]
    }
    """

        val getDigitalCredentialOption = GetDigitalCredentialOption(requestJson = openId4vpRequest)
        val request = GetCredentialRequest(listOf(getDigitalCredentialOption))

İstek aşağıdaki önemli bilgileri içerir:

  • DCQL sorgusu: dcql_query, yeterlilik belgesi türünü ve istenen hak taleplerini (email_verified) belirtir. Doğrulama düzeyini belirlemek için başka hak talepleri de isteyebilirsiniz. Olası hak taleplerinden bazıları şunlardır:

    • email_verified: Yanıtta, e-postanın doğrulanıp doğrulanmadığını belirten bir Boole değeridir.
    • hd (barındırılan alan): Yanıtta bu alan boştur.
  • E-posta adresi @gmail.com ile bitmiyorsa Google, Google Hesabı oluşturulurken bu e-postayı doğrulamıştır ancak güncel olduğunu iddia etmez. Bu nedenle, Google dışı e-postalar için kullanıcıyı doğrulamak üzere ek bir doğrulama (ör. OTP) kullanmayı düşünebilirsiniz. Kimlik bilgisinin şemasını ve email_verified gibi alanları doğrulamayla ilgili özel kuralları anlamak için Google Kimliği kılavuzlarına bakın.

  • nonce: Her istek için benzersiz ve kriptografik olarak güvenli bir rastgele değer oluşturulur. Bu, tekrar oynatma saldırılarını önlediği için güvenlik açısından kritik öneme sahiptir.

  • UserInfoCredential: Bu değer, kullanıcı özelliklerini içeren belirli bir dijital kimlik türünü ifade eder. Bu bilgiyi isteğe eklemek, e-posta doğrulama kullanım alanını ayırt etmek için çok önemlidir.

Ardından, openId4vpRequest JSON'ı GetDigitalCredentialOption içine alın, GetCredentialRequest oluşturun ve getCredential()'ü çağırın.

İsteği kullanıcıya sunma

Yerleşik Kimlik Bilgisi Yöneticisi kullanıcı arayüzünü kullanarak kullanıcıya isteği sunun.

try {
    // Requesting Digital Credential from user...
    val result = credentialManager.getCredential(activity, request)

    when (val credential = result.credential) {
        is DigitalCredential -> {
            val responseJsonString = credential.credentialJson

            // Successfully received digital credential response.

            // Next, parse this response and send it to your server.
            // ...
        }

        else -> {
            // handle Unexpected State() - Up to the developer
        }
    }
} catch (e: Exception) {
    // handle exceptions - Up to the developer
}

Yanıtı istemcide ayrıştırma

Yanıtı aldıktan sonra istemcide ön ayrıştırma işlemi gerçekleştirebilirsiniz. Bu, kullanıcı adını göstermek gibi kullanıcı arayüzünü anında güncellemek için kullanışlıdır.

Aşağıdaki kod, ham Seçici Açıklama JWT'sini (SD-JWT) ayıklar ve taleplerinin kodunu çözmek için bir yardımcı kullanır.

// 1. Parse the outer JSON wrapper to get the `vp_token`
val responseData = JSONObject(responseJsonString)
val vpToken = responseData.getJSONObject("vp_token")

// 2. Extract the raw SD-JWT string
val credentialId = vpToken.keys().next()
val rawSdJwt = vpToken.getJSONArray(credentialId).getString(0)

// 3. Use your parser to get the verified claims
// Server-side validation/parsing is highly recommended.

// Assumes a local parser like the one in our SdJwtParser.kt sample
val claims = SdJwtParser.parse(rawSdJwt)
Log.d("TAG", "Parsed Claims: ${claims.toString(2)}")

// 4. Create your VerifiedUserInfo object with REAL data
val userInfo = VerifiedUserInfo(
    email = claims.getString("email"),
    displayName = claims.optString("name", claims.getString("email"))
)

Yanıtı işleme

Credential Manager API, DigitalCredential yanıtını döndürür.

Aşağıda, ham responseJsonString'nin nasıl göründüğüne ve doğrulanmış e-postanın yanı sıra ek meta veriler de aldığınız iç SD-JWT ayrıştırıldıktan sonra hak taleplerinin nasıl göründüğüne dair bir örnek verilmiştir:

/*
// Example of the raw JSON response from credential.credentialJson:
{
  "vp_token": {
    // This key matches the 'id' you set in your dcql_query
    "user_info_query": [
      // The SD-JWT string (Issuer JWT ~ Disclosures ~ Key Binding JWT)
      "eyJhbGciOiJ...~WyI...IiwgImVtYWlsIiwgInVzZXJAZXhhbXBsZS5jb20iXQ~...~eyJhbGciOiJ..."
    ]
  }
}

// Example of the parsed and verified claims from the SD-JWT on your server:
{
  "cnf": {
    "jwk": {..}
  },
  "exp": 1775688222,
  "iat": 1775083422,
  "iss": "https://verifiablecredentials-pa.googleapis.com",
  "vct": "UserInfoCredential",
  "email": "[email protected]",
  "email_verified": true,
  "given_name": "Jane",
  "family_name": "Doe",
  "name": "Jane Doe",
  "picture": "http://example.com/janedoe/me.jpg",
  "hd": ""
}
 */

Hesap oluşturma için sunucu tarafı doğrulama

Alınan e-posta şifreleme yöntemiyle doğrulandığından e-posta OTP doğrulama adımını atlayabilirsiniz. Bu sayede kayıt sürecindeki zorluklar önemli ölçüde azaltılır ve dönüşüm artabilir. Bu işlem en iyi şekilde sunucunuzda gerçekleştirilir. İstemci, ham yanıtı (vp_token içeren) ve orijinal tek seferlik rastgele sayıyı yeni bir sunucu uç noktasına gönderir.

Doğrulama için uygulamanız, hesap oluşturmadan veya kullanıcıyı oturum açmadan önce tam responseJsonString değerini kriptografik doğrulama için sunucunuza göndermelidir.

Dijital kimlik bilgisi, sunucunuz için iki önemli doğrulama düzeyi sağlar:

  • Verilerin gerçekliği: Veren (iss) URL'sinin ve SD-JWT imzasının doğrulanması, bu verilerin güvenilir bir yetkili tarafından verildiğini kanıtlar.
  • Sunan kişinin kimliği: cnf alanı ve anahtar bağlama (kb) imzası doğrulanarak kimlik bilgisinin, ilk olarak verildiği cihaz tarafından paylaşıldığı onaylanır. Böylece, kimlik bilgisinin başka bir cihazda ele geçirilmesi veya kullanılması önlenir.

Sunucudaki doğrulama aşağıdaki koşulları karşılamalıdır:

  • Düzenleyeni doğrulayın: iss (düzenleyen) alanının https://verifiablecredentials-pa.googleapis.com ile eşleştiğinden emin olun.
  • İmzayı doğrulama: https://verifiablecredentials-pa.googleapis.com/.well-known/vc-public-jwks adresinde bulunan ortak anahtarları (JWK'ler) kullanarak SD-JWT'nin imzasını kontrol edin.

Tam güvenlik için, tekrar oynatma saldırılarını önlemek amacıyla nonce öğesini de doğruladığınızdan emin olun.

Bu adımları birleştirerek sunucunuz hem verilerin gerçekliğini hem de sunan kişinin kimliğini doğrulayabilir. Böylece, yeni hesap sağlanmadan önce kimlik bilgilerinin ele geçirilmediği veya sahtesinin oluşturulmadığı doğrulanır.

try {
    // Send the raw credential response and the original nonce to your server.
    // Your server must validate the response. createAccountWithVerifiedCredentials
    // is a custom implementation per each RP for server side verification and account creation.
    val serverResponse = createAccountWithVerifiedCredentials(responseJsonString, nonce)

    // Server returns the new account info (e.g., email, name)
    val claims = JSONObject(serverResponse.json)

    val userInfo = VerifiedUserInfo(
        email = claims.getString("email"),
        displayName = claims.optString("name", claims.getString("email"))
    )

    // handle response - Up to the developer
} catch (e: Exception) {
    // handle exceptions - Up to the developer
}

Geçiş anahtarı oluşturma

Hesap sağlandıktan sonra isteğe bağlı ancak kesinlikle önerilen bir sonraki adım, bu hesap için hemen geçiş anahtarı oluşturmaktır. Bu, kullanıcının oturum açması için güvenli ve şifresiz bir yöntem sağlar. Bu akış, standart geçiş anahtarı kaydıyla aynıdır.

WebView desteği

Akışın WebView'da çalışması için geliştiricilerin, devri kolaylaştırmak amacıyla JavaScript köprüsü (JS köprüsü) uygulaması gerekir. Bu köprü, WebView'un yerel uygulamaya sinyal göndermesine olanak tanır. Yerel uygulama daha sonra Credential Manager API'ye gerçek çağrıyı yapabilir.

Ayrıca bkz.