This guide will outline all necessary steps to form a proper JWS. This example uses the ACH v2 API, but please note that this approach to forming the JWS is the same across all of the latest versioned US Payments APIs.
Step 1 : JWS Signature
All payment requests will need to be signed with a JWS signature. This step makes certain that no one tampered with the payload after the signature was generated.
SVB provides code samples in Python below to calculate the JWS signature.
Python code sample
Below Python and json files can be grouped and used to calculate the JWS signature token. When below files are grouped within a project, following command can be executed to retrieve the JWS signature:
- -f /detached-jwt-utility/payload.json -s clientSecret
- where the first parameter is the absolute path to the request payload (i.e. payload.json in this example) and the second parameter is the secret string received form the API support team (clientSecret).
detachedJWT.py
from jwcrypto import jwk, jwt from InputOpt import InputOption import uuid def main(): input = InputOption() InputOption.input() print(DetachedJWT.detached_jwt(input.get_filePath(), input.get_secret())) class DetachedJWT: @staticmethod def detached_jwt(filePath, secret): key = jwk.JWK.from_password(secret) # Reading the input payload to be signed file = open(filePath, "r") payload = file.read() # Generating headers with necessary claims headers = {"alg": "HS256", "kid": str(uuid.uuid4()), "typ": "JOSE"} # Creating the jwstoken and sign jwstoken = jwt.JWT(header=headers, claims=payload) jwstoken.make_signed_token(key) sig = jwstoken.serialize() # Detaching JWT splittedJWS = sig.split(".") splittedJWS[1] = "" print("printing the jws token") return '.'.join(splittedJWS) if __name__ == "__main__": main()
InputOpt.py
import getopt import sys class InputOption: @staticmethod def usage(): print("ToCreateDetachJET: python detachedJWT.py -f <filePath.json> -s <Secret key>") @staticmethod def input(): try: (opts, args) = getopt.getopt(sys.argv[1:], 'f:s:h', ['filePath=', 'secret=', 'help']) except getopt.GetoptError as err: print(err) sys.exit(2) if len(opts) != 0: for (o, a) in opts: if o in ('-h', '--help'): InputOption.usage() sys.exit() elif o in ('-f', '--filePath'): global filePath filePath = str(a) InputOption.set_filePath(filePath) elif o in ('-s', '--secret'): global secret secret = str(a) InputOption.set_secret(secret) else: InputOption.usage() sys.exit(2) else: InputOption.usage() sys.exit(2) def set_filePath(filePath): filePath = filePath def get_filePath(self): return filePath def set_secret(secret): secret = secret def get_secret(self): return secret
payload.json
{ "buy": { "currency_code": "EUR", "value": "100.00" }, "sell_currency": "USD", "tenor": "TOD" }
Step 2 : oAuth 2.0 Access Token
ACH payment requests leverage two input parameters for security: JWS signature and oAuth 2.0 access token.
An API request to /v1/security/oauth/token is submitted to retrieve an access token.
/token endpoint uses Basic Authorization with a username/password pair which represent the credentials received by the API Support/Implementations team.
Step 3 : Submitting an ACH payment request
API requests will use an authorization type: Bearer token : access token, where the access token represents the token returned from the /token endpoint in Step 2.
JWS signature token from Step 1 will be included as a header parameter: