Generating OAuth links to provision new merchants

Last updated 04/01/2021

Introduction

To provision new merchants with Weav, you will need to dynamically generate OAuth links, unique for each merchant, commerce platform pair. This document explains the simple process of automatically generating these OAuth links, which is implemented using OAuth2.0 and JSON Web Tokens (JWTs).

You will need to direct each merchant to the personalized platform OAuth link, by embedding it in a provisioning button (e.g. Connect your Stripe) or by your preferred method.

You will need to generate different OAuth links for the commerce platforms you support. Most commonly, these links are embedded within an appropriate button.

Stripe

http://api.weav.co/provision/oauth/stripe?tok=<jwt_token>

Required parameters

Shopify

http://api.weav.co/provision/oauth/shopify-ca?tok=<jwt_token>

Required parameters

Important: Note that the link must contain shopify-ca (not just shopify)


Generating JWT tokens

For each merchant you provision, you will need to generate a JWT token. To generate JWT tokens you will need the following variables:

  • <public_key>: see your Weav go-live doc (you provided this when you onboarded)

  • <private_key>: see your Weav go-live doc (you generated this when you onboarded)

  • <account_name>: see your Weav go-live doc

  • <merchant_name>: name of the merchant being provisioned

  • <expiry_timestamp>: a timestamp for when the token expires as a NumericDate. The expiration must be after the current timestamp. We recommend setting this to 10 minutes after the current time.

    import datetime
    current_time = datetime.datetime.now(datetime.timezone.utc)
    unix_timestamp = int(current_time.timestamp())
    
    unix_timestamp_plus_10_min = unix_timestamp + (10 * 60) # 10 min * 60 sec
    
  • <shopify_store>: required for Shopify only. You will need to collect the Shopify shop name from the merchant.

Use the code snippet below to generate your JWT tokens in Python.

>>> pip install pyjwt
import jwt

jwt_token = jwt.encode({'exp': <expiry_timestamp>,
                       'iss': '<account_name>',
                       'name': '<merchant_name>'},
                       '<private_key>',
                       algorithm ='RS256')

Important: when provisioning Shopify merchants you must also include the field 'shopify_store'. Make sure to pass only the shop name (without the .com suffix.)

Example JWT for Stripe

{
  "exp": 1608218174,
  "iss": "testAccount",
  "name": "testMerchant"
}

Example JWT for Shopify

{
  "exp": 1608218174,
  "iss": "testAccount",
  "name": "testMerchant",
  "shopify_store": "testStore"
}

Important: exp field must be an int.

Notes

  • Make sure <private_key> and <public_key> are formatted properly (i.e. "-----BEGIN PUBLIC KEY-----\nMII...\n-----END PUBLIC KEY-----")
  • You can find more information on the pyjwt library and how to implement JWT in other languages here.

Putting it all together

import jwt
import datetime

current_time = datetime.datetime.now(datetime.timezone.utc)
unix_timestamp = int(current_time.timestamp())
unix_timestamp_plus_10_min = unix_timestamp + (10 * 60) # 10 min * 60 sec

jwt_token = jwt.encode({'exp': unix_timestamp_plus_10_min,
                       'iss': '<account_name>',
                       'name': '<merchant_name>'},
                       '<private_key>',
                       algorithm ='RS256')

On successful provisioning

Upon successful provisioning with Weav, the merchant will be redirected to a preconfigured callback URL that you provide (as indicated in your go-live doc.)

Callback v1

The following URL parameters will be included in the callback:

  • <weav_id>: the ID Weav uses to identify the merchant, and that you will use to query the Weav API
  • <original_id>: the merchant_name you provided in your provision request
  • <status>: returns "success" upon successful completion, otherwise an error code
  • <error>: an error code that may or may not be present depending on the user action e.g. access_denied
  • <error_description>: a more verbose description of the error code e.g. The user denied your request
  • <signature>: a signature you can use to authenticate the response parameters. Using the above parameters and your account’s assigned <api_key> (see your go-live doc) you can construct the signature to verify authenticity. See Python code:
from hashlib import sha256
# construct the signature plaintext string
sig_string = ""
if error:
    sig_string = f"{<weav_id>}_{<merchant_name>}_{error}_{error_description}_{<api_key>}"
else:
    sig_string = f"{<weav_id>}_{<merchant_name>}_{<api_key>}"
h = sha256(sig_string.encode('utf8'))
signature = base64.urlsafe_b64encode(h.digest()).decode('utf8').rstrip("=")

Callback v2

To use this callback, make sure to specificy cb=v2 in the provision URL: https://<weav>/provision/oauth/shopify-ca?cb=v2&tok=

The following URL parameters will be included in the callback:

  • <weav_id>: the ID Weav uses to identify the merchant, and that you will use to query the Weav API
  • <original_id>: the merchant_name you provided in your provision request
  • <status>: returns "success" upon successful completion, otherwise an error code
  • <vendor>: the name of the vendor that was provisioned (e.g. stripe, shopify-ca)
  • <error>: an error code that may or may not be present depending on the user action e.g. access_denied
  • <error_description>: a more verbose description of the error code e.g. The user denied your request
  • <signature>: a signature you can use to authenticate the response parameters. Using the above parameters and your account’s assigned <api_key> (see your go-live doc) you can construct the signature to verify authenticity. See Python code:
import base64
from hashlib import sha256
from urllib.parse import urlparse, parse_qs
from collections import OrderedDict

callback_url = urlparse("example_callback_url")
query_params = parse_qs(callback_url.query)
sorted_query_params = OrderedDict(sorted(query_params.items()))
api_key = "<apiKey>"
sig_string = api_key + "_" + "_".join([sorted_query_params[key][0] for key in sorted_query_params if key != "signature" and key != "state"])
h = sha256(sig_string.encode('utf8'))
final_signature = base64.urlsafe_b64encode(h.digest()).decode('utf-8').rstrip("=")

Getting started with API calls

You can now begin querying the Weav API using your <api_key> (see go-live doc) and the <weav_id>for a provisioned merchant (returned on successful provisioning).

For example, use the following command to list all transactions:

curl 'https://api.weav.co/v1/merchant/<weav_id>/transactions' -H 'Authorization: Bearer <api_key>'

We’re here to help 👌

Questions? Please don’t hesitate to reach out via Slack, email or a Zoom call. We're here to make sure your onboarding experience is seamless.


Appendix

Generating a public-private key pair

ssh-keygen -t rsa -b 4096 -m PEM -f <output .key file>
openssl rsa -in <output .key file> -pubout -outform PEM -out <output .key.pub file>

These commands will

  1. Generate a public-private key pair and write it to <output .key file> and then
  2. Extract out the public key and dump it into <output .key.pub file>. Copy the contents of this file into the Public Key column on your go-live sheet.

Privately and securely store the <output .key file> so you have the private key on hand.