Skip to content

Commit

Permalink
fix: several oid4vc fixes (#1972)
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <timo@animo.id>
  • Loading branch information
TimoGlastra committed Jul 30, 2024
1 parent cebfcce commit 2110e4a
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 5 deletions.
5 changes: 5 additions & 0 deletions .changeset/chatty-pens-hope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@credo-ts/openid4vc': patch
---

fix: incorrect generation of code verifier for pkce
5 changes: 5 additions & 0 deletions .changeset/four-dodos-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@credo-ts/openid4vc': patch
---

fix: include client_id when requesting credential using authorization_code flow
23 changes: 18 additions & 5 deletions packages/openid4vc/src/openid4vc-holder/OpenId4VciHolderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import type {
AuthorizationDetailsJwtVcJson,
CredentialIssuerMetadataV1_0_11,
CredentialIssuerMetadataV1_0_13,
AuthorizationDetailsJwtVcJsonLdAndLdpVc,
AuthorizationDetailsSdJwtVc,
} from '@sphereon/oid4vci-common'

import {
Expand Down Expand Up @@ -59,6 +61,7 @@ import {
OpenID4VCIClient,
OpenID4VCIClientV1_0_11,
OpenID4VCIClientV1_0_13,
OpenID4VCIClientStateV1_0_13,
} from '@sphereon/oid4vci-client'
import { CodeChallengeMethod, OpenId4VCIVersion, PARMode, post } from '@sphereon/oid4vci-common'

Expand Down Expand Up @@ -163,15 +166,15 @@ export class OpenId4VciHolderService {
types: offeredCredential.types,
}

return { type, format, locations, credential_definition }
return { type, format, locations, credential_definition } satisfies AuthorizationDetailsJwtVcJsonLdAndLdpVc
} else if (format === OpenId4VciCredentialFormatProfile.SdJwtVc) {
return {
type,
format,
locations,
vct: offeredCredential.vct,
claims: offeredCredential.claims,
}
} satisfies AuthorizationDetailsSdJwtVc
} else {
throw new CredoError(`Cannot create authorization_details. Unsupported credential format '${format}'.`)
}
Expand All @@ -185,7 +188,7 @@ export class OpenId4VciHolderService {
const { metadata, offeredCredentials } = resolvedCredentialOffer
const codeVerifier = (
await Promise.all([agentContext.wallet.generateNonce(), agentContext.wallet.generateNonce()])
).join()
).join('')
const codeVerifierSha256 = Hasher.hash(codeVerifier, 'sha-256')
const codeChallenge = TypedArrayEncoder.toBase64URL(codeVerifierSha256)

Expand Down Expand Up @@ -217,7 +220,7 @@ export class OpenId4VciHolderService {
codeChallengeMethod: CodeChallengeMethod.S256,
codeVerifier,
},
},
} satisfies OpenID4VCIClientStateV1_0_13,
}

const client =
Expand All @@ -228,7 +231,7 @@ export class OpenId4VciHolderService {
const authorizationRequestUri = await client.createAuthorizationRequestUrl({
authorizationRequest: {
redirectUri,
scope: scope ? scope[0] : 'openid',
scope: scope ? scope.join(' ') : undefined,
authorizationDetails: authDetails,
parMode: PARMode.AUTO,
},
Expand Down Expand Up @@ -308,6 +311,7 @@ export class OpenId4VciHolderService {
resolvedAuthorizationRequestWithCode?: OpenId4VciResolvedAuthorizationRequestWithCode
accessToken?: string
cNonce?: string
clientId?: string
}
) {
const { resolvedCredentialOffer, acceptCredentialOfferOptions } = options
Expand Down Expand Up @@ -390,12 +394,21 @@ export class OpenId4VciHolderService {
.withEndpointMetadata(metadata)
.withAlg(signatureAlgorithm)

// TODO: what if auth flow using did, and the did is different from client id. We now use the client_id
if (credentialBinding.method === 'did') {
proofOfPossessionBuilder.withClientId(parseDid(credentialBinding.didUrl).did).withKid(credentialBinding.didUrl)
} else if (credentialBinding.method === 'jwk') {
proofOfPossessionBuilder.withJWK(credentialBinding.jwk.toJson())
}

// Add client id if in auth flow. This may override the clientId from the did binding method. But according to spec,
// the "value of this claim MUST be the client_id of the Client making the Credential request."
if (options.clientId || options.resolvedAuthorizationRequestWithCode?.clientId) {
proofOfPossessionBuilder.withClientId(
(options.clientId || options.resolvedAuthorizationRequestWithCode?.clientId) as string
)
}

if (newCNonce) proofOfPossessionBuilder.withAccessTokenNonce(newCNonce)

const proofOfPossession = await proofOfPossessionBuilder.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,13 @@ export interface OpenId4VciCredentialRequestOptions extends Omit<OpenId4VciAccep
resolvedCredentialOffer: OpenId4VciResolvedCredentialOffer
accessToken: string
cNonce?: string

/**
* The client id used for authorization. Only required if authorization_code flow was used.
*/
clientId?: string
}

/**
* Options that are used to accept a credential offer for both the pre-authorized code flow and authorization code flow.
* NOTE: Merge with @see OpenId4VciCredentialRequestOptions for 0.6
Expand Down

0 comments on commit 2110e4a

Please sign in to comment.