I'm following Coinbase's guide on sending bitcoin to someone via the API. Coinbase requires user to enter 2FA code when sendMoney() is called. Then I somehow need to put this code in the HTTP header for sendMoney() to successfully execute. But I'm not sure how to make this work with Coinbase's API (sendMoney() has no parameter for setting the HTTP header). I think I could manually POST to URL instead of calling sendMoney(), but I'm not sure what parameters to pass.
function getBalance(client, res){
client.getAccount('BTC', function(err,account){
// SENDING MONEY REQUIRES 2FA
account.sendMoney({
'to': '3MLCRpMDXC3AFBsaSLNimWfJFvsMVBq4Ac',
'amount': '0.0000018',
'currency': 'BTC'
}, function(err, txt){
res.render('authPurchase'); // RENDER INPUT FIELD FOR USER TO ENTER 2FA CODE
});
});
} // how do I 'replay' the above sendMoney request with the 2FA code in the http header?
Coinbase Docs provide this walkthrough, but sadly no example pertaining to making a POST request with 2FA authorization.
1. User is sending funds and the app calls POST api.coinbase.com/v2/accounts/primary/transactions
2. Server responds with 402 and sends the user a 2FA token via SMS if he doesn’t have Authy installed
3. App re-plays the request from step 1 with exactly same parameters and the 2FA token in the CB-2FA-TOKEN header (HOW????)
4. Transaction is sent and 201 CREATED status code is returned
I figured it out!
module.exports.replaySendMoney = function replaySendMoney(smsCode){
// in the future access token will be stored and retrieved from database
var Client = require('coinbase').Client;
let accessToken = '2aac7a723eb58bfaf13a9073ac7b6982dca072f14fa0abbc766e9ed9f60be596';
let refreshToken = '17a609e13c7608ecd499a1be502da19a7095ccf2d5fe9f40fca2b87501f7c233';
var client = new Client({'accessToken': accessToken, 'refreshToken': refreshToken});
client.getAccount('BTC', function(err,acct){
// REQUIRES 2FA
acct.sendMoney({
'to': '3MLCRpMDoC3AFBsbSLNimWfJFvsMVBq4Ac',
'amount': '0.0000018',
'currency': 'BTC',
'two_factor_token' : smsCode
}, function(err, txt){
console.log(err);
console.log(txt);
res.render('authPurchase', {});
});
});
}
Related
In a Vue app I have a login. With email and password I send a POST request against the node express backend. If email and password don't match I send back a 409 HTTP status code with a message: "No access! In my POST fetch block I intercept the status code and check if I didn't get a 200 status. If this is the case, I send an error message. If I have a 200 status code I put the JWT token into a cookie. This works. But to be honest, I find the check for the status code too low.
What approaches are there to check the login response. Are there other approaches? Thanks a lot!
async submit() {
try {
const d = await fetch(config.apiUri + "sign-in", {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'omit',
body: JSON.stringify(this.data),
});
const j = await d.json();
if (d.status !== 200) {
this.errorMsg = j.message
console.log(this.errorMsg)
return;
}
accessHelper.setToken(j.token, this.mys);
accessHelper.setAuth = true;
this.$router.push("/");
} catch(err) {
console.log("Something went wrong", err)
}
}
For login use cases most "magic" happens on the server. That includes
hashing and salting the password when it's stored and updated,
hashing and checking the received password during logins
You'd want to lock accounts after a certain number of failed logins
and lock IPs after a certain number of failed logins.
After a successful login you're server sends some kind of authentication information (in your case a JWT), which allows the frontend to access secured endpoints. The frontend can't really know more than the fact that the username / password combination was not correct. Therefore, it's fine to only check for the status code.
This OWASP Cheat Sheet contains some useful information in regards to Authentication.
If you feel uncomfortable with handling logins you could think about using OAUTH with e.g. GitHub and/or authentication services like Firebase Authentication
I wrote the below twilio function to store incoming messages into a postgres database in RDS on AWS. I'm getting a 504 timeout error. Details of how I am running:
I'm running this by deploying the function to twilio & adding it as a widget to a twilio studio flow.
My postgres database is in RDS. It is publicly accessible and I'm able to access it from my local machine (I added a security rule for My IP. I'm not sure if I need to add a rule for Twilio, I could find a specific IP they would be on.)
This is my personal computer, so it shouldn't have any extra firewalls. Any thoughts would be appreciated!
I'm not sure if:
There is something wrong with the below script or
AWS/RDS database is refusing connection. I don't know how to properly update my security rules to allow traffic from twilio.
const{Client} = require("pg");
exports.handler = async function(context, event, callback) {
console.log("HELLO")
// Not sure what the below does
// context.callbackWaitsForEmptyEventLoop = false;
// Add database config
const client = new Client({
host: context.host,
port: context.port,
user: context.user,
password: context.password,
database: context.database
});
// Try actually connecting to the database
try {
await client.connect();
console.log("connected successfully");
const user = ["12222222222", "2022-07-10T00:22:10Z", '{"question1": {"question": "How are you?", "answer": "great"}}'];
// Try to actually store the data
await client.query("INSERT INTO text_responses (phone_number, datetime, response) VALUES ($1, $2, $3::jsonb)", user);
await client.end();
console.log("Executed!");
callback(null, "12222222222");
} catch (e) {
console.log(`error: ${e}`);
callback(e);
}
};
Twilio error
Outbound HTTP Request Failed: Request URL: https://example-2039-dev.twil.io/log-sms-db
Request Method: POST
Response Status Code: 502
Response Content Type:
Error - 81016
Outgoing HTTP request failed
The outgoing HTTP request from a Studio widget failed.
Possible Causes
The URL you are requesting is incorrect
The response is badly formed
The URL returned a 4xx or 5xx error code
Possible Solutions
Make sure the request results in a response code 2xx or 3xx
I am using sign-in with apple using the following link in Nuxt app:
https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js
So the problem is if I don't use usePopup flag and use the server link with redirectURI then apple does makes a post request to redirectURI then request completes successfully but I can't get the data from the server.
and If I use the usePopup: true then I have to do the post request to the server then it fails (apple response: invalid request) I am using expressjs as a server.
AppleID.auth.init({
clientId: "my-client-id", // This is the service ID we created.
scope: "name email", // To tell apple we want the user name and emails fields in the response it sends us.
redirectURI: "https://9b29-103-213-105-122.in.ngrok.io/login", // As registered along with our service ID
state: "origin:web", // Any string of your choice that you may use for some logic. It's optional and you may omit it.
usePopup: true, // Important if we want to capture the data apple sends on the client side.
});
then after the response from the following code I make the post request:
this.appleResponse = await AppleID.auth.signIn();
I store users in firebase realtime database and stripe to handle payments. An authenticated user can click a button and will get redirected to Stripe Checkout. After making a payment, user gets redirected to success_url back in the app. Next I would like to update user Object in database - just save the information that the payment was successful and its id.
The problem: I don't know how to find a user which completed a payment, after redirection to success_url. I would like to update user's data on database after the payment.
The idea: I can save the payment_intent in the user profile, as this information is sent to the client side with a session. And then, after the payment completion I could search for the payment_intent and update the user which had this data. But is this a good approach? Is there any better way to find a user?
My code is based on Firebase Cloud Function HTTP Requests.
Following the Stripe guidelines to accept a payment, I create a session for a user which wants to make a payment:
export const payment = functions.https.onRequest((request, response) => {
cors(request, response, async () => {
response.set("Access-Control-Allow-Headers", "Content-Type");
response.set("Access-Control-Allow-Credentials", "true");
response.set("Access-Control-Allow-Origin", "*");
await stripe.checkout.sessions.create(
{
payment_method_types: ["card"],
line_items: [
{
price_data: {
currency: "usd",
product_data: {
name: "Test"
},
unit_amount: 1000
},
quantity: 1
}
],
mode: "payment",
success_url: "https://example.com/success",
cancel_url: "https://example.com/cancel"
},
function(err: Error, session: any) {
response.send(session);
// the session is sent to the client and can be used to finalise a transaction
}
);
});
});
On the client side I use axios to call a payment cloud function request and afterwards I pass the sessionId to Stripe.redirectToCheckout which starts the checkout redirection:
let sessionId = "";
await axios.post("payment function url request")
.then(response => {
sessionId = response.data.id;
});
const stripe: any = await loadStripe("stripe key");
stripe.redirectToCheckout({
sessionId: sessionId
});
After the customer completes a payment on Stripe Checkout, they’re redirected to the URL that is specified as success_url, it is advised to run a webhook from stripe when the checkout is completed.
It allows to fire another cloud function, which sends a response to the client side about a successful payment response.json({ received: true }):
export const successfulPayment = functions.https.onRequest(
(request, response) => {
const sig = request.headers["stripe-signature"];
let event;
try {
event = stripe.webhooks.constructEvent(
request.rawBody,
sig,
endpointSecret
);
} catch (err) {
return response.status(400).send(`Webhook Error: ${err.message}`);
}
// Handle the checkout.session.completed event
// Should I update the user data in the database here?
if (event.type === "checkout.session.completed") {
const session = event.data.object;
console.log(`Event passed: ${session}`);
}
// Return a response to acknowledge receipt of the event
response.json({ received: true });
// Or how do I use this response to then update the user from the client side?
}
);
I will really appreciate all the help and suggestions :)
Thanks for your question, kabugh!
Next I would like to update user Object in database - just save the information that the payment was successful and its id.
First, you likely do not want to use the success URL as a signal for storing successful payment. It's possible the customer closes their browser, the internet connection between your server and the customer drops out, or that the customer just navigates away after successful payment and before hitting the success URL. Instead, it's highly recommended to use webhooks, specifically listening for the checkout.session.completed event. From the success URL, you can retrieve the Checkout Session and show the status to the customer if they land there, but you don't want to use that for fulfillment or as the source of truth for the status of the payment.
I can save the payment_intent in the user profile, as this information is sent to the client side with a session. And then, after the payment completion I could search for the payment_intent and update the user which had this data. But is this a good approach? Is there any better way to find a user?
I believe you mean the Checkout Session ID, not the PaymentIntent ID here. The PaymentIntent ID will not be created until after the user is redirected. Yes, this is a good idea and a good practice to store a reference to the ID of the Checkout Session with the user profile somewhere in your db. You could also set a metadata value on the Checkout Session when you create it, with some reference to the user's ID in your system. That way when you receive the checkout.session.completed webhook event, you can look up the user by ID based on the ID stored in metadata or by the ID of the Checkout Session stored with the user profile as discussed earlier.
it is advised to run a webhook from stripe when the checkout is completed. It allows to fire another cloud function, which sends a response to the client side about a successful payment response.json({ received: true })
Note that the webhook event is a POST request from Stripe's servers directly to your server. It will not in any way render or send a response back to the customer's browser or client. The webhook response from your server goes back to Stripe and there is no concept of a shared session between those three parties. When sending response.json({ received: true }) as the result of a webhook handler, that is sent back to Stripe, not to the customer's browser.
I need to retrieve some data from Google Search Console (Webmaster Tools) using a service account.
So far I've been able to retrieve an access_token for the service account which I need to append to the url of the request. The problem is that I can't find a way to do so, this is the code i'm using:
function retrieveSearchesByQuery(token)
{
gapi.client.webmasters.searchanalytics.query(
{
'access_token': token,
'siteUrl': 'http://www.WEBSITE.com',
'fields': 'responseAggregationType,rows',
'resource': {
'startDate': formatDate(cSDate),
'endDate': formatDate(cEDate),
'dimensions': [
'date'
]
}
})
.then(function(response) {
console.log(response);
})
.then(null, function(err) {
console.log(err);
});
}
This is the url called by the function:
https://content.googleapis.com/webmasters/v3/sites/http%3A%2F%2Fwww.WEBSITE.com/searchAnalytics/query?fields=responseAggregationType%2Crows&alt=json"
Instead it should be something like this:
https://content.googleapis.com/webmasters/v3/sites/http%3A%2F%2Fwww.WEBSITE.com/searchAnalytics/query?fields=responseAggregationType%2Crows&alt=json&access_token=XXX"
The gapi.client.webmasters.searchanalytics.query doesn't recognize 'access_token' as a valid key thus it doesn't append it to the url and that's why I get a 401 Unauthorized as response.
If I use 'key' instead of 'access_token' the parameter gets appended to the url but 'key' is used for OAuth2 authentication so the service account token I pass is not valid.
Does anyone have a solution or a workaround for this?
If your application requests private data, the request must be authorized by an authenticated user who has access to that data. As specified in the documentation of the Search Console API, your application must use OAuth 2.0 to authorize requests. No other authorization protocols are supported.
If you application is correctly configured, when using the Google API, an authenticated request looks exactly like an unauthenticated request. As stated in the documentation, if the application has received an OAuth 2.0 token, the JavaScript client library includes it in the request automatically.
You're mentioning that you have retrieved an access_token, if correctly received, the API client will automatically send this token for you, you don't have to append it yourself.
A very basic workflow to authenticate and once authenticated, send a request would looks like the following code. The Search Console API can use the following scopes: https://www.googleapis.com/auth/webmasters and https://www.googleapis.com/auth/webmasters.readonly.
var clientId = 'YOUR CLIENT ID';
var apiKey = 'YOUR API KEY';
var scopes = 'https://www.googleapis.com/auth/webmasters';
function auth() {
// Set the API key.
gapi.client.setApiKey(apiKey);
// Start the auth process using our client ID & the required scopes.
gapi.auth2.init({
client_id: clientId,
scope: scopes
})
.then(function () {
// We're authenticated, let's go...
// Load the webmasters API, then query the API
gapi.client.load('webmasters', 'v3')
.then(retrieveSearchesByQuery);
});
}
// Load the API client and auth library
gapi.load('client:auth2', auth);
At this point, your retrieveSearchesByQuery function will need to be modified since it doesn't need to get a token by argument anymore in order to pass it in the query. The JavaScript client library should include it in the request automatically.
You can also use the API Explorer to check what parameters are supported for a specific query and check the associated request.
If you need to use an externally generated access token, which should be the case with a Service Account, you need to use the gapi.auth.setToken method to sets the OAuth 2.0 token object yourself for the application:
gapi.auth.setToken(token_Object);