Initiate provisioning

Issuer-initiated provisioning allows users to start the provisioning process directly from your app or website. This flow is useful when you want to encourage users who are already engaged with your platform to add their verifiable digital credential to Google Wallet.

To initiate provisioning from your issuer app or website, you must construct a CredentialOffer and pass it to the platform-specific API.

Android

On Android, use CredentialManager to initiate the provisioning flow.

Implementation

The following example demonstrates how to construct the request and call createCredential in your ViewModel.

// HomeViewModel.kt

import androidx.credentials.CredentialManager
import androidx.credentials.CreateDigitalCredentialRequest
// ... other imports

class HomeViewModel : ViewModel() {

  fun onAddToWalletClicked(activity: Activity) {
    viewModelScope.launch {
      // 1. Gather the necessary data (protocol, issuerId, authCode)
      val currentProtocol = _uiState.value.protocol
      val currentIssuerId = _uiState.value.issuerId
      val currentAuthorizationCode = _uiState.value.authorizationCode

      try {
        // 2. Construct the Credential Offer JSON
        // The structure matches the "digital" object in the Web API.
        val credentialOfferJson = JSONObject().apply {
          put("requests", JSONArray().apply {
            put(JSONObject().apply {
              put("protocol", currentProtocol)
              put("data", JSONObject().apply {
                put("credential_issuer", currentIssuerId)
                put("credentials", JSONArray()) // Add specific credentials if needed
                put("grants", JSONObject().apply {
                  put("authorization_code", JSONObject().apply {
                    put("issuer_state", currentAuthorizationCode)
                  })
                })
              })
            })
          })
        }.toString()

        // 3. Initiate the flow using CredentialManager
        val response = CredentialManager.create(activity).createCredential(
          activity,
          CreateDigitalCredentialRequest(credentialOfferJson)
        )

        // Handle successful response
        _uiState.update { it.copy(result = Result.Credential("Credential creation request sent")) }

      } catch (e: Exception) {
        // Handle errors (e.g., user cancellation, API errors)
        Log.e("HomeViewModel", "Failed to create credential: $e")
        _uiState.update { it.copy(result = Result.Error(e.message)) }
      }
    }
  }
}

UI (Jetpack Compose)

Call the ViewModel method from your composable.

// HomeScreen.kt

@Composable
fun HomeScreen(viewModel: HomeViewModel) {
  // ... UI setup ...

  FloatingActionButton(onClick = {
    val currentActivity = LocalActivity.current
    // Pass the Activity context to CredentialManager
    viewModel.onAddToWalletClicked(requireNotNull(currentActivity))
  }) {
    Text("Add to Wallet")
  }

  // ... Rest of UI ...
}

Web

On the web, you use the Digital Credentials API to initiate the flow.

Implementation

Use navigator.credentials.create() with the openid4vci1.0 protocol.

issueButton.addEventListener('click', async () => {
  const protocol = 'openid4vci1.0';
  const issuerId = 'https://credential-issuer.example.com';
  const preAuthCode = '...'; // Your pre-authorized code

  // Construct the request object matching the "digital" request structure
  const request = {
    "protocol": protocol,
    "data": {
      "credential_issuer": issuerId,
      "credentials": [],
      "grants": {
        "authorization_code": {
          "issuer_state": preAuthCode
        }
      }
    }
  };

  try {
    // Request the credential
    await navigator.credentials.create({
      digital: {
        requests: [request]
      }
    });
    console.log('Credential issued successfully!');
  } catch (error) {
     console.error('Credential request failed:', error);
  }
});

Prerequisites

  • A configured Google Wallet Issuer account.

Request Structure

The request structure for initiating provisioning is consistent across Android and Web.

  {
    "protocol": "<protocol>",
    "data": {
      "credential_issuer": "https://credential-issuer.example.com",
      "credentials": [
        // Optional: Specific credential types to request
      ],
      "grants": {
        "authorization_code": {
          "issuer_state": "..." // Pre-authorized code or state
        }
      }
    }
  }

Sequence Diagram

The following diagram illustrates the flow for Issuer-initiated provisioning.

Configurable Values

  • protocol
    • example: google-canonical or openid4vci1.0(coming soon)
  • credentialIssuer
    • example: "https://credential-issuer.example.com"
  • credentialConfigurationIds
    • example: ["eu.europa.ec.av.1"]

Next steps

Once the provisioning intent is launched, the flow merges with the standard device registration process.

Proceed to Device registration.