From 11465d9e5ac2a95ea856db9bb74ab656509f31e3 Mon Sep 17 00:00:00 2001 From: traviskhl Date: Fri, 29 Aug 2025 08:18:56 -0700 Subject: [PATCH 1/4] feat: require tennant id and api key and get auth token in script Signed-off-by: traviskhl --- src/config/env.js | 12 ++++++--- src/main.js | 17 ++++++++---- src/services/apiService.js | 53 +++++++++++++++++++++++++++++++------- 3 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src/config/env.js b/src/config/env.js index f00196a..27aa2f0 100644 --- a/src/config/env.js +++ b/src/config/env.js @@ -4,8 +4,12 @@ if (!process.env.API_ENDPOINT) { throw new Error("Missing API_ENDPOINT in .env file"); } -if (!process.env.TOKEN) { - throw new Error("Missing TOKEN in .env file"); +if (!process.env.API_KEY) { + throw new Error("Missing API_KEY in .env file"); +} + +if (!process.env.TENANT_ID) { + throw new Error("Missing TENANT_ID in .env file"); } if (!process.env.CREDENTIAL_DEFINITION) { @@ -20,8 +24,10 @@ 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, apiEndpoint: process.env.API_ENDPOINT, credentialDefintion: process.env.CREDENTIAL_DEFINITION, issuerDid: process.env.ISSUER_DID, diff --git a/src/main.js b/src/main.js index 59225b2..1586f48 100644 --- a/src/main.js +++ b/src/main.js @@ -5,11 +5,18 @@ 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); + console.log('Process completed successfully!'); + + } 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..4c59778 100644 --- a/src/services/apiService.js +++ b/src/services/apiService.js @@ -1,51 +1,86 @@ const axios = require('axios'); -const { apiEndpoint,token } = require('../config/env'); +const { apiEndpoint, apiKey, tenantId } = 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; + } + + try { + console.log('Obtaining authentication token...'); + const response = await apiClient.post(`/multitenancy/tenant/${tenantId}/token`, { + api_key: apiKey, + }); + authToken = response.data.token; + console.log(`token ${authToken}`); + 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'); + } +} 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(); // Ensure we have a valid token + 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(); // Ensure we have a valid token + 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(); // Ensure we have a valid token + 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; } } From 99343e3b74f00ad64acbef9d3474c5dc543e9d6c Mon Sep 17 00:00:00 2001 From: traviskhl Date: Fri, 29 Aug 2025 08:24:39 -0700 Subject: [PATCH 2/4] refactor: remove debug console logs Signed-off-by: traviskhl --- src/services/apiService.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/services/apiService.js b/src/services/apiService.js index 4c59778..2e8fcca 100644 --- a/src/services/apiService.js +++ b/src/services/apiService.js @@ -13,12 +13,10 @@ async function getAuthToken() { } try { - console.log('Obtaining authentication token...'); const response = await apiClient.post(`/multitenancy/tenant/${tenantId}/token`, { api_key: apiKey, }); authToken = response.data.token; - console.log(`token ${authToken}`); apiClient.defaults.headers.common['Authorization'] = `Bearer ${authToken}`; return authToken; } catch (err) { From decfeae78cd37dc507274f92b493e4f17d77d328 Mon Sep 17 00:00:00 2001 From: traviskhl Date: Fri, 29 Aug 2025 10:56:23 -0700 Subject: [PATCH 3/4] feat: optionally take TOKEN or API_KEY + TENANT_ID in .env Signed-off-by: traviskhl --- src/config/env.js | 16 ++++++------- src/main.js | 4 +--- src/services/apiService.js | 45 +++++++++++++++++++++++------------- src/services/offerService.js | 4 ++-- 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/config/env.js b/src/config/env.js index 27aa2f0..8c32bb0 100644 --- a/src/config/env.js +++ b/src/config/env.js @@ -4,12 +4,11 @@ if (!process.env.API_ENDPOINT) { throw new Error("Missing API_ENDPOINT in .env file"); } -if (!process.env.API_KEY) { - throw new Error("Missing API_KEY in .env file"); -} - -if (!process.env.TENANT_ID) { - throw new Error("Missing TENANT_ID in .env file"); +// Accept either TOKEN or API_KEY + TENANT_ID +if (!process.env.TOKEN) { + 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) { @@ -28,9 +27,10 @@ if (!process.env.SCHEMA_VERSION) { module.exports = { 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 1586f48..a97561a 100644 --- a/src/main.js +++ b/src/main.js @@ -10,9 +10,7 @@ async function main() { const sendOfferRepsonse = await sendOfferToAPI(offer); const oobPayload = await prepareOOBPayload(sendOfferRepsonse); const oobInvite = await prepareURLAPI(oobPayload); - generateQR(oobInvite.invitation_url); - console.log('Process completed successfully!'); - + generateQR(oobInvite.invitation_url); } catch (error) { console.error('Error in main process:', error.message); process.exit(1); diff --git a/src/services/apiService.js b/src/services/apiService.js index 2e8fcca..8d12a3c 100644 --- a/src/services/apiService.js +++ b/src/services/apiService.js @@ -1,5 +1,5 @@ const axios = require('axios'); -const { apiEndpoint, apiKey, tenantId } = require('../config/env'); +const { apiEndpoint, apiKey, tenantId, token } = require('../config/env'); let authToken = null; @@ -12,24 +12,37 @@ async function getAuthToken() { return authToken; } - try { - const response = await apiClient.post(`/multitenancy/tenant/${tenantId}/token`, { - api_key: apiKey, - }); - authToken = response.data.token; + // If TOKEN is provided in .env use it + if (token) { + authToken = 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); + } + + // 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('Failed to obtain authentication token'); } + + throw new Error('No valid authentication method available'); } async function sendOfferToAPI(offer) { try { + await getAuthToken(); const res = await apiClient.post(`/issue-credential-2.0/create-offer`, offer); return res.data; @@ -38,13 +51,13 @@ async function sendOfferToAPI(offer) { if (err.response) { console.error("Status:", err.response.status, "Data:", err.response.data); } - throw err; + throw err; } } async function prepareURLAPI(payload) { try { - await getAuthToken(); // Ensure we have a valid token + await getAuthToken(); const res = await apiClient.post(`/out-of-band/create-invitation`, payload); return res.data; } catch (err) { @@ -58,7 +71,7 @@ async function prepareURLAPI(payload) { async function getIssuanceStatus(cred_ex_id) { try { - await getAuthToken(); // Ensure we have a valid token + await getAuthToken(); const res = await apiClient.get(`/issue-credential-2.0/records/${cred_ex_id}`); return res.data; } catch (err) { @@ -71,7 +84,7 @@ async function getIssuanceStatus(cred_ex_id) { async function issueCredential(cred_ex_id) { try { - await getAuthToken(); // Ensure we have a valid token + await getAuthToken(); const res = await apiClient.post(`/issue-credential-2.0/records/${cred_ex_id}/issue`); return res.data; } catch (err) { @@ -82,4 +95,4 @@ async function issueCredential(cred_ex_id) { } } -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, From 62112cd08a924e98f46fed7bacf2f6489fd2fefd Mon Sep 17 00:00:00 2001 From: traviskhl Date: Fri, 29 Aug 2025 11:09:23 -0700 Subject: [PATCH 4/4] docs: update readme Signed-off-by: traviskhl --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) 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. ---