Finished refresh/user token auth flow
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
import fetch from "node-fetch";
|
||||
import fetchEbayReadToken from "../utils/fetchEbayReadToken.js"; // Adjust the import path according to your project structure
|
||||
import fetchEbayToken from "../utils/fetchEbayReadToken.js";
|
||||
|
||||
export const itemLookup = async (req, res) => {
|
||||
const productCode = req.query.productCode;
|
||||
const oauthToken = await fetchEbayReadToken();
|
||||
const token = await fetchEbayToken();
|
||||
console.log(productCode);
|
||||
try {
|
||||
const response = await fetch(
|
||||
@@ -11,7 +11,7 @@ export const itemLookup = async (req, res) => {
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${oauthToken}`,
|
||||
Authorization: `Bearer ${token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,44 +1,63 @@
|
||||
// inventoryController.js
|
||||
import buildAddFixedPriceItemRequestXML from "../utils/buildAddFixedPriceItemRequestXML.js";
|
||||
import fetch from "node-fetch";
|
||||
import fetchEbayUserToken from "../utils/fetchEbayUserToken.js"; // Adjust the import path according to your project structure
|
||||
|
||||
export const addItem = async (req, res) => {
|
||||
const itemDetails = req.body; // Assuming item details are sent in the request body
|
||||
itemDetails.userToken =
|
||||
"v^1.1#i^1#r^0#I^3#f^0#p^3#t^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";
|
||||
console.log(itemDetails);
|
||||
const xmlRequest = buildAddFixedPriceItemRequestXML(itemDetails);
|
||||
const itemDetails = req.body;
|
||||
// hardcoded user token - will be expired when we come back and we need to figure out to cache these while we make calls
|
||||
const token = "v^1.1#i^1#r^0#I^3#f^0#p^3#t^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"
|
||||
|
||||
// Constructing the payload for the Inventory API
|
||||
const offerPayload = {
|
||||
sku: itemDetails.sku,
|
||||
marketplaceId: itemDetails.marketplaceId,
|
||||
format: itemDetails.format,
|
||||
listingDescription: itemDetails.listingDescription,
|
||||
availableQuantity: itemDetails.availableQuantity,
|
||||
categoryId: itemDetails.categoryId,
|
||||
listingPolicies: {
|
||||
paymentPolicyId: itemDetails.listingPolicies.paymentPolicyId,
|
||||
fulfillmentPolicyId: itemDetails.listingPolicies.fulfillmentPolicyId,
|
||||
returnPolicyId: itemDetails.listingPolicies.returnPolicyId,
|
||||
},
|
||||
pricingSummary: {
|
||||
price: {
|
||||
currency: itemDetails.pricingSummary.price.currency,
|
||||
value: itemDetails.pricingSummary.price.value,
|
||||
},
|
||||
},
|
||||
merchantLocationKey: itemDetails.merchantLocationKey,
|
||||
quantityLimitPerBuyer: itemDetails.quantityLimitPerBuyer,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch("https://api.ebay.com/ws/api.dll", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "text/xml",
|
||||
"X-EBAY-API-SITEID": "0",
|
||||
"X-EBAY-API-CALL-NAME": "AddFixedPriceItem",
|
||||
"X-EBAY-API-COMPATIBILITY-LEVEL": "967", // Ensure this is the current compatibility level
|
||||
"X-EBAY-API-APP-NAME": process.env.EBAY_CLIENT_ID,
|
||||
"X-EBAY-API-DEV-NAME": process.env.EBAY_DEV_ID,
|
||||
"X-EBAY-API-CERT-NAME": process.env.EBAY_CLIENT_SECRET,
|
||||
},
|
||||
body: xmlRequest,
|
||||
});
|
||||
const response = await fetch(
|
||||
"https://api.ebay.com/sell/inventory/v1/offer",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Content-Language": "en-US",
|
||||
"Authorization": `Bearer ${token}`,
|
||||
},
|
||||
body: JSON.stringify(offerPayload),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`eBay API responded with status ${response.status}`);
|
||||
}
|
||||
console.log(response)
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text(); // Get the response body as text
|
||||
console.error(`eBay API responded with status ${response.status}: ${errorBody}`);
|
||||
throw new Error(`eBay API responded with status ${response.status}: ${errorBody}`);
|
||||
}
|
||||
|
||||
const responseData = await response.text();
|
||||
// Parse the XML response and handle it appropriately
|
||||
// You might need an XML parser here to handle the response
|
||||
|
||||
res.json({ success: true, data: responseData }); // Send back a success response
|
||||
const responseData = await response.json();
|
||||
res.json({ success: true, data: responseData });
|
||||
} catch (error) {
|
||||
console.error("Error adding item to eBay:", error);
|
||||
console.error("Error adding item to eBay via Inventory API:", error);
|
||||
console.log(error.message);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: "Failed to add item to eBay",
|
||||
message: "Failed to add item to eBay via Inventory API",
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
// routes/itemLookup.js
|
||||
import express from "express";
|
||||
import itemLookup from "../controllers/itemLookup.js";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// Use the itemLookup controller for the POST request to '/item-lookup'
|
||||
router.get("/item-lookup", itemLookup);
|
||||
|
||||
export default router;
|
||||
@@ -12,9 +12,60 @@ const app = express();
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
|
||||
// Use the itemLookupRoute with a base path, e.g., '/api'
|
||||
app.use("/api/data", dataRoutes);
|
||||
app.use("/api/inventory", inventoryRoutes);
|
||||
|
||||
/*
|
||||
the below code needs to be encapsulated somehow. It requires a manual flow, including QUICKLY copy/pasting the code query string from the result of localhost:300/auth/ebay (below)
|
||||
|
||||
Here are the steps:
|
||||
1. Go to localhost:3000/auth/ebay and copy/paste query string from code
|
||||
2. Quickly go to the editor and paste that code into the const code= at /auth/ebay/callback
|
||||
3. Go to localhost:3000/auth/ebay/callback and tokens will be in console - this is an 18 month deal, so we should tuck this code away
|
||||
|
||||
That is not really a callback... that was my intention, but it did not work out that way. That is simply an explicit API call to grab a user/refresh token from the manual process above
|
||||
|
||||
Next ToDos:
|
||||
1. change the name of fetchEbayToken to fetchEbayReadToken
|
||||
2. Add a fetchEbayUserToken endpoint and figure how to cycle user tokens every 2 hours with refresh token
|
||||
3. Add refresh token to .env and figure out how to safely store user tokens serverside (cookie? knowledge gap here)
|
||||
*/
|
||||
app.get('/auth/ebay', async (req, res) => {
|
||||
// the below URL is hardcoded because it's static in the eBay dev dashboard
|
||||
const authUrl = `https://auth.ebay.com/oauth2/authorize?client_id=TylerPul-ebayimpo-PRD-a983027cf-9b6b8bba&response_type=code&redirect_uri=Tyler_Pulse-TylerPul-ebayim-ledkmyo&scope=https://api.ebay.com/oauth/api_scope https://api.ebay.com/oauth/api_scope/sell.marketing.readonly https://api.ebay.com/oauth/api_scope/sell.marketing https://api.ebay.com/oauth/api_scope/sell.inventory.readonly https://api.ebay.com/oauth/api_scope/sell.inventory https://api.ebay.com/oauth/api_scope/sell.account.readonly https://api.ebay.com/oauth/api_scope/sell.account https://api.ebay.com/oauth/api_scope/sell.fulfillment.readonly https://api.ebay.com/oauth/api_scope/sell.fulfillment https://api.ebay.com/oauth/api_scope/sell.analytics.readonly https://api.ebay.com/oauth/api_scope/sell.finances https://api.ebay.com/oauth/api_scope/sell.payment.dispute https://api.ebay.com/oauth/api_scope/commerce.identity.readonly https://api.ebay.com/oauth/api_scope/sell.reputation https://api.ebay.com/oauth/api_scope/sell.reputation.readonly https://api.ebay.com/oauth/api_scope/commerce.notification.subscription https://api.ebay.com/oauth/api_scope/commerce.notification.subscription.readonly https://api.ebay.com/oauth/api_scope/sell.stores https://api.ebay.com/oauth/api_scope/sell.stores.readonly`;
|
||||
res.redirect(authUrl); // Redirect the user to eBay's sign-in page
|
||||
});
|
||||
|
||||
// Step 2: Handle the redirect from eBay
|
||||
app.get('/auth/ebay/callback', async (req, res) => {
|
||||
// this code comes from a query string at localhost:3000/auth/ebay when we redirect
|
||||
const code = 'v%5E1.1%23i%5E1%23p%5E3%23f%5E0%23r%5E1%23I%5E3%23t%5EUl41Xzc6NUE2ODc0NkU5Q0Q4N0QxQjhENTVCNzAxQTAwMEM2MzlfMF8xI0VeMjYw'
|
||||
try {
|
||||
// Step 3: Exchange the authorization code for access and refresh tokens
|
||||
const tokenResponse = await fetch('https://api.ebay.com/identity/v1/oauth2/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Authorization': `Basic ${Buffer.from(`${process.env.EBAY_CLIENT_ID}:${process.env.EBAY_CLIENT_SECRET}`).toString('base64')}`
|
||||
},
|
||||
// we use Tyler_Pulse-TylerPul-ebayim-ledkmyo and not the initial redirect URL
|
||||
body: `grant_type=authorization_code&code=${code}&redirect_uri=Tyler_Pulse-TylerPul-ebayim-ledkmyo`
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
throw new Error('Failed to exchange authorization code for tokens');
|
||||
}
|
||||
|
||||
const tokenData = await tokenResponse.json();
|
||||
console.log('Access Token:', tokenData.access_token);
|
||||
console.log('Refresh Token:', tokenData.refresh_token);
|
||||
|
||||
res.send('Authentication successful! Tokens acquired.'); // For demonstration purposes; you might want to redirect the user or show a different message
|
||||
} catch (error) {
|
||||
console.error('Error during token exchange:', error);
|
||||
res.status(500).send('Internal Server Error');
|
||||
}
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
const buildAddFixedPriceItemRequestXML = (itemDetails) => {
|
||||
// Constructing the XML payload using template literals
|
||||
return `<?xml version="1.0" encoding="utf-8"?>
|
||||
<AddFixedPriceItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">
|
||||
<RequesterCredentials>
|
||||
<eBayAuthToken>${itemDetails.userToken}</eBayAuthToken>
|
||||
</RequesterCredentials>
|
||||
<Item>
|
||||
<Title>${itemDetails.title}</Title>
|
||||
<Description><${itemDetails.description}></Description>
|
||||
<PrimaryCategory>
|
||||
<CategoryID>${itemDetails.categoryID}</CategoryID>
|
||||
</PrimaryCategory>
|
||||
<StartPrice>${itemDetails.startPrice}</StartPrice>
|
||||
<ConditionID>${itemDetails.conditionID}</ConditionID>
|
||||
<Country>${itemDetails.country}</Country>
|
||||
<Currency>${itemDetails.currency}</Currency>
|
||||
<DispatchTimeMax>${itemDetails.dispatchTimeMax}</DispatchTimeMax>
|
||||
<ListingDuration>${itemDetails.listingDuration}</ListingDuration>
|
||||
<ListingType>${itemDetails.listingType}</ListingType>
|
||||
<PaymentMethods>
|
||||
<PaymentMethod>${
|
||||
itemDetails.paymentMethods
|
||||
? itemDetails.paymentMethods[0]
|
||||
: "DefaultPaymentMethod"
|
||||
}</PaymentMethod>
|
||||
</PaymentMethods>
|
||||
|
||||
<PayPalEmailAddress>${itemDetails.payPalEmailAddress}</PayPalEmailAddress>
|
||||
<PictureDetails>
|
||||
<PictureURL>${itemDetails.imageURLs}</PictureURL>
|
||||
</PictureDetails>
|
||||
<PostalCode>${itemDetails.postalCode}</PostalCode>
|
||||
<Quantity>${itemDetails.quantity}</Quantity>
|
||||
<ReturnPolicy>
|
||||
<ReturnsAcceptedOption>${
|
||||
itemDetails.returnsAcceptedOption
|
||||
}</ReturnsAcceptedOption>
|
||||
<RefundOption>${itemDetails.refundOption}</RefundOption>
|
||||
<ReturnsWithinOption>${
|
||||
itemDetails.returnsWithinOption
|
||||
}</ReturnsWithinOption>
|
||||
<Description>${itemDetails.returnPolicyDescription}</Description>
|
||||
<ShippingCostPaidByOption>${
|
||||
itemDetails.shippingCostPaidByOption
|
||||
}</ShippingCostPaidByOption>
|
||||
</ReturnPolicy>
|
||||
<ShippingDetails>
|
||||
<ShippingType>${itemDetails.shippingType}</ShippingType>
|
||||
<ShippingServiceOptions>
|
||||
<ShippingServicePriority>1</ShippingServicePriority>
|
||||
<ShippingService>${itemDetails.shippingService}</ShippingService>
|
||||
<ShippingServiceCost>${
|
||||
itemDetails.shippingServiceCost
|
||||
}</ShippingServiceCost>
|
||||
</ShippingServiceOptions>
|
||||
</ShippingDetails>
|
||||
<Site>${itemDetails.site}</Site>
|
||||
</Item>
|
||||
</AddFixedPriceItemRequest>`;
|
||||
};
|
||||
|
||||
export default buildAddFixedPriceItemRequestXML;
|
||||
@@ -1,7 +1,7 @@
|
||||
// Need to figoure out expiration and make sure to cycle this appropriately to avoid unnecessary calls
|
||||
import fetch from "node-fetch";
|
||||
|
||||
const fetchEbayReadToken = async () => {
|
||||
const fetchEbayToken = async () => {
|
||||
const ebayClientId = process.env.EBAY_CLIENT_ID;
|
||||
const ebayClientSecret = process.env.EBAY_CLIENT_SECRET;
|
||||
const credentials = Buffer.from(
|
||||
@@ -15,7 +15,7 @@ const fetchEbayReadToken = async () => {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
Authorization: `Basic ${credentials}`,
|
||||
"authorization": `Basic ${credentials}`,
|
||||
},
|
||||
body: "grant_type=client_credentials&scope=https%3A%2F%2Fapi.ebay.com%2Foauth%2Fapi_scope",
|
||||
}
|
||||
@@ -29,6 +29,7 @@ const fetchEbayReadToken = async () => {
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
return data.access_token;
|
||||
} catch (error) {
|
||||
console.error("Error fetching eBay OAuth token:", error);
|
||||
@@ -36,4 +37,4 @@ const fetchEbayReadToken = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
export default fetchEbayReadToken;
|
||||
export default fetchEbayToken;
|
||||
|
||||
@@ -1,41 +1,7 @@
|
||||
import fetch from "node-fetch";
|
||||
|
||||
const fetchEbayUserToken = async (authorizationCode) => {
|
||||
const clientId = process.env.EBAY_CLIENT_ID;
|
||||
const clientSecret = process.env.EBAY_CLIENT_SECRET;
|
||||
const redirectUri = process.env.EBAY_REDIRECT_URI; // Make sure this matches the URI registered with eBay
|
||||
const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString(
|
||||
"base64"
|
||||
);
|
||||
|
||||
try {
|
||||
const response = await fetch(
|
||||
"https://api.ebay.com/identity/v1/oauth2/token",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
Authorization: `Basic ${credentials}`,
|
||||
},
|
||||
body: `grant_type=authorization_code&code=${authorizationCode}&redirect_uri=${encodeURIComponent(
|
||||
redirectUri
|
||||
)}`,
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorBody = await response.text();
|
||||
throw new Error(
|
||||
`Failed to fetch eBay user token: ${response.status} ${response.statusText} - ${errorBody}`
|
||||
);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.access_token; // This is the User access token
|
||||
} catch (error) {
|
||||
console.error("Error fetching eBay user token:", error);
|
||||
throw error;
|
||||
}
|
||||
// this is where we will use our refresh token and cycle our user tokens
|
||||
};
|
||||
|
||||
export default fetchEbayUserToken;
|
||||
|
||||
Reference in New Issue
Block a user