Skip to content

Commit 4f8d2a8

Browse files
committed
[VCI] Do not error when token response doesn't have a scope defined
1 parent a28bdbc commit 4f8d2a8

1 file changed

Lines changed: 68 additions & 61 deletions

File tree

app/src/main/java/com/credman/cmwallet/createcred/CreateCredentialViewModel.kt

Lines changed: 68 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -91,84 +91,91 @@ class CreateCredentialViewModel : ViewModel() {
9191
viewModelScope.launch {
9292
// Figure out auth server
9393
val authServer = openId4VCI.authServerIdentifier()
94+
val scope = openId4VCI.credentialOffer.credentialConfigurationIds.first()
9495
val tokenResponse = openId4VCI.requestTokenFromEndpoint(
9596
authServer, TokenRequest(
9697
grantType = "authorization_code",
9798
code = code,
9899
redirectUri = redirectUrl,
99100
clientId = WALLET_CLIENT_ID,
100-
scope = openId4VCI.credentialOffer.credentialConfigurationIds.first(),
101+
scope = scope,
101102
codeVerifier = openId4VCI.codeVerifier
102103
)
103104
)
104105
Log.i(TAG, "tokenResponse $tokenResponse")
105-
processToken(tokenResponse)
106+
processToken(tokenResponse, tokenRequestScope = scope)
106107
}
107108
}
108109

