Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: access token can only be used for offer #1828

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { OpenId4VcIssuanceRequest } from './requestContext'
import type { AgentContext } from '@credo-ts/core'
import type { JWTSignerCallback } from '@sphereon/oid4vci-common'
import type { AccessTokenRequest, JWTSignerCallback } from '@sphereon/oid4vci-common'
import type { NextFunction, Response, Router } from 'express'

import { getJwkFromKey, CredoError, JwsService, JwtPayload, getJwkClassFromKeyType, Key } from '@credo-ts/core'
Expand Down Expand Up @@ -86,7 +86,7 @@ function getJwtSignerCallback(
const jwk = getJwkFromKey(signerPublicKey)
const signedJwt = await jwsService.createJwsCompact(agentContext, {
protectedHeaderOptions: { ...jwt.header, jwk, alg },
payload: new JwtPayload(jwt.payload),
payload: JwtPayload.fromJson(jwt.payload),
key: signerPublicKey,
})

Expand All @@ -103,11 +103,15 @@ export function handleTokenRequest(config: OpenId4VciAccessTokenEndpointConfig)
const requestContext = getRequestContext(request)
const { agentContext, issuer } = requestContext

if (request.body.grant_type !== GrantTypes.PRE_AUTHORIZED_CODE) {
return response.status(400).json({
error: TokenErrorResponse.invalid_request,
error_description: PRE_AUTHORIZED_CODE_REQUIRED_ERROR,
})
const body = request.body as AccessTokenRequest
if (body.grant_type !== GrantTypes.PRE_AUTHORIZED_CODE) {
return sendErrorResponse(
response,
agentContext.config.logger,
400,
TokenErrorResponse.invalid_request,
PRE_AUTHORIZED_CODE_REQUIRED_ERROR
)
}

const openId4VcIssuerService = agentContext.dependencyManager.resolve(OpenId4VcIssuerService)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import type { OpenId4VciCredentialRequest } from '../../shared'
import type { OpenId4VciCredentialRequestToCredentialMapper } from '../OpenId4VcIssuerServiceOptions'
import type { Router, Response } from 'express'

import { CredoError, JwsService, Jwt } from '@credo-ts/core'

import { getRequestContext, sendErrorResponse } from '../../shared/router'
import { OpenId4VcIssuerService } from '../OpenId4VcIssuerService'
import { getCNonceFromCredentialRequest } from '../util/credentialRequest'
Expand All @@ -31,9 +29,12 @@ export function configureCredentialEndpoint(router: Router, config: OpenId4VciCr
const { agentContext, issuer } = getRequestContext(request)
const openId4VcIssuerService = agentContext.dependencyManager.resolve(OpenId4VcIssuerService)

let preAuthorizedCode: string

// Verify the access token (should at some point be moved to a middleware function or something)
try {
await verifyAccessToken(agentContext, issuer, request.headers.authorization)
preAuthorizedCode = (await verifyAccessToken(agentContext, issuer, request.headers.authorization))
.preAuthorizedCode
} catch (error) {
return sendErrorResponse(response, agentContext.config.logger, 401, 'unauthorized', error)
}
Expand All @@ -46,6 +47,19 @@ export function configureCredentialEndpoint(router: Router, config: OpenId4VciCr
credentialRequest,
})

if (issuanceSession?.preAuthorizedCode !== preAuthorizedCode) {
agentContext.config.logger.warn(
`Credential request used access token with for credential offer with different pre-authorized code than was used for the issuance session ${issuanceSession?.id}`
)
return sendErrorResponse(
response,
agentContext.config.logger,
401,
'unauthorized',
'Access token is not valid for this credential request'
)
}

if (!issuanceSession) {
const cNonce = getCNonceFromCredentialRequest(credentialRequest)
agentContext.config.logger.warn(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,12 @@ export async function verifyAccessToken(
if (accessToken.payload.iss !== issuerMetadata.issuerUrl) {
throw new CredoError('Access token was not issued by the expected issuer')
}

if (typeof accessToken.payload.additionalClaims.preAuthorizedCode !== 'string') {
throw new CredoError('No preAuthorizedCode present in access token')
}

return {
preAuthorizedCode: accessToken.payload.additionalClaims.preAuthorizedCode,
}
}
Loading