Skip to content

Commit

Permalink
fix: feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
auer-martin committed Jul 29, 2024
1 parent cb3e749 commit c49466b
Show file tree
Hide file tree
Showing 15 changed files with 76 additions and 73 deletions.
3 changes: 2 additions & 1 deletion packages/openid4vc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
"dependencies": {
"@credo-ts/core": "workspace:*",
"@sphereon/did-auth-siop": "link:../../../../Documents/OID4VCI/packages/siop-oid4vp",
"@sphereon/common": "link:../../../../Documents/OID4VCI/packages/common",
"@sphereon/oid4vci-client": "link:../../../../Documents/OID4VCI/packages/client",
"@sphereon/oid4vci-common": "link:../../../../Documents/OID4VCI/packages/common",
"@sphereon/oid4vci-common": "link:../../../../Documents/OID4VCI/packages/oid4vci-common",
"@sphereon/oid4vci-issuer": "link:../../../../Documents/OID4VCI/packages/issuer",
"@sphereon/ssi-types": "0.26.1-next.132",
"class-transformer": "^0.5.1",
Expand Down
8 changes: 4 additions & 4 deletions packages/openid4vc/src/openid4vc-holder/OpenId4VcHolderApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,9 @@ export class OpenId4VcHolderApi {
const {
access_token: accessToken,
c_nonce: cNonce,
dPoPJwk,
dpop,
} = await this.openId4VciHolderService.requestAccessToken(this.agentContext, options)
return { accessToken, cNonce, dPoPJwk }
return { accessToken, cNonce, dpop }
}

/**
Expand All @@ -161,14 +161,14 @@ export class OpenId4VcHolderApi {
* @param options.tokenResponse Obtained through @see requestAccessToken
*/
public async requestCredentials(options: OpenId4VciRequestCredentialOptions) {
const { resolvedCredentialOffer, cNonce, accessToken, dPoPJwk, ...credentialRequestOptions } = options
const { resolvedCredentialOffer, cNonce, accessToken, dpop, ...credentialRequestOptions } = options

return this.openId4VciHolderService.acceptCredentialOffer(this.agentContext, {
resolvedCredentialOffer,
acceptCredentialOfferOptions: credentialRequestOptions,
accessToken,
cNonce,
dPoPJwk,
dpop,
})
}

Expand Down
47 changes: 26 additions & 21 deletions packages/openid4vc/src/openid4vc-holder/OpenId4VciHolderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
injectable,
parseDid,
} from '@credo-ts/core'
import { SigningAlgo, CreateDPoPClientOpts } from '@sphereon/common'

Check failure on line 49 in packages/openid4vc/src/openid4vc-holder/OpenId4VciHolderService.ts

View workflow job for this annotation

GitHub Actions / Validate

