Skip to content
Open
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
2 changes: 1 addition & 1 deletion .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ module.exports = {
'unicorn/prefer-node-protocol': 'error',
'vue/no-v-html': 'off'
}
};
};
56 changes: 50 additions & 6 deletions common/jwt.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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) {
Copy link
Collaborator

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

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;
Copy link
Collaborator

Choose a reason for hiding this comment

The 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,
Copy link
Author

Choose a reason for hiding this comment

The 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;
Expand All @@ -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 ?? []) {
Expand Down
62 changes: 58 additions & 4 deletions configs/combined.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

app:
# server:
# baseUri: https://evil-cows-return.loca.lt
# baseUri: https://evil-cows-return.loca.lt
opencred:
caStore:
- pem: |
Expand Down Expand Up @@ -149,6 +149,47 @@ app:
steps:
default:
acceptedCredentialType: "TODO" # required
- name: "DC API Test App"
clientId: "opencred"
clientSecret: "opencred"
description: "Relying Party DC API Test App"
icon: "https://placekitten.com/200/200"
backgroundImage: "https://placekitten.com/800/300"
idTokenExpirySeconds: 3600
brand:
cta: "#0B669D"
primary: "#045199"
header: "#0979c4"
redirectUri: "http://0.0.0.0:8080/realms/OpenCred/broker/oauth2/endpoint"
scopes:
- name: "openid"
description: "Open ID Connect"
claims:
- name: "email"
path: "email"
workflow:
id: 235bbcc4-f0b4-4eb3-8a3b-0006ae17462c
type: dc-api
submissionEndpoint: ""
referenceEndpoint: ""
baseUrl: https://cb1e46108f7d.ngrok-free.app/
clientSecret: "z1AanFEw6Dk5x2QGfz7B32X9xSDSatz6XEXCATtNvSxBAcP"
steps:
initiated:
callback:
complete:
callback:
dcApiRequest: >
{
"namespaces": {
"org.iso.18013.5.1": [
"family_name",
"given_name",
"document_number"
]
},
"origin": "https://cb1e46108f7d.ngrok-free.app"
}
- name: "load-test"
clientId: "load-test"
clientSecret: "DeepestAndDarkest"
Expand Down Expand Up @@ -282,20 +323,20 @@ app:
required: true
- type: number
id: height
name: Height (cm)
name: Height (cm)
path: "$.credentialSubject.height"
required: false
- type: dropdown
id: sex
name: Sex
name: Sex
path: "$.credentialSubject.sex"
required: false
options:
"Male": 1
"Female": 2
- type: dropdown
id: senior_citizen
name: Are you a senior citizen?
name: Are you a senior citizen?
path: "$.credentialSubject.senior_citizen"
required: true
options:
Expand Down Expand Up @@ -334,3 +375,16 @@ app:
exchangeErrorSubtitle: "Error details:"
exchangeResetTitle: Please try again.
exchangeReset: Retry exchange
# DC API specific translations
dcApiTitle: "Verify with Digital Credential"
dcApiLoading: "Requesting your digital credential..."
dcApiLoadingHelp: "Please follow the prompts in your browser to select and share your credential."
dcApiError: "Unable to verify credential"
dcApiReady: "Click To Verify with DC API"
dcApiRetry: "Try Again"
dcApiContinue: "Continue"
dcApiSwitchMethod: "Use a different verification method"
dcApiInitializing: "Initializing Digital Credential verification..."
dcApiHavingTrouble: "Having trouble?"
dcApiTryAnotherWay: "Try another way"
dcApiCancel: "Cancel DC API Verification Request"
Loading