401 Error when sending data to Stripe `Customers` API - stripe-payments

I want to create a new customer in Stripe upon form submit and add that customer's credit card to their account. As of now, I'm using the following code upon submit in my React App. The create customer call is then made separately from my server:
async submit(ev) {
let {token} = await this.props.stripe.createToken({name: "Name"});
let response = await fetch("https://api.stripe.com/v1/customers", {
method: "POST",
headers: {"Content-Type": "text/plain"},
body: token.id
});
When sending that data, I get a 401 error on the let response = ... line. I know that a 401 is an auth error, but my test API keys are definitely correct and don't have limits on how they can access my stripe account. Can anyone advise?

The issue here is that you are trying to create a Customer object client-side in raw Javascript. This API request requires your Secret API key. This means you can never do this client-side, otherwise anyone could find your API key and use it to make refunds or transfer for example.
Instead, you need to send the token to your own server. There, you will be able to create a Customer or a Charge using one of Stripe's official libraries instead of making the raw HTTP request yourself.

In my case, it's throwing the error due to a missing of stripe public key
var stripe = Stripe('{{ env("STRIPE_KEY") }}');
then I pass the public key as above, and it worked like a charm.

Related

handling stripe webhook in multiple stripe account laravel

I've multiple stripe account on my site, and each stripe account is associated with a webhook.
My webhook is returning 403 Error "No signatures found matching the expected signature for payload"
i've checked the Cashier middleware and its getting the webhook secret key from the env file.
Since this project attached to multiple stripe account, we can't store the webhook secret in env file. so, we're placing the webhook secret key of each stripe account in a table.
I would like to get the secret key from database instead of this config file.
Is it possible to listen to multiple stripe account's webhook?
Any help will be appreciated.
I am not sure if this is a good approach but you can:
Send meta data in the checkout which gets posted to the web hook
Get the raw json posted by the web hook before you use the web hook key to validate that the post was from Stripe. Stripe.Net contains a parse method and a construct method. Parse does not require the key. Construct uses the key to validate the post was from Stripe.
So with Stripe.net:
string endpointSecret;
// get the json posted
var json = await new
StreamReader(HttpContext.Request.Body).ReadToEndAsync();
// convert the json into a stripe event object
var objStripeEvent = EventUtility.ParseEvent(json);
if (objStripeEvent.Type == Events.CheckoutSessionCompleted)
{
// get the session object and see if it contains the Meta data we passed
// in at checkout
var session = objStripeEvent.Data.Object as Session;
var met = session.Metadata;
if (met.ContainsKey("FranchiseGuid"))
{
// if the meta data contains the franchise guid get the correct
// wh secret from the DB
var FranchiseGuid= new Guid(met["FranchiseGuid"]);
endpointSecret = _repo.GetWebHookSecret(FranchiseGuid);
}
}
// Then you can go on to use the Construct method to validate the post with the correct key for the Stripe account where the web hook is based.
try
{
// check if was from Stripe
var stripeEvent = EventUtility.ConstructEvent(
json,
Request.Headers["Stripe-Signature"],
endpointSecret);
---- etc
I've requested help on this from Stripe support but they have promised to get back to me. I'll test out the above to see if it works. I don't think it's ideal though because if a hacker were able to get a valid franchise guid they could possibly fake posts and spam the endpoint. It would not be easy to guess a guid and these id's are not available in any way publicly. Plus https is used. But it still makes me nervous because the franchise guid would be one of a dozen or more. Not like a booking guid which is generated and sent once for the booking that is marked as paid. The franchise guid would be sent every time a payment was made for that franchise.
I think what I may do is use the booking guid since this is randomly generated for every booking. I can join to the franchise table from the booking and get the web hook secret.
We'll see if Stripe come back with something useful.

Unauthenticated response status from firebase function

whenever i try to POST request to function https://europe-west3-[my-project].cloudfunctions.net/[my-function-name] i got a 401 response with body:
{
"error": {
"message": "Unauthenticated",
"status": "UNAUTHENTICATED"
}
}
the method itself consists of validation:
export const myFunctionName = regionFunctions.https.onCall(
async (request, context) => {
if (!userIsAuthenticated(context)) return {status: 401}
if (!userIsAdmin(context)) return {status: 403}
await syncCategories()
return {status: 200}
})
export const userIsAuthenticated = (context: CallableContext) => {
return context.auth
}
what I try to do, is to use server key from firebase project settings in request Authorization header.
Am I using wrong server key or what could be the issue?
Thanks a lot.
For callable functions, you're typically not supposed to deal with headers at all. The client SDK will handle all of that automatically for you, as shown in the documentation.
But if you do need to invoke a callable function directly using HTTPS, the Authorization header needs to be a Firebase Authentication user ID token as described in the protocol documentation. It is not a server key.
Thank you Doug,
your answer helped me to fix this issue.
What I have done:
Logged in to my application, through browser console looked at user ID token, copied it to Authorization header and it worked.
Yes, it is possible to use an API KEY from google cloud.
you must use this concept:
Request format: headers
The HTTP request to a callable trigger endpoint must be a POST with the following headers:
Optional: X-Firebase-AppCheck:
The Firebase App Check token provided by the client app making the request. The backend automatically verifies this token and decodes it, injecting the appId in the handler's context. If the token cannot be verified, the request is rejected. (Available for SDK >=3.14.0)
If any other headers are included, the request is rejected, as described in the response documentation below.

DocuSign API Can't download signed PDFs USER_LACKS_MEMBERSHIP Error

I am using the envelopes list status changes api and getting the error below. I am the only user on the account and a DS Admin. Also, we have used this code successfully with other DocuSign accounts.
Can you please help me resolve the issue?
Error:
ApiException: Error while requesting server, received a non successful HTTP code 400 with response
Body:
'{"errorCode":"USER_LACKS_MEMBERSHIP","message":"The UserID does not have a valid membership in this Account."}'
ApiClient apiClient = new ApiClient(basePath);
apiClient.setAccessToken(token, tokenExpirationSeconds);
EnvelopesApi envelopesApi = new EnvelopesApi(apiClient);
// prepare the request body
EnvelopesApi.ListStatusChangesOptions options = envelopesApi.new ListStatusChangesOptions();
LocalDate date = LocalDate.now().minusDays(30);
options.setFromDate(date.toString("yyyy/MM/dd"));
// call the API - ERROR HERE
EnvelopesInformation results = envelopesApi.listStatusChanges(accountId, options);
the userId you used for your JWT token must be an admin of the same exact account in DocuSign.
Any chance you use demo vs. production? two different accounts?
This error simply means your API calls is using a user that is not authorized to view this envelope because it lacks a membership to the account that this envelope is part of.
The most common cause of that error (after you've confirmed the account ID is correct) is hitting the wrong Base URL for the account. The first time you generate an authentication token for a particular user, you should make a UserInfo call and cache the BaseURL value.
Thanks! Ended up rebuilding credentials from scratch. I appreciate the insights.

Node POST request not working for Instagram API: This client has not been approved to access this resource

I'm trying to do some simple GET/POST requests with Instagram's API. I have a get request that uses the request node module and it works fine. I have an access token attached to the end of my query https://api.instagram.com/v1/users/[user]/media/recent?[access_token]
request(
{url, method: "GET"}, function(error, response, body) {
var parsed = JSON.parse(body)
console.log(parsed.data[5])
});
However, when I try to make a post request in postman with the following query:
https://api.instagram.com/v1/media/[media-id]/likes?[authID]
it displays
{"meta":
{"error_type":"OAuthPermissionsException","code":400,"error_message":"This
client has not been approved to access this resource."}}
I'm in sandbox mode and the docs specify that you can do up to 30 POST req's to an endpoint an hour with no live account. Can anybody shed some light on this?
What kind of scopes you have requested for this token? Your GET request requires just public_content permission, while POST likes requires likes scope. You should add this permission to scope list during authorization.

Accessing a public calendar using Google API without requiring a user to log in

I'd like to access a public calendar using Google's REST API.
Google's calendar API suggests I need an OAuth token to get access to calendars:
https://developers.google.com/google-apps/calendar/auth
However, I'm accessing a public calendar and am doing this from the server so can't/shouldn't have to ask the user to authenticate.
I'm using the node.js api:
googleapis
.discover('calendar', 'v3').execute(function(err, client) {
client.calendar.calendars.get({ calendarId: '***#group.calendar.google.com' })
.execute(function (err, response) {
console.log('response from google', response);
});
});
This returns "Your client has issued a malformed or illegal request. That’s all we know."
Calling .withApiKey('***') after .calendars.get() returns the same error.
Any suggestions?
Oh come on guys! You can fetch data without OAuth without requiring a user to login as long as the calendar is set to be public! I've tested it myself.
$.ajax({
url:"https://www.googleapis.com/calendar/v3/calendars/" + cal_id + "/events?key=" + api_key,
success: function(data) {
console.log(data);
}
});
Just try it.
The documentation is here https://developers.google.com/google-apps/calendar/v3/reference/events/list#examples
As the documentation states more than once
All requests to the Google Calendar API must be authorized by an authenticated user.
Hence, if you want to use the google calendar API you need an authenticated user. This can be easily achieved using modules like Passport.js and Passport-google-oauth.
However, if you can leave aside the API for a moment and
the calendar is public
you want read only access
you can easily grab the public address and consume the calendar through ical, xml or html. Have a look at the UK holidays public calendar: http://imgur.com/UGjPtqp
You can access the data publicly from:
xml https://www.google.com/calendar/feeds/en.uk%23holiday%40group.v.calendar.google.com/public/basic
ical https://www.google.com/calendar/ical/en.uk%23holiday%40group.v.calendar.google.com/public/basic.ics
html https://www.google.com/calendar/embed?src=en.uk%23holiday%40group.v.calendar.google.com&ctz=Europe/London
At this point, it's trivial to fetch such resources with node and get the data you want.

Resources