diff --git a/README.md b/README.md index 7e7cc81..9849132 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,16 @@ It guides the user through providing credential details, sending them to the API ## Basic Setup - `.env` file configured with API and credential settings. +``` +API_ENDPOINT= +TOKEN= //optional if API_KEY and TENANT_ID are provided +API_KEY= //optional if TOKEN is provided +TENANT_ID= //optional if TOKEN is provided +CREDENTIAL_DEFINITION= +ISSUER_DID= +SCHEMA_NAME= +SCHEMA_VERSION= +``` - Node.js installed on your system. --- diff --git a/src/config/env.js b/src/config/env.js index f00196a..8c32bb0 100644 --- a/src/config/env.js +++ b/src/config/env.js @@ -4,8 +4,11 @@ if (!process.env.API_ENDPOINT) { throw new Error("Missing API_ENDPOINT in .env file"); } +// Accept either TOKEN or API_KEY + TENANT_ID if (!process.env.TOKEN) { - throw new Error("Missing TOKEN in .env file"); + if (!process.env.API_KEY || !process.env.TENANT_ID) { + throw new Error("Missing authentication: provide either TOKEN or both API_KEY and TENANT_ID in .env file"); + } } if (!process.env.CREDENTIAL_DEFINITION) { @@ -20,11 +23,14 @@ if (!process.env.SCHEMA_NAME) { if (!process.env.SCHEMA_VERSION) { throw new Error("Missing SCHEMA_VERSION in .env file"); } + module.exports = { - token:process.env.TOKEN, + apiKey: process.env.API_KEY, + tenantId: process.env.TENANT_ID, + token: process.env.TOKEN, apiEndpoint: process.env.API_ENDPOINT, - credentialDefintion: process.env.CREDENTIAL_DEFINITION, + credentialDefinition: process.env.CREDENTIAL_DEFINITION, issuerDid: process.env.ISSUER_DID, schemaName: process.env.SCHEMA_NAME, schemaVersion: process.env.SCHEMA_VERSION -}; \ No newline at end of file +}; diff --git a/src/main.js b/src/main.js index 59225b2..a97561a 100644 --- a/src/main.js +++ b/src/main.js @@ -5,11 +5,16 @@ const {prepareOOBPayload} = require('./services/prepareOOBPayload'); const { prepareURLAPI } = require('./services/apiService'); async function main() { - const offer = await createOffer(); - const sendOfferRepsonse = await sendOfferToAPI(offer); - const oobPayload = await prepareOOBPayload(sendOfferRepsonse) - const oobInvite = await prepareURLAPI(oobPayload); - generateQR(oobInvite.invitation_url) + try { + const offer = await createOffer(); + const sendOfferRepsonse = await sendOfferToAPI(offer); + const oobPayload = await prepareOOBPayload(sendOfferRepsonse); + const oobInvite = await prepareURLAPI(oobPayload); + generateQR(oobInvite.invitation_url); + } catch (error) { + console.error('Error in main process:', error.message); + process.exit(1); + } } main(); \ No newline at end of file diff --git a/src/services/apiService.js b/src/services/apiService.js index 31381f6..8d12a3c 100644 --- a/src/services/apiService.js +++ b/src/services/apiService.js @@ -1,52 +1,98 @@ const axios = require('axios'); -const { apiEndpoint,token } = require('../config/env'); +const { apiEndpoint, apiKey, tenantId, token } = require('../config/env'); -axios.defaults.baseURL = apiEndpoint -axios.defaults.headers.common['Authorization'] = `Bearer ${token}`; +let authToken = null; + +const apiClient = axios.create({ + baseURL: apiEndpoint +}); + +async function getAuthToken() { + if (authToken) { + return authToken; + } + + // If TOKEN is provided in .env use it + if (token) { + authToken = token; + apiClient.defaults.headers.common['Authorization'] = `Bearer ${authToken}`; + return authToken; + } + + // otherwise obtain token using API_KEY + TENANT_ID + if (apiKey && tenantId) { + try { + const response = await apiClient.post(`/multitenancy/tenant/${tenantId}/token`, { + api_key: apiKey, + }); + authToken = response.data.token; + apiClient.defaults.headers.common['Authorization'] = `Bearer ${authToken}`; + return authToken; + } catch (err) { + console.error("Error obtaining auth token:", err.message); + if (err.response) { + console.error("Status:", err.response.status, "Data:", err.response.data); + } + throw new Error('Failed to obtain authentication token'); + } + } + + throw new Error('No valid authentication method available'); +} async function sendOfferToAPI(offer) { try { - const res = await axios.post(`/issue-credential-2.0/create-offer`, offer); + + await getAuthToken(); + const res = await apiClient.post(`/issue-credential-2.0/create-offer`, offer); return res.data; } catch (err) { console.error("Error sending to API:", err.message); if (err.response) { console.error("Status:", err.response.status, "Data:", err.response.data); } + throw err; } } async function prepareURLAPI(payload) { - try { - const res = await axios.post(`/out-of-band/create-invitation`, payload); + try { + await getAuthToken(); + const res = await apiClient.post(`/out-of-band/create-invitation`, payload); return res.data; } catch (err) { console.error("Error preparing OOB API:", err.message); if (err.response) { console.error("Status:", err.response.status, "Data:", err.response.data); } + throw err; } } async function getIssuanceStatus(cred_ex_id) { try { - const res = await axios.get(`/issue-credential-2.0/records/${cred_ex_id}`); + await getAuthToken(); + const res = await apiClient.get(`/issue-credential-2.0/records/${cred_ex_id}`); + return res.data; } catch (err) { if (err.response) { console.error('Status',err.response.status , 'Data', err.response.data ) } + throw err; } - } async function issueCredential(cred_ex_id) { try { - const res = await axios.get(`/issue-credential-2.0/records/${cred_ex_id}/issue`,cred_ex_id); + await getAuthToken(); + const res = await apiClient.post(`/issue-credential-2.0/records/${cred_ex_id}/issue`); + return res.data; } catch (err) { if (err.response) { console.error('Status',err.response.status , 'Data', err.response.data ) } + throw err; } } -module.exports = { sendOfferToAPI , prepareURLAPI ,getIssuanceStatus,issueCredential}; +module.exports = { sendOfferToAPI, prepareURLAPI, getIssuanceStatus, issueCredential, getAuthToken }; diff --git a/src/services/offerService.js b/src/services/offerService.js index b619c92..f7e38fe 100644 --- a/src/services/offerService.js +++ b/src/services/offerService.js @@ -1,5 +1,5 @@ const { askQuestion, closePrompt } = require('../cli/prompts'); -const { credentialDefintion, issuerDid, schemaName, schemaVersion } = require('../config/env'); +const { credentialDefinition, issuerDid, schemaName, schemaVersion } = require('../config/env'); async function createOffer() { console.log('Enter credential details to create an offer'); @@ -26,7 +26,7 @@ async function createOffer() { }, "filter": { "indy": { - "cred_def_id": credentialDefintion, + "cred_def_id": credentialDefinition, "issuer_did": issuerDid, "schema_issuer_did": issuerDid, "schema_name": schemaName,