Python app on heroku dosn't open the Stripe Payment page

Question:

I am trying to integrate Stripe payments in a flutter web app. To do this I’ve written a python script that I’m hosting on heroku:

import json
import os
import stripe
from flask import Flask, render_template, jsonify, request
from flask_cors import CORS

# This is your test secret API key.
stripe.api_key = 'sk_test_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'


app = Flask(__name__, static_folder='public',static_url_path='', template_folder='public') 
CORS(app)
app.config['CORS_HEADERS'] = 'Content-Type'


def calculate_order_amount(items):
    # Replace this constant with a calculation of the order's amount
    # Calculate the order total on the server to prevent
    # people from directly manipulating the amount on the client
    return 1400

@app.route('/create-payment-intent', methods=['POST'])
def create_payment():
    print('Processing checkout')
    request_data = request.data
    request_data = json.loads(request_data.decode('utf-8'))
    print(request_data)

    try:
        parking = request_data['parking']

        items = [
                {
                    'price_data': {
                        'currency':'aud',
                        'product_data': {
                            'name': parking['name'],
                        },
                        'unit_amount': parking['amount'],
                    },
                    'quantity':1,
                }
            ],
        print(request.data)
        # Create a PaymentIntent with the order amount and currency
        intent = stripe.PaymentIntent.create(
            amount=40*100,
            currency='aud',
            payment_method_types=["card"],
        )
        return jsonify({
            'clientSecret': intent['client_secret']
        })
    except Exception as e:
        print('Error Occured: {}'.format(e))
        return jsonify(error=str(e)), 403
        
if __name__ == '__main__':
    app.run(port=4242)

From my flutter app, I am doing this:

var url = Uri.parse('https://spaceshuttleparking-checkout.herokuapp.com/create-payment-intent');
final response = await http.post(
headers:{
  "Accept": "application/json",
  "Access-Control-Allow-Origin": "*"
 },
url,
body: json.encode(
     {
       'parking':{
          'name':parking.name,
          'amount':parking.amount,
              }
       }
       )).then((value) {
         print(value.body);
         print(value.statusCode);
         print(value.request);
        });

In my flutter app , I get the following output:

    200
POST https://spaceshuttleparking-checkout.herokuapp.com/create-payment-intent
{"clientSecret":"pi_3LXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"}

On heroku logs, I get the following:

2022-09-12T07:49:08.216994+00:00 app[web.1]: Processing checkout
2022-09-12T07:49:08.238030+00:00 app[web.1]: {'parking': {'name': 'Undercover Park & Fly', 'amount': 38}}
2022-09-12T07:49:08.238031+00:00 app[web.1]: b'{"parking":{"name":"Undercover Park & Fly","amount":38}}'
2022-09-12T07:49:08.647809+00:00 heroku[router]: at=info method=POST path="/create-payment-intent" host=spaceshuttleparking-checkout.herokuapp.com request_id=43b4cc48-c3a1-44ec-b240-821901183e5b fwd="119.18.0.79" dyno=web.1 connect=0ms service=431ms status=200 bytes=291 protocol=https
2022-09-12T07:49:08.647485+00:00 app[web.1]: 10.1.32.94 - - [12/Sep/2022:07:49:08 +0000] "POST /create-payment-intent HTTP/1.1" 200 80 "http://localhost:8620/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.33"

I am super new to this stuff so I am not sure what I am missing. Why doesn’t the server open the stripe checkout page?

Asked By: Danish Ajaib

||

Answers:

I don’t know if an intent is used to open a checkout page.
You can try to use the stripe.checkout object.
This is some code taken from their docs:

@app.route('/create-checkout-session', methods=['POST'])
def create_checkout_session():
  session = stripe.checkout.Session.create(
    line_items=[{
      'price_data': {
        'currency': 'usd',
        'product_data': {
          'name': 'T-shirt',
        },
        'unit_amount': 2000,
      },
      'quantity': 1,
    }],
    mode='payment',
    success_url='https://example.com/success',
    cancel_url='https://example.com/cancel',
  )

  return redirect(session.url, code=303)
Answered By: vladc

You need to configure the CORS Headers Server (Flask) Side.

See this answer for more information on doing so in Flask: Python Flask Cors Issue


Some recommendations:

As you have also mentioned that you are new to this, and it is dealing with Stripe payment stuff, please read the documentation for Flask and Flask CORS regarding running securely.

The first issue would be to avoid using Flask.run() (app.run(), in your example), instead use a production ready WSGI server. See this section of the flask docs on how to do so: https://flask.palletsprojects.com/en/2.2.x/tutorial/deploy/#run-with-a-production-server

Secondly, if you are implementing Flask CORS, be sure to implement some CSRF mitigation. A pretty good article can be found here: https://testdriven.io/blog/csrf-flask/

Answered By: Tech1337