Skip to content

Commit

Permalink
auth flow
Browse files Browse the repository at this point in the history
Signed-off-by: Timo Glastra <[email protected]>
  • Loading branch information
TimoGlastra committed Nov 19, 2024
1 parent 2a8607f commit 21dd4bc
Show file tree
Hide file tree
Showing 19 changed files with 1,063 additions and 436 deletions.
20 changes: 7 additions & 13 deletions agent/package.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,29 @@
{
"name": "agent",
"dependencies": {
"@credo-ts/askar": "0.5.13-alpha-20241107100446",
"@credo-ts/core": "0.5.13-alpha-20241107100446",
"@credo-ts/node": "0.5.13-alpha-20241107100446",
"@credo-ts/openid4vc": "0.5.13-alpha-20241107100446",
"@credo-ts/askar": "0.6.0-alpha-20241119125554",
"@credo-ts/core": "0.6.0-alpha-20241119125554",
"@credo-ts/node": "0.6.0-alpha-20241119125554",
"@credo-ts/openid4vc": "0.6.0-alpha-20241119125554",
"@hyperledger/aries-askar-nodejs": "^0.2.3",
"@protokoll/mdoc-client": "^0.2.36",
"@animo-id/mdoc": "^0.2.38",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
"express": "^4.18.2",
"oidc-provider": "^8.5.3",
"zod": "^3.22.4"
},
"devDependencies": {
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/node": "^20.11.7",
"@types/oidc-provider": "^8.5.2",
"tsx": "^4.7.0",
"typescript": "~5.3.3"
},
"scripts": {
"build": "tsc -p tsconfig.json",
"start": "node dist/server.js",
"dev": "tsx watch -r dotenv/config src/server.ts dotenv_config_path=.env.development"
},
"pnpm": {
"overrides": {
"@credo-ts/askar": "0.5.13-alpha-20241107100446",
"@credo-ts/core": "0.5.13-alpha-20241107100446",
"@credo-ts/openid4vc": "0.5.13-alpha-20241107100446",
"@credo-ts/node": "0.5.13-alpha-20241107100446"
}
}
}
9 changes: 3 additions & 6 deletions agent/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { OpenId4VcHolderModule, OpenId4VcIssuerModule, OpenId4VcVerifierModule }
import { ariesAskar } from '@hyperledger/aries-askar-nodejs'
import { Router } from 'express'
import { AGENT_HOST, AGENT_WALLET_KEY } from './constants'
import { credentialRequestToCredentialMapper } from './issuer'
import { credentialRequestToCredentialMapper, getVerificationSessionForIssuanceSession } from './issuer'

