Nextjs api and authentication - node.js

I'm in the process of building an application for stripe payments. This application generates a form that passes the data to the Stripe api via nextjs api. I just need to build in some basic authentication so only those submitting their payments via my form have access to the api. How would I go about adding some basic auth to my api without requiring users to login? Would I do this via env variable? I'm fairly new to the nextjs/vercel world and come from the python/django/react realm, so maybe my thoughts on this are backwards... I'm planning on hosting the api on vercel and the react form on a php site. So the react form will essentially push data to the vercel app api.
(The reason I'm not building the api in php is because I don't know php and because I'm attempting to build something with as little footprint in the current php site as possible.) Any help or guidance on this would be much appreciated!
My pages/api/customers.js file
import Stripe from 'stripe'
const stripe = new Stripe(process.env.SECRET_KEY)
export default async (req, res) => {
if (req.method === 'POST') {
try {
const { email, name, address, phone, source } = req.body
// Check for customer
const customerExist = await stripe.customers.list(
{
email: email,
limit: 0
})
// console.log('customerExist', customerExist.data[0])
if (customerExist.data.length < 1) {
const customer = await stripe.customers.create({
email,
name,
address,
phone,
source
})
res.status(200).send(customer.id)
} else {
res.status(200).send(customerExist.data[0].id)
}
} catch (err) {
res.status(500).json({ statusCode: 500, message: err.message })
}
} else {
res.setHeader('Allow', 'POST')
res.status(405).end('Method Not Allowed')
}
}
Part of my checkout form
// Function to check/create a user account via api
const checkUserAccount = async (billingDetails, source) => {
try {
const customer = await axios.post('/api/customers', {
email: billingDetails.email,
name: billingDetails.name,
phone: billingDetails.phone,
address: billingDetails.address,
source: source
})
return customer.data
} catch (err) {
console.log(err)
}
}
UPDATE:
Alright, so I added a "TOKEN" to my .env file and now require my api to receive that specific token.
I added this to my checkout form:
...
axios.defaults.headers.common.Authorization = process.env.AUTH_TOKEN
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
...
and then added this to the api:
if (req.method === 'POST' && req.headers.authorization === process.env.AUTH_TOKEN)...
Since I'm not using a login/logout system, I'm hoping this is enough. Thoughts or feedback are more than welcome.

Related

Oauth2 with Google docs API Node.js (trying to programmatically write a new google doc)

I have a typical web app with a client and a node.js server. When a user selects an option on the client, I want to export (create) a google doc in their drive.
I am half way there following this tutorial https://developers.google.com/identity/protocols/oauth2/web-server
With my current set up, after the user authenticates, the authentication token is sent to a web hook (server side), but I don't have any of the data for creating the google doc there.
If I did, I could create the doc from there. Otherwise, I need to send the token itself back to the client so I can create the doc with the necessary payload from there.
In that case, I don't know how to signal to the client that the user has been authenticated. Should I use a web socket?
Something tells me that my general set up might not be correct, and that I should be doing it a different way in my use case.
This is my client side code that brings the user to the google auth page after getting the auth url (not sure if this really needs to be done server side, but since I have some user credentials I thought it might be better).
export async function exportToGoogleDoc() {
const response = await POST(`${API_URL}export/gdoc`, {
'hello': 'world'
});
if (response.status == 200){
window.location.href = response.authUrl;
}
}
And then the endpoint (just returns the autheticationUrl)
api.post('/export/gdoc', express.raw({ type: 'application/json' }), async (req, res, next) => {
try {
const scopes = [
'https://www.googleapis.com/auth/drive'
];
const oauth2Client = new google.auth.OAuth2(
credentials.web.client_id,
credentials.web.client_secret,
credentials.web.redirect_uris[0]
);
const authorizationUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
include_granted_scopes: true
});
res.json({ 'status': 200, authUrl : authorizationUrl } );
} catch (err){
next(err);
}
});
But then after the user agrees and authenticates with their google account, the auth token is sent to this web hook. At the bottom I am able to write an empty google doc to the authenticated google drive, but I don't have the data I need to create the real doc.
api.get('/auth/google', express.raw({ type: 'application/json' }), async (req, res, next) => {
const q = url.parse(req.url, true).query;
const oauth2Client = new google.auth.OAuth2(
credentials.web.client_id,
credentials.web.client_secret,
credentials.web.redirect_uris[0]
);
if (q.error) {
console.log('Error:' + q.error);
} else {
const { tokens } = await oauth2Client.getToken(q.code.toString());
oauth2Client.setCredentials(tokens);
const drive = google.drive('v3');
const requestBody = {
'name': 'Dabble',
'mimeType': 'application/vnd.google-apps.document',
};
drive.files.create({
requestBody: requestBody,
fields: 'id',
auth: oauth2Client
}, function (err, file) {
if (err) {
// Handle error
console.error(err);
} else {
console.log('File Id: ', file);
}
});
}
Somehow I either need to get the data for the google doc inside this web hook, or to listen for this web hook from the client.
OR I need an entirely different set up. I realize I also should be probably storing this token somewhere (local storage on client side?) and only making this call if they do not have a token.
Can anyone help me modify my set up? Thanks!

register webhooks on nodejs when order created

I have a shopify store mystore and I have an nodejs app myapp. I need to do is when something happens on mystore a webhook will be created/registered in my nodejs app. I have tried https://www.npmjs.com/package/#shopify/koa-shopify-webhooks this package but it is not working for me and I don't think that it is the same thing that I want. I just want that when let suppose order is created in store a webhook is registered.
if you just have to register a webhook you can use this code.
You just have to change the webhook topic and the endpoint.
This is for orders/create webhook registration
add shopify-api-node and request-promise packages and require them
const ShopifyAPIClient = require("shopify-api-node");
const request = require("request-promise");
then
const createOrderWebhook = await registerWebhook(yourShopDomain, yourShopAccessToken, {
topic: "orders/create",
address: "Your node app end point" //www.example.com/webhooks/createOrder,
format: "json",
});
add your registerWebhook function
const registerWebhook = async function (shopDomain, accessToken, webhook) {
const shopify = new ShopifyAPIClient({
shopName: shopDomain,
accessToken: accessToken,
});
const isCreated = await checkWebhookStatus(shopDomain, accessToken, webhook);
if (!isCreated) {
shopify.webhook.create(webhook).then(
(response) => console.log(`webhook '${webhook.topic}' created`),
(err) =>
console.log(
`Error creating webhook '${webhook.topic}'. ${JSON.stringify(
err.response.body
)}`
)
);
}
};
for checking the webhook already not created at Shopify you can use following code
const checkWebhookStatus = async function (shopDomain, accessToken, webhook) {
try {
const shopifyWebhookUrl =
"https://" + shopDomain + "/admin/api/2020-07/webhooks.json";
const webhookListData = {
method: "GET",
url: shopifyWebhookUrl,
json: true,
headers: {
"X-Shopify-Access-Token": accessToken,
"content-type": "application/json",
},
};
let response = await request.get(webhookListData);
if (response) {
let webhookTopics = response.webhooks.map((webhook) => {
return webhook.topic;
});
return webhookTopics.includes(webhook.topic);
} else {
return false;
}
} catch (error) {
console.log("This is the error", error);
return false;
}
};
Happy coding :)
You can not create/register a new webhook when the order created.
Webhooks are a tool for retrieving and storing data from a certain event. They allow you to register an https:// URL where the event data can be stored in JSON or XML formats. Webhooks are commonly used for:
Placing an order
Changing a product's price
Notifying your IM client or your pager when you are offline
Collecting data for data-warehousing
Integrating your accounting software
Filtering the order items and informing various shippers about the order
Removing customer data from your database when they uninstall your app

The provided dynamic link domain is not configured or authorized for the current project

My aim is sending email for sign up users using Firebase function and authentication.
I followed Firebase example.
But it tells below error message.
The provided dynamic link domain is not configured or authorized for
the current project
My code is at below.
const actionCodeSettings = {
url: 'https://www.example.com/finishSignUp?cartId=1234',
handleCodeInApp: true,
iOS: {
bundleId: 'com.example.ios'
},
android: {
packageName: 'com.example.android',
installApp: true,
minimumVersion: '12'
},
dynamicLinkDomain: 'example.page.link'
};
exports.sendmail = functions.https.onRequest((req, res) => {
return cors(req, res, () => {
firebase.auth().sendSignInLinkToEmail("sungyong#humminglab.io", actionCodeSettings)
.then((userCredential) => {
res.status(200).send(userCredential);
res.status(200).send(userCredential);
return;
})
.catch(error => {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(error)
// ...
res.status(400).send(error);
});
});
});
Here are my configuration at my console.
example.page.link is not configured as a dynamic link domain for your project.
You need to use one you own. You can get that from "Dynamic Links" under "Grow" in the left menu of the Firebase Console.
If you don't need to use dynamic links with mobile flows, just change to:
const actionCodeSettings = {
// Replace this URL with the URL where the user will complete sign-in.
url: 'https://www.example.com/finishSignUp?cartId=1234',
handleCodeInApp: true
};
Add "example.page.link" in the Authorised domain instead of www.example.com.
Because example.page.link is your domain id.

React-Redux app with Node backend shows previous user's info on login

I've got an app which requests a bunch of plots from the backend based on the present user's company code. The problem is that when a user logs in, it shows him the previous user's plots. On refresh, the app shows the current user's plots, as it is supposed to.
I'm using JWT stored in local storage for authentication. Looking in local storage, the user's information is properly stored and disposed of on logout.
The API endpoint:
if (req.user.companyCode === 'admin') {
plotStatus = await PlotStatus.find({}).lean();
} else {
plotStatus = await PlotStatus.find({
company: req.user.companyCode
}).lean();
}
if (!plotStatus) {
throw new Error('Plot Statuses not found');
} else {
res.send(plotStatus);
}
The Redux action:
export function fetchPlotStatuses() {
const user = JSON.parse(localStorage.getItem('user'));
return function(dispatch) {
axios
.get(`${ROOT_URL}/plotstatuses`, {
headers: { authorization: user.token }
})
.then(response => {
dispatch({
type: FETCH_PLOTSTATUSES,
payload: response.data
});
});
};
}

REST API Security and CrossPlatform

I'm working on rest api with node.js. I create jwt-token in /signup endpoint. Then send this token every ios-app,windowsphone-app requests in Authoriziton header. So api try find user which contain this token. If its have then return responses.
I'm worry about security. Everybody will monitoring api addresses for create user and get token then use this token for all endpoints. So will post data an infinate number to other schemas and application be garbage, dies.
How can prevent this situation ? Native iOS,Windows Phone apps and Web Site used to this api. Whats the best way handling security and user management somelike cross platform application api's ? Is there good documentation for this sturucture ?
There is user scheme.
var userSchema = mongoose.Schema({
token:String,
favorites:[favorites],
local : {
username:String,
email: String,
password: String,
sex:Number
},
facebook: {
id:String,
token:String,
email:String,
name:String
},
lists:[{listid:String,insertdate:Date}]
});
Every endpoint control authorization like this
function ensureAuthorized(req, res, next) {
var bearerToken;
console.log(req.headers);
var bearerHeader = req.headers["authorization"];
if (typeof bearerHeader !== 'undefined') {
req.token = bearerHeader;
User.findOne({'token':bearerHeader},function(err,currentUser){
if(err)
res.json({success:false,description:err});
console.log("current" + currentUser);
if(currentUser)
{
req.user = currentUser;
next();
}
else
{
res.status(403).end();
}
});
} else {
res.status(403).end();
}
}
Thank you all.

Resources