109110
@OptIn(ExperimentalUuidApi::class)
110-
private suspend fun processToken(tokenResponse: TokenResponse) {
111+
private suspend fun processToken(
112+
tokenResponse: TokenResponse,
113+
tokenRequestScope: String? // Fallback when the tokenResponse doesn't contain a scope property
114+
) {
111115
val newCredentials = mutableListOf<CredentialItem>()
112-
tokenResponse.scopes?.split(" ")?.forEach { scope ->
113-
val deviceKeys: MutableList<KeyPair> = mutableListOf()
114-
val kpg = KeyPairGenerator.getInstance("EC")
115-
kpg.initialize(ECGenParameterSpec("secp256r1"))
116-
for (i in 0..< (openId4VCI.credentialOffer.issuerMetadata.batchCredentialIssuance?.batchSize ?: 1)) {
117-
deviceKeys.add(kpg.genKeyPair())
118-
}
119-
val credentialResponse = openId4VCI.requestCredentialFromEndpoint(
120-
accessToken = tokenResponse.accessToken,
121-
credentialRequest = CredentialRequest(
122-
credentialConfigurationId = scope,
123-
proofs = openId4VCI.createProofJwt(deviceKeys)
116+
if (tokenResponse.authorizationDetails == null) {
117+
val scopes = (tokenResponse.scopes ?: tokenRequestScope)?.split(" ")
118+
scopes?.forEach { scope ->
119+
val deviceKeys: MutableList<KeyPair> = mutableListOf()
120+
val kpg = KeyPairGenerator.getInstance("EC")
121+
kpg.initialize(ECGenParameterSpec("secp256r1"))
122+
for (i in 0..< (openId4VCI.credentialOffer.issuerMetadata.batchCredentialIssuance?.batchSize ?: 1)) {
123+
deviceKeys.add(kpg.genKeyPair())
124+
}
125+
val credentialResponse = openId4VCI.requestCredentialFromEndpoint(
126+
accessToken = tokenResponse.accessToken,
127+
credentialRequest = CredentialRequest(
128+
credentialConfigurationId = scope,
129+
proofs = openId4VCI.createProofJwt(deviceKeys)
130+
)
124131
)
125-
)
126-
Log.i(TAG, "credentialResponse $credentialResponse")
127-
val config = openId4VCI.credentialOffer.issuerMetadata.credentialConfigurationsSupported[scope]!!
128-
val display = credentialResponse.display?.firstOrNull()
129-
val configDisplay = config.credentialMetadata?.display?.firstOrNull()
130-
val newCredentialItem = CredentialItem(
131-
id = Uuid.random().toHexString(),
132-
config = config,
133-
displayData = CredentialDisplayData(
134-
title = display?.name ?: configDisplay?.name ?: "Unknown",
135-
subtitle = display?.description ?: configDisplay?.description,
136-
icon = display?.logo?.uri.imageUriToImageB64()
137-
),
138-
credentials = credentialResponse.credentials!!.map {
139-
val deviceKeyPair = when (config) {
140-
is CredentialConfigurationMDoc -> {
141-
val mdoc = MDoc(it.credential.decodeBase64UrlNoPadding())
142-
val deviceKey = mdoc.deviceKey
143-
deviceKeys.firstOrNull {
144-
val public = it.public as ECPublicKey
145-
val x = String(public.w.affineX.toFixedByteArray(32))
146-
val y = String(public.w.affineY.toFixedByteArray(32))
147-
x == deviceKey.first && y == deviceKey.second
132+
Log.i(TAG, "credentialResponse $credentialResponse")
133+
val config = openId4VCI.credentialOffer.issuerMetadata.credentialConfigurationsSupported[scope]!!
134+
val display = credentialResponse.display?.firstOrNull()
135+
val configDisplay = config.credentialMetadata?.display?.firstOrNull()
136+
val newCredentialItem = CredentialItem(
137+
id = Uuid.random().toHexString(),
138+
config = config,
139+
displayData = CredentialDisplayData(
140+
title = display?.name ?: configDisplay?.name ?: "Unknown",
141+
subtitle = display?.description ?: configDisplay?.description,
142+
icon = display?.logo?.uri.imageUriToImageB64()
143+
),
144+
credentials = credentialResponse.credentials!!.map {
145+
val deviceKeyPair = when (config) {
146+
is CredentialConfigurationMDoc -> {
147+
val mdoc = MDoc(it.credential.decodeBase64UrlNoPadding())
148+
val deviceKey = mdoc.deviceKey
149+
deviceKeys.firstOrNull {
150+
val public = it.public as ECPublicKey
151+
val x = String(public.w.affineX.toFixedByteArray(32))
152+
val y = String(public.w.affineY.toFixedByteArray(32))
153+
x == deviceKey.first && y == deviceKey.second
154+
}
148155
}
149-
}
150-
is CredentialConfigurationSdJwtVc -> {
151-
val issuerJwtString = it.credential.split('~')[0]
152-
val cnfKey = IssuerJwt(issuerJwtString).payload.getJSONObject("cnf").getJSONObject("jwk")
153-
deviceKeys.firstOrNull {
154-
val public = it.public as ECPublicKey
155-
val x = public.w.affineX.toFixedByteArray(32).toBase64UrlNoPadding()
156-
val y = public.w.affineY.toFixedByteArray(32).toBase64UrlNoPadding()
157-
x == cnfKey.getString("x") && y == cnfKey.getString("y")
156+
is CredentialConfigurationSdJwtVc -> {
157+
val issuerJwtString = it.credential.split('~')[0]
158+
val cnfKey = IssuerJwt(issuerJwtString).payload.getJSONObject("cnf").getJSONObject("jwk")
159+
deviceKeys.firstOrNull {
160+
val public = it.public as ECPublicKey
161+
val x = public.w.affineX.toFixedByteArray(32).toBase64UrlNoPadding()
162+
val y = public.w.affineY.toFixedByteArray(32).toBase64UrlNoPadding()
163+
x == cnfKey.getString("x") && y == cnfKey.getString("y")
164+
}
158165
}
166+
else -> throw UnsupportedOperationException("Unknown configuration $config")
159167
}
160-
else -> throw UnsupportedOperationException("Unknown configuration $config")
168+
Credential(
169+
key = CredentialKeySoftware(
170+
publicKey = Base64.encodeToString(deviceKeyPair!!.public.encoded, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP),
171+
privateKey = Base64.encodeToString(deviceKeyPair.private.encoded, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP),
172+
),
173+
credential = it.credential
174+
)
161175
}
162-
Credential(
163-
key = CredentialKeySoftware(
164-
publicKey = Base64.encodeToString(deviceKeyPair!!.public.encoded, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP),
165-
privateKey = Base64.encodeToString(deviceKeyPair.private.encoded, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP),
166-
),
167-
credential = it.credential
168-
)
169-
}
170-
)
171-
newCredentials.add(newCredentialItem)
176+
)
177+
newCredentials.add(newCredentialItem)
178+
}
172179
}
173180
tokenResponse.authorizationDetails?.forEach { authDetail ->
174181
when (authDetail) {
@@ -300,18 +307,18 @@ class CreateCredentialViewModel : ViewModel() {
300307

301308
if (openId4VCI.credentialOffer.grants!!.preAuthorizedCode != null) {
302309
val grant = openId4VCI.credentialOffer.grants!!.preAuthorizedCode
303-
310+
val scope = openId4VCI.credentialOffer.credentialConfigurationIds.first()
304311
val tokenResponse = openId4VCI.requestTokenFromEndpoint(
305312
authServer, TokenRequest(
306313
grantType = "urn:ietf:params:oauth:grant-type:pre-authorized_code",
307314
preAuthorizedCode = grant?.preAuthorizedCode,
308315
txCode = "123456",
309316
clientId = WALLET_CLIENT_ID,
310-
scope = openId4VCI.credentialOffer.credentialConfigurationIds.first()
317+
scope = scope
311318
)
312319
)
313320
Log.i(TAG, "tokenResponse $tokenResponse")
314-
processToken(tokenResponse)
321+
processToken(tokenResponse, tokenRequestScope = scope)
315322

316323
} else if (openId4VCI.credentialOffer.grants!!.authorizationCode != null) {
317324
val grant = openId4VCI.credentialOffer.grants!!.authorizationCode!!

0 commit comments

Comments
 (0)