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

Genel Bakış

Bağımlılık ekleme

Uygulamanızın build.gradle dosyasına, Kimlik Bilgisi Yöneticisi için aşağıdaki bağımlılıkları ekleyin:

Kotlin

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

Groovy

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

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ğrulama e-postası istemek için GetDigitalCredentialOption içeren bir GetCredentialRequest oluşturun. Bu seçenek, Doğrulanabilir Sunumlar için OpenID (OpenID4VP) isteği olarak biçimlendirilmiş bir requestJson dizesi gerektirir.

OpenID4VP isteği JSON'u belirli bir yapıda olmalıdır. Mevcut sağlayıcılar, dış "digital": {"requests": [...]} sarmalayıcıya sahip 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))

Ardından, openId4vpRequest JSON'u bir GetDigitalCredentialOption içine sarmalayın, bir GetCredentialRequest oluşturun ve getCredential() yöntemini çağırın.

İsteği kullanıcıya sunma

Kimlik Bilgisi Yöneticisi'nin yerleşik kullanıcı arayüzünü kullanarak isteği kullanıcıya gösterin.

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

İstemcide yanıtı ayrıştırma

Yanıtı aldıktan sonra istemcide ön ayrıştırma yapabilirsiniz. Bu, kullanıcı arayüzünü hemen güncellemek (ör. kullanıcının adını göstermek) 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 dataObject = responseData.getJSONObject("data")
val vpToken = dataObject.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ı döndürür.

Aşağıda, ham responseJsonString'nin nasıl göründüğüne ve dahili SD-JWT'yi ayrıştırdıktan sonra hak taleplerinin nasıl göründüğüne dair bir örnek verilmiştir. Bu örnekte, doğrulanmış e-postanın yanı sıra ek meta veriler de gösterilmektedir:

/*
// Example of the raw JSON response from credential.credentialJson:
{
  "protocol": "openid4vp-v1-unsigned",
  "data": {
    "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": "jane.doe.246745@gmail.com",
  "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

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

  • Verilerin özgünlüğü: Veren kuruluşun (iss) URL'sinin ve SD-JWT imzasının doğrulanması, bu verilerin güvenilir bir yetkili tarafından verildiğini kanıtlar.

Sunucudaki doğrulama işlemi şunları gerçekleştirmelidir:

  • Vereni doğrulama: iss (veren) 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 değerini de doğruladığınızdan emin olun.

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
}

Hesabın temel hazırlığı yapıldıktan sonra isteğe bağlı ancak kesinlikle önerilen bir sonraki adım, ilgili hesap için hemen geçiş anahtarı oluşturmaktır. Bu sayede kullanıcılar, güvenli ve şifresiz bir yöntemle oturum açabilir. Bu akış, standart geçiş anahtarı kaydıyla aynıdır.

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