├── .gitignore ├── .python-version ├── README.md ├── requirements.txt ├── sample.env ├── shopify_flask.py └── templates ├── login.html └── products.html /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | __pycache__/ 3 | .env -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.8.0 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # shopify-flask-embedded 2 | 3 | This is an example Shopify application written in Python with Flask which authenticates with Shopify via OAuth, performs authenticated API requests, and initializes the Shopify App Bridge library. 4 | 5 | ## Getting started 6 | 7 | 1. Create a new Shopify application from the [Shopify Partner Dashboard](https://partners.shopify.com). 8 | 2. In the root folder of the project, create a new file named `.env` or copy the provided sample (`cp sample.env .env`) 9 | 3. Add your API key and secret key (from the Shopify Partner Dashboard) to the `.env` file. 10 | 4. Install the requirements for this project via pip (`pip install -r requirements.txt`) 11 | 5. Run the project with `env FLASK_APP=shopify_flask.py flask run` 12 | 13 | 7. Navigate to the application in your browser, supplying the domain of your Shopify store as the `shop` query parameter (`https://22638980.ngrok.io/?shop=my-shop.myshopify.com`) 14 | 15 | NOTE: This app assumes that it is running over HTTPS - the easiest way to achieve this is by using a tunneling service like [ngrok](https://ngrok.com) 16 | 17 | Make sure to enable third-party cookies in your browser! Some browsers such as Safari and Chromium block third-party cookies by default. 18 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask >= 1.1.1 2 | ShopifyAPI >= 5.1.2 3 | python-dotenv >= 0.10.3 -------------------------------------------------------------------------------- /sample.env: -------------------------------------------------------------------------------- 1 | API_KEY=1c558730b249c438a4c22891fa65089a 2 | API_SECRET=390b2d8d1a464bd8dc1893bd21dd2fc5 -------------------------------------------------------------------------------- /shopify_flask.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, redirect, render_template, request, session, url_for 2 | from pyactiveresource.connection import UnauthorizedAccess 3 | import shopify 4 | import os 5 | import binascii 6 | from dotenv import load_dotenv 7 | load_dotenv() 8 | 9 | app = Flask(__name__) 10 | 11 | # Generate a random key for signing the session: 12 | app.secret_key = binascii.hexlify(os.urandom(16)) 13 | 14 | # API credentials are sourced from enviroment variables: 15 | API_KEY = os.getenv("API_KEY") 16 | API_SECRET = os.getenv("API_SECRET") 17 | API_VERSION = '2019-10' 18 | shopify.Session.setup(api_key=API_KEY, secret=API_SECRET) 19 | 20 | 21 | @app.route('/') 22 | def index(): 23 | if not is_authenticated(): 24 | return login() 25 | 26 | api_session = shopify.Session( 27 | session['shop'], 28 | API_VERSION, 29 | session['access_token']) 30 | 31 | shopify.ShopifyResource.activate_session(api_session) 32 | 33 | try: 34 | products = shopify.Product.find(limit=10) 35 | except UnauthorizedAccess: 36 | return login() 37 | except: 38 | return "An unknown error occured.", 500 39 | 40 | return render_template('products.html', api_key=API_KEY, products=products) 41 | 42 | 43 | @app.route('/auth/shopify/callback') 44 | def oauth_callback(): 45 | params = request.args 46 | shop = params['shop'] 47 | 48 | try: 49 | token = shopify.Session(shop, API_VERSION).request_token(params) 50 | except shopify.session.ValidationException: 51 | return "HMAC signature does not match. Check your API credentials.", 400 52 | except: 53 | return "An unknown error occured.", 500 54 | 55 | session['shop'] = shop 56 | session['access_token'] = token 57 | 58 | return redirect(url_for('index')) 59 | 60 | 61 | def is_authenticated(): 62 | params = request.args 63 | if ('shop' in params) & ('shop' in session): 64 | if session['shop'] != params['shop']: 65 | clear_session() 66 | return False 67 | 68 | return 'access_token' in session 69 | 70 | 71 | def clear_session(): 72 | del session['shop'] 73 | del session['access_token'] 74 | 75 | 76 | def login(): 77 | scopes = ['read_products'] 78 | 79 | shop = request.args.get('shop', None) 80 | if shop is not None: 81 | return render_template( 82 | 'login.html', 83 | shop=shop, 84 | api_key=API_KEY, 85 | scopes=','.join(scopes), 86 | redirect_uri=url_for('oauth_callback', _external=True, _scheme='https')) 87 | 88 | else: 89 | return "No shop parameter provided.", 400 90 | -------------------------------------------------------------------------------- /templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Logging in... 5 | 6 | 7 | 25 | -------------------------------------------------------------------------------- /templates/products.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 18 |

Your products:

19 | 24 | --------------------------------------------------------------------------------