-
Notifications
You must be signed in to change notification settings - Fork 27
Feat/dc api workflow #19
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
base: main
Are you sure you want to change the base?
Changes from all commits
80ed67b
2ac17e2
1292951
e2924ba
f451cb5
9acbbab
d606fe7
b903bf5
ff3cc39
31cd654
086ae02
e089c70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -28,4 +28,4 @@ module.exports = { | |
| 'unicorn/prefer-node-protocol': 'error', | ||
| 'vue/no-v-html': 'off' | ||
| } | ||
| }; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,8 +16,8 @@ import jp from 'jsonpath'; | |
| * @param {import("../configs/config.js").RelyingParty} rp | ||
| */ | ||
| export const jwtFromExchange = async (exchange, rp) => { | ||
| const signingKey = config.opencred.signingKeys?.find( | ||
| sk => sk.purpose.includes('id_token') | ||
| const signingKey = config.opencred.signingKeys?.find(sk => | ||
| sk.purpose.includes('id_token'), | ||
| ); | ||
| if(!signingKey) { | ||
| throw new Error('No signing key found in config with purpose id_token'); | ||
|
|
@@ -45,15 +45,59 @@ export const jwtFromExchange = async (exchange, rp) => { | |
| const header = { | ||
| alg: signingKey.type, | ||
| typ: 'JWT', | ||
| kid: signingKey.id | ||
| kid: signingKey.id, | ||
| }; | ||
|
|
||
| if(!exchange.variables?.results) { | ||
| return null; | ||
| } | ||
|
|
||
| const stepResultKey = Object.keys(exchange.variables.results).find( | ||
| v => v == exchange.step | ||
| v => v == exchange.step, | ||
| ); | ||
| const stepResults = exchange.variables.results[stepResultKey]; | ||
|
|
||
| // Handle DC API workflow differently | ||
| if(rp.workflow?.type === 'dc-api' && !!stepResults) { | ||
| try { | ||
| const now = Math.floor(Date.now() / 1000); | ||
| // Default to 1 hour | ||
| const expirySeconds = rp.idTokenExpirySeconds || 3600; | ||
|
|
||
| const subject = stepResults.response['org.iso.18013.5.1'].document_number; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Danger with non happy path payloads |
||
|
|
||
| const verified = | ||
| stepResults.response.issuer_authentication == 'Valid' && | ||
| stepResults.response.device_authentication == 'Valid'; | ||
|
|
||
| const errors = stepResults.response.errors; | ||
|
|
||
| const payload = { | ||
| iss: config.server.baseUri, | ||
| aud: rp.clientId, | ||
| sub: subject || exchange.id, | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to identify what the subject should be. It may not be guaranteed that the document number would be requested by a relying party. Need to identify if this JWT construction is correct. |
||
| iat: now, | ||
| exp: now + expirySeconds, | ||
| verified, | ||
| verification_method: 'dc-api', | ||
| verified_credentials: stepResults.response, | ||
| }; | ||
|
|
||
| if(errors !== null) { | ||
| payload.errors = errors; | ||
| } | ||
|
|
||
| const jwt = await JWT.sign({payload, header, signFn}); | ||
| return jwt.toString(); | ||
| } catch(error) { | ||
| console.error('Error in DC API JWT generation:', error); | ||
| throw error; | ||
| } | ||
| } | ||
|
|
||
| const c = jp.query( | ||
| stepResults, '$.verifiablePresentation.verifiableCredential[0]' | ||
| stepResults, | ||
| '$.verifiablePresentation.verifiableCredential[0]', | ||
| ); | ||
| if(!c.length) { | ||
| return null; | ||
|
|
@@ -65,7 +109,7 @@ export const jwtFromExchange = async (exchange, rp) => { | |
| aud: rp.clientId, | ||
| sub: c[0].credentialSubject.id, | ||
| iat: now, | ||
| exp: now + rp.idTokenExpirySeconds | ||
| exp: now + rp.idTokenExpirySeconds, | ||
| }; | ||
|
|
||
| for(const {name, path} of rp.claims ?? []) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Break out into testable function to generate the payload for dc API