Unable to resolve path to module '@sphereon/common'
import {
AccessTokenClient,
CredentialRequestClientBuilder,
Expand All @@ -67,9 +68,7 @@ import {
OpenId4VCIVersion,
PARMode,
post,
SigningAlgo,
EndpointMetadataResult,
CreateDPoPClientOptions,
} from '@sphereon/oid4vci-common'

Check failure on line 72 in packages/openid4vc/src/openid4vc-holder/OpenId4VciHolderService.ts

View workflow job for this annotation

GitHub Actions / Validate

Unable to resolve path to module '@sphereon/oid4vci-common'

import { OpenId4VciCredentialFormatProfile } from '../shared'
Expand Down Expand Up @@ -279,19 +278,19 @@ export class OpenId4VciHolderService {
credentialIssuerMetadata: OpenId4VciIssuerMetadata
}
) {
const dPoPSigningAlgValuesSupported =
const dpopSigningAlgValuesSupported =
metadata.authorizationServerMetadata?.dpop_signing_alg_values_supported ??
metadata.credentialIssuerMetadata.dpop_signing_alg_values_supported

if (!dPoPSigningAlgValuesSupported) return undefined
if (!dpopSigningAlgValuesSupported) return undefined

const alg = dPoPSigningAlgValuesSupported.find((alg) => getJwkClassFromJwaSignatureAlgorithm(alg))
const alg = dpopSigningAlgValuesSupported.find((alg) => getJwkClassFromJwaSignatureAlgorithm(alg))

const JwkClass = alg ? getJwkClassFromJwaSignatureAlgorithm(alg) : undefined

if (!JwkClass) {
throw new CredoError(
`No supported dpop signature algorithms found in dpop_signing_alg_values_supported '${dPoPSigningAlgValuesSupported.join(
`No supported dpop signature algorithms found in dpop_signing_alg_values_supported '${dpopSigningAlgValuesSupported.join(
', '
)}'`
)
Expand All @@ -300,13 +299,13 @@ export class OpenId4VciHolderService {
const key = await agentContext.wallet.createKey({ keyType: JwkClass.keyType })
const jwk = getJwkFromKey(key)

const createDPoPOptions: CreateDPoPClientOptions = {
const createDPoPOpts: CreateDPoPClientOpts = {
jwtIssuer: { alg: alg as unknown as SigningAlgo, jwk: jwk.toJson() },
dPoPSigningAlgValuesSupported,
dpopSigningAlgValuesSupported,
jwtPayloadProps: {},
createJwtCallback: getCreateJwtCallback(agentContext),
}
return createDPoPOptions
return createDPoPOpts
}

public async requestAccessToken(agentContext: AgentContext, options: OpenId4VciTokenRequestOptions) {
Expand All @@ -318,8 +317,8 @@ export class OpenId4VciHolderService {

const accessTokenClient = new AccessTokenClient()

const createDPoPOptions = await this.getCreateDPoPOptions(agentContext, metadata)
const dPoPJwk = createDPoPOptions ? getJwkFromJson(createDPoPOptions.jwtIssuer.jwk) : undefined
const createDPoPOpts = await this.getCreateDPoPOptions(agentContext, metadata)
const dpopJwk = createDPoPOpts ? getJwkFromJson(createDPoPOpts.jwtIssuer.jwk) : undefined

if (resolvedAuthorizationRequest) {
const { codeVerifier, redirectUri } = resolvedAuthorizationRequest
Expand All @@ -330,14 +329,14 @@ export class OpenId4VciHolderService {
code,
codeVerifier,
redirectUri,
createDPoPOptions,
createDPoPOpts,
})
} else {
accessTokenResponse = await accessTokenClient.acquireAccessToken({
metadata: metadata,
credentialOffer: { credential_offer: credentialOfferRequestWithBaseUrl.credential_offer },
pin: txCode,
createDPoPOptions,
createDPoPOpts,
})
}

Expand All @@ -349,7 +348,7 @@ export class OpenId4VciHolderService {

this.logger.debug('Requested OpenId4VCI Access Token.')

return { ...accessTokenResponse.successBody, dPoPJwk }
return { ...accessTokenResponse.successBody, dpop: { dpopJwk: dpopJwk } }
}

public async acceptCredentialOffer(
Expand All @@ -360,7 +359,9 @@ export class OpenId4VciHolderService {
resolvedAuthorizationRequestWithCode?: OpenId4VciResolvedAuthorizationRequestWithCode
accessToken?: string
cNonce?: string
dPoPJwk?: Jwk
dpop?: {
dpopJwk: Jwk
}
}
) {
const { resolvedCredentialOffer, acceptCredentialOfferOptions } = options
Expand Down Expand Up @@ -402,7 +403,11 @@ export class OpenId4VciHolderService {
} as OpenId4VciTokenRequestOptions

const tokenResponse = options.accessToken
? { access_token: options.accessToken, c_nonce: options.cNonce, dPoPJwk: options.dPoPJwk }
? {
access_token: options.accessToken,
c_nonce: options.cNonce,
...(options.dpop && { dpop: { dpopJwk: options.dpop.dpopJwk } }),
}
: await this.requestAccessToken(agentContext, tokenRequestOptions)

const receivedCredentials: Array<OpenId4VciCredentialResponse> = []
Expand Down Expand Up @@ -468,12 +473,12 @@ export class OpenId4VciHolderService {

const credentialRequestClient = credentialRequestBuilder.build()

let createDPoPOptions: CreateDPoPClientOptions | undefined
if (options.dPoPJwk) {
const jwk = options.dPoPJwk
let createDPoPOpts: CreateDPoPClientOpts | undefined
if (options.dpop) {
const jwk = options.dpop.dpopJwk
const alg = jwk.supportedSignatureAlgorithms[0]

createDPoPOptions = {
createDPoPOpts = {
jwtIssuer: { alg: alg as unknown as SigningAlgo, jwk: jwk.toJson() },
jwtPayloadProps: { accessToken: options.accessToken },
createJwtCallback: getCreateJwtCallback(agentContext),
Expand All @@ -484,7 +489,7 @@ export class OpenId4VciHolderService {
proofInput: proofOfPossession,
credentialTypes: getTypesFromCredentialSupported(offeredCredentialConfiguration),
format: offeredCredentialConfiguration.format,
createDPoPOptions,
createDPoPOpts,
})

newCNonce = credentialResponse.successBody?.c_nonce
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export type OpenId4VciNotificationEvent = 'credential_accepted' | 'credential_fa

export type OpenId4VciTokenResponse = Pick<AccessTokenResponse, 'access_token' | 'c_nonce'>

export type OpenId4VciRequestTokenResponse = { accessToken: string; cNonce?: string; dPoPJwk?: Jwk }
export type OpenId4VciRequestTokenResponse = { accessToken: string; cNonce?: string; dpop: { dpopJwk?: Jwk } }

export interface OpenId4VciCredentialResponse {
credential: VerifiableCredential
Expand Down Expand Up @@ -112,7 +112,7 @@ export interface OpenId4VciCredentialRequestOptions extends Omit<OpenId4VciAccep
resolvedCredentialOffer: OpenId4VciResolvedCredentialOffer
accessToken: string
cNonce?: string
dPoPJwk?: Jwk
dpop?: { dpopJwk: Jwk }
}
/**
* Options that are used to accept a credential offer for both the pre-authorized code flow and authorization code flow.
Expand Down
18 changes: 9 additions & 9 deletions packages/openid4vc/src/openid4vc-issuer/OpenId4VcIssuerApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,22 +63,22 @@ export class OpenId4VcIssuerApi {
}

public async updateIssuerMetadata(
options: Pick<OpenId4VcIssuerRecordProps, 'issuerId' | 'display' | 'dPoPSigningAlgValuesSupported'> &
options: Pick<OpenId4VcIssuerRecordProps, 'issuerId' | 'display' | 'dpopSigningAlgValuesSupported'> &
(OpenId4VcIssuerRecordCredentialSupportedProps | OpenId4VcIssuerRecordCredentialConfigurationsSupportedProps)
) {
const issuer = await this.openId4VcIssuerService.getIssuerByIssuerId(this.agentContext, options.issuerId)
const { issuerId, credentialConfigurationsSupported, credentialsSupported, ...issuerOptions } = options

if (options.credentialConfigurationsSupported) {
issuer.credentialConfigurationsSupported = options.credentialConfigurationsSupported
issuer.credentialsSupported = credentialsSupportedV13ToV11(options.credentialConfigurationsSupported)
const issuer = await this.openId4VcIssuerService.getIssuerByIssuerId(this.agentContext, issuerId)

if (credentialConfigurationsSupported) {
issuer.credentialConfigurationsSupported = credentialConfigurationsSupported
issuer.credentialsSupported = credentialsSupportedV13ToV11(credentialConfigurationsSupported)
} else {
issuer.credentialsSupported = options.credentialsSupported
issuer.credentialsSupported = credentialsSupported
issuer.credentialConfigurationsSupported = undefined
}
issuer.display = options.display
issuer.dPoPSigningAlgValuesSupported = options.dPoPSigningAlgValuesSupported

return this.openId4VcIssuerService.updateIssuer(this.agentContext, issuer)
return this.openId4VcIssuerService.updateIssuer(this.agentContext, Object.assign(issuer, issuerOptions))
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ export class OpenId4VcIssuerService {
const openId4VcIssuerBase = {
issuerId: options.issuerId ?? utils.uuid(),
display: options.display,
dPoPSigningAlgValuesSupported: options.dPoPSigningAlgValuesSupported,
dpopSigningAlgValuesSupported: options.dpopSigningAlgValuesSupported,
accessTokenPublicKeyFingerprint: accessTokenSignerKey.fingerprint,
} as const

Expand Down Expand Up @@ -345,7 +345,7 @@ export class OpenId4VcIssuerService {
issuerRecord.credentialConfigurationsSupported ??
credentialsSupportedV11ToV13(agentContext, issuerRecord.credentialsSupported),
issuerDisplay: issuerRecord.display,
dPoPSigningAlgValuesSupported: issuerRecord.dPoPSigningAlgValuesSupported,
dpopSigningAlgValuesSupported: issuerRecord.dpopSigningAlgValuesSupported,
} satisfies OpenId4VcIssuerMetadata

return issuerMetadata
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export type OpenId4VcIssuerMetadata = {
issuerDisplay?: OpenId4VciIssuerMetadataDisplay[]
credentialsSupported: OpenId4VciCredentialSupportedWithId[]
credentialConfigurationsSupported: OpenId4VciCredentialConfigurationsSupported
dPoPSigningAlgValuesSupported?: [JwaSignatureAlgorithm, ...JwaSignatureAlgorithm[]]
dpopSigningAlgValuesSupported?: [JwaSignatureAlgorithm, ...JwaSignatureAlgorithm[]]
}

export interface OpenId4VciCreateCredentialOfferOptions {
Expand Down Expand Up @@ -159,5 +159,5 @@ export type OpenId4VciCreateIssuerOptions = {
issuerId?: string

display?: OpenId4VciIssuerMetadataDisplay[]
dPoPSigningAlgValuesSupported?: [JwaSignatureAlgorithm, ...JwaSignatureAlgorithm[]]
dpopSigningAlgValuesSupported?: [JwaSignatureAlgorithm, ...JwaSignatureAlgorithm[]]
} & (OpenId4VcIssuerRecordCredentialSupportedProps | OpenId4VcIssuerRecordCredentialConfigurationsSupportedProps)
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export type OpenId4VcIssuerRecordProps = {
* The DPoP signing algorithms supported by this issuer.
* If not provided, dPoP is considered unsupported.
*/
dPoPSigningAlgValuesSupported?: [JwaSignatureAlgorithm, ...JwaSignatureAlgorithm[]]
dpopSigningAlgValuesSupported?: [JwaSignatureAlgorithm, ...JwaSignatureAlgorithm[]]

display?: OpenId4VciIssuerMetadataDisplay[]
} & (OpenId4VcIssuerRecordCredentialSupportedProps | OpenId4VcIssuerRecordCredentialConfigurationsSupportedProps)
Expand All @@ -62,7 +62,7 @@ export class OpenId4VcIssuerRecord extends BaseRecord<DefaultOpenId4VcIssuerReco
public credentialsSupported!: OpenId4VciCredentialSupportedWithId[]
public credentialConfigurationsSupported?: OpenId4VciCredentialConfigurationsSupported
public display?: OpenId4VciIssuerMetadataDisplay[]
public dPoPSigningAlgValuesSupported?: [JwaSignatureAlgorithm, ...JwaSignatureAlgorithm[]]
public dpopSigningAlgValuesSupported?: [JwaSignatureAlgorithm, ...JwaSignatureAlgorithm[]]

public constructor(props: OpenId4VcIssuerRecordProps) {
super()
Expand All @@ -77,7 +77,7 @@ export class OpenId4VcIssuerRecord extends BaseRecord<DefaultOpenId4VcIssuerReco
this.credentialsSupported =
props.credentialsSupported ?? credentialsSupportedV13ToV11(props.credentialConfigurationsSupported)
this.credentialConfigurationsSupported = props.credentialConfigurationsSupported
this.dPoPSigningAlgValuesSupported = props.dPoPSigningAlgValuesSupported
this.dpopSigningAlgValuesSupported = props.dpopSigningAlgValuesSupported
this.display = props.display
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { OpenId4VcIssuanceRequest } from './requestContext'
import type { AgentContext } from '@credo-ts/core'
import type { AccessTokenRequest, JWK, JWTSignerCallback, SigningAlgo } from '@sphereon/oid4vci-common'
import type { JWK, SigningAlgo } from '@sphereon/common'
import type { AccessTokenRequest, JWTSignerCallback } from '@sphereon/oid4vci-common'
import type { NextFunction, Response, Router } from 'express'

import {
Expand All @@ -11,16 +12,15 @@ import {
getJwkClassFromKeyType,
Key,
joinUriParts,
Jwt,
} from '@credo-ts/core'
import { verifyDPoP } from '@sphereon/common'

Check failure on line 16 in packages/openid4vc/src/openid4vc-issuer/router/accessTokenEndpoint.ts

View workflow job for this annotation

GitHub Actions / Validate

Unable to resolve path to module '@sphereon/common'
import {
GrantTypes,
IssueStatus,
PRE_AUTHORIZED_CODE_REQUIRED_ERROR,
PRE_AUTH_CODE_LITERAL,
TokenError,
TokenErrorResponse,
verifyDPoP,
} from '@sphereon/oid4vci-common'

Check failure on line 24 in packages/openid4vc/src/openid4vc-issuer/router/accessTokenEndpoint.ts

View workflow job for this annotation

GitHub Actions / Validate

Unable to resolve path to module '@sphereon/oid4vci-common'
import { assertValidAccessTokenRequest, createAccessTokenResponse } from '@sphereon/oid4vci-issuer'

Check failure on line 25 in packages/openid4vc/src/openid4vc-issuer/router/accessTokenEndpoint.ts

View workflow job for this annotation

GitHub Actions / Validate

Unable to resolve path to module '@sphereon/oid4vci-issuer'

Expand Down Expand Up @@ -132,19 +132,19 @@ export function handleTokenRequest(config: OpenId4VciAccessTokenEndpointConfig)
const issuerMetadata = openId4VcIssuerService.getIssuerMetadata(agentContext, issuer)
const accessTokenSigningKey = Key.fromFingerprint(issuer.accessTokenPublicKeyFingerprint)

let dPoPJwk: JWK | undefined
let dpopJwk: JWK | undefined
if (request.headers.dpop) {
try {
const issuerConfig = agentContext.dependencyManager.resolve(OpenId4VcIssuerModuleConfig)
const fullUrl = joinUriParts(issuerConfig.baseUrl, [requestContext.issuer.issuerId, request.url])

dPoPJwk = await verifyDPoP(
const fullUrl = joinUriParts(issuerConfig.baseUrl, [requestContext.issuer.issuerId, request.url])
dpopJwk = await verifyDPoP(
{ method: request.method, headers: request.headers, fullUrl },
{
jwtVerifyCallback: getVerifyJwtCallback(agentContext),
expectAccessToken: false,
maxIatAgeInSeconds: undefined,
acceptedAlgorithms: issuerMetadata.dPoPSigningAlgValuesSupported as SigningAlgo[] | undefined,
acceptedAlgorithms: issuerMetadata.dpopSigningAlgValuesSupported as SigningAlgo[] | undefined,
}
)
} catch (error) {
Expand All @@ -167,7 +167,7 @@ export function handleTokenRequest(config: OpenId4VciAccessTokenEndpointConfig)
cNonceExpiresIn: cNonceExpiresInSeconds,
cNonces: new OpenId4VcCNonceStateManager(agentContext, issuer.issuerId),
accessTokenSignerCallback: getJwtSignerCallback(agentContext, accessTokenSigningKey, config),
dPoPJwk,
dPoPJwk: dpopJwk,
})
response.status(200).json(accessTokenResponse)
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function configureIssuerMetadataEndpoint(router: Router) {
credentials_supported: issuerMetadata.credentialsSupported,
credential_configurations_supported: issuerMetadata.credentialConfigurationsSupported,
display: issuerMetadata.issuerDisplay,
dpop_signing_alg_values_supported: issuerMetadata.dPoPSigningAlgValuesSupported,
dpop_signing_alg_values_supported: issuerMetadata.dpopSigningAlgValuesSupported,
} satisfies CredentialIssuerMetadata

response.status(200).json(transformedMetadata)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type { OpenId4VcIssuanceRequest } from './requestContext'
import type { OpenId4VcIssuerRecord } from '../repository'
import type { AgentContext } from '@credo-ts/core'
import type { SigningAlgo } from '@sphereon/oid4vci-common'
import type { SigningAlgo } from '@sphereon/common'

import { CredoError, joinUriParts, JwsService, Jwt } from '@credo-ts/core'
import { verifyResourceDPoP } from '@sphereon/oid4vci-common'
import { verifyResourceDPoP } from '@sphereon/common'

Check failure on line 7 in packages/openid4vc/src/openid4vc-issuer/router/verifyResourceRequest.ts

View workflow job for this annotation

GitHub Actions / Validate

Unable to resolve path to module '@sphereon/common'

import { getVerifyJwtCallback } from '../../shared/utils'
import { OpenId4VcIssuerModuleConfig } from '../OpenId4VcIssuerModuleConfig'
Expand Down Expand Up @@ -43,7 +43,7 @@ export async function verifyResourceRequest(
{ method: request.method, headers: request.headers, fullUrl },
{
jwtVerifyCallback: getVerifyJwtCallback(agentContext),
acceptedAlgorithms: issuerMetadata.dPoPSigningAlgValuesSupported as SigningAlgo[] | undefined,
acceptedAlgorithms: issuerMetadata.dpopSigningAlgValuesSupported as SigningAlgo[] | undefined,
}
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Jwt } from '@credo-ts/core'
import { SigningAlgo } from '@sphereon/oid4vci-common'
import { SigningAlgo } from '@sphereon/common'
import { cleanAll, enableNetConnect } from 'nock'

import { AskarModule } from '../../../../askar/src'
Expand Down
Loading

0 comments on commit c49466b

Please sign in to comment.