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
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

---
Expand Down
14 changes: 10 additions & 4 deletions src/config/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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
};
};
15 changes: 10 additions & 5 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
66 changes: 56 additions & 10 deletions src/services/apiService.js
Original file line number Diff line number Diff line change
@@ -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 };
4 changes: 2 additions & 2 deletions src/services/offerService.js
Original file line number Diff line number Diff line change
@@ -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');
Expand All @@ -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,
Expand Down