process.on('unhandledRejection', (reason) => {
console.error('Unhandled rejection', reason)
Expand Down Expand Up @@ -37,11 +37,8 @@ export const agent = new Agent({
openId4VcIssuer: new OpenId4VcIssuerModule({
baseUrl: joinUriParts(AGENT_HOST, ['oid4vci']),
router: openId4VciRouter,
endpoints: {
credential: {
credentialRequestToCredentialMapper,
},
},
credentialRequestToCredentialMapper,
getVerificationSessionForIssuanceSessionAuthorization: getVerificationSessionForIssuanceSession,
}),
openId4VcHolder: new OpenId4VcHolderModule(),
openId4VcVerifier: new OpenId4VcVerifierModule({
Expand Down
92 changes: 61 additions & 31 deletions agent/src/endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@ import z from 'zod'
import { agent } from './agent'
import { AGENT_HOST } from './constants'
import { getIssuerIdForCredentialConfigurationId } from './issuer'
import { issuers } from './issuers'
import { issuers, issuersCredentialsData } from './issuers'
import { getX509Certificate } from './keyMethods'
import { oidcUrl } from './oidcProvider/provider'
import { getVerifier } from './verifier'
import { allDefinitions, verifiers } from './verifiers'

type CredentialConfigurationId = keyof typeof issuersCredentialsData

const zCreateOfferRequest = z.object({
// FIXME: rename offeredCredentials to credentialSupportedIds in AFJ
credentialSupportedIds: z.array(z.string()),
credentialSupportedIds: z.array(
z.enum(Object.keys(issuersCredentialsData) as [CredentialConfigurationId, ...CredentialConfigurationId[]])
),
issuerId: z.string(),
})

Expand All @@ -30,18 +35,38 @@ export const apiRouter = express.Router()
apiRouter.use(express.json())
apiRouter.use(express.text())
apiRouter.post('/offers/create', async (request: Request, response: Response) => {
// FIXME: somehow JSON doesn't work
const createOfferRequest = zCreateOfferRequest.parse(
typeof request.body === 'string' ? JSON.parse(request.body) : request.body
)
const issuerId = getIssuerIdForCredentialConfigurationId(createOfferRequest.credentialSupportedIds[0])
const createOfferRequest = zCreateOfferRequest.parse(request.body)

// TODO: support multiple credential isuance
const configurationId = createOfferRequest.credentialSupportedIds[0]
const issuerId = getIssuerIdForCredentialConfigurationId(configurationId)
const authorization = issuersCredentialsData[configurationId].authorization
const issuerMetadata = await agent.modules.openId4VcIssuer.getIssuerMetadata(issuerId)

const offer = await agent.modules.openId4VcIssuer.createCredentialOffer({
issuerId,
offeredCredentials: createOfferRequest.credentialSupportedIds,
preAuthorizedCodeFlowConfig: {
userPinRequired: false,
},
preAuthorizedCodeFlowConfig:
authorization.type === 'pin' || authorization.type === 'none'
? {
authorizationServerUrl: issuerMetadata.credentialIssuer.credential_issuer,
txCode:
authorization.type === 'pin'
? {
input_mode: 'numeric',
length: 4,
}
: undefined,
}
: undefined,
authorizationCodeFlowConfig:
authorization.type === 'browser' || authorization.type === 'presentation'
? {
requirePresentationDuringIssuance: authorization.type === 'presentation',
authorizationServerUrl:
authorization.type === 'browser' ? oidcUrl : issuerMetadata.credentialIssuer.credential_issuer,
}
: undefined,
})

return response.json(offer)
Expand All @@ -58,13 +83,25 @@ apiRouter.get('/x509', async (_, response: Response) => {
apiRouter.get('/issuer', async (_, response: Response) => {
return response.json({
credentialsSupported: issuers.flatMap((i) =>
i.credentialsSupported.map((c) => {
Object.entries(i.credentialConfigurationsSupported).map(([id, c]) => {
const displayName =
c.display?.[0]?.name ??
(c.format === 'vc+sd-jwt' ? c.vct : c.format === 'mso_mdoc' ? c.doctype : 'Unregistered format')

const data = issuersCredentialsData[id as keyof typeof issuersCredentialsData]
const authorizationLabel =
data.authorization.type === 'pin'
? 'Requires PIN'
: data.authorization.type === 'browser'
? 'Requires Sign In'
: data.authorization.type === 'presentation'
? 'Requires Presentation'
: data.authorization.type === 'none'
? 'No authorization'
: ''

return {
display: `${i.display[0].name} - ${displayName} (${c.format})`,
display: `${i.display[0].name} - ${displayName} (${c.format}) - ${authorizationLabel}`,
id: c.id,
}
})
Expand All @@ -78,9 +115,7 @@ const zReceiveOfferRequest = z.object({
})

apiRouter.post('/offers/receive', async (request: Request, response: Response) => {
const receiveOfferRequest = zReceiveOfferRequest.parse(
typeof request.body === 'string' ? JSON.parse(request.body) : request.body
)
const receiveOfferRequest = zReceiveOfferRequest.parse(request.body)

const resolvedOffer = await agent.modules.openId4VcHolder.resolveCredentialOffer(
receiveOfferRequest.credentialOfferUri
Expand All @@ -92,10 +127,10 @@ apiRouter.post('/offers/receive', async (request: Request, response: Response) =
resolvedCredentialOffer: resolvedOffer,
accessToken: token.accessToken,
cNonce: token.cNonce,
credentialBindingResolver: async ({ keyType, supportsJwk }) => {
credentialBindingResolver: async ({ keyTypes, supportsJwk }) => {
if (supportsJwk) {
const key = await agent.wallet.createKey({
keyType,
keyType: keyTypes[0],
})

return {
Expand All @@ -108,23 +143,23 @@ apiRouter.post('/offers/receive', async (request: Request, response: Response) =
},
})

for (const credential of credentials) {
for (const credential of credentials.credentials) {
// authenticated channel issuance, not relevant here
if (typeof credential === 'string') continue

if ('compact' in credential.credential) {
await agent.sdJwtVc.store(credential.credential.compact as string)
if ('compact' in credential.credentials[0]) {
await agent.sdJwtVc.store(credential.credentials[0].compact as string)
}
}

return response.json({
credentials: credentials.map((credential) => {
credentials: credentials.credentials.map((credential) => {
// if (credential instanceof Mdoc) {
// return credential.credential
// }
if (typeof credential === 'string') return credential
if ('payload' in credential.credential) {
return credential.credential.payload
if (typeof credential.credentials[0] === 'string') return credential
if ('payload' in credential.credentials[0]) {
return credential.credentials[0].payload
}
throw new Error('Unsupported credential type')
}),
Expand Down Expand Up @@ -153,10 +188,7 @@ const zCreatePresentationRequestBody = z.object({
apiRouter.post('/requests/create', async (request: Request, response: Response) => {
const verifier = await getVerifier()

// FIXME: somehow JSON doesn't work
const createPresentationRequestBody = zCreatePresentationRequestBody.parse(
typeof request.body === 'string' ? JSON.parse(request.body) : request.body
)
const createPresentationRequestBody = zCreatePresentationRequestBody.parse(request.body)

const x509Certificate = getX509Certificate()

Expand Down Expand Up @@ -274,9 +306,7 @@ apiRouter.get('/requests/:verificationSessionId', async (request, response) => {
})

apiRouter.post('/requests/receive', async (request: Request, response: Response) => {
const receivePresentationRequestBody = zReceivePresentationRequestBody.parse(
typeof request.body === 'string' ? JSON.parse(request.body) : request.body
)
const receivePresentationRequestBody = zReceivePresentationRequestBody.parse(request.body)

const resolved = await agent.modules.openId4VcHolder.resolveSiopAuthorizationRequest(
receivePresentationRequestBody.authorizationRequestUri
Expand Down
Loading

0 comments on commit 21dd4bc

Please sign in to comment.