Signing HTTP requests

Signing API requests with the private key

The Authorization header is a JWS (signed JWT) that includes few standard claims, plus the digest computed as described above. Below there is a complete example in Python with the relevant comments. Once you compute the JWS, just add it to every request as an Authorization header:

curl -d '{"key1":"value1", "key2":"value2"}' -H "Authorization: Bearer eyJ0e...cYjeaRcw" https://api.finqware.com/v1s/...

For some programming languages, Google provides libraries/wrappers for signing payloads, but this may be achieved in any programming language using standard libraries.

import time

import google.auth.crypt
import google.auth.jwt
import hashlib
import json
import base64

def generate_jwt():
    now = int(time.time())

    payload = {
        "client_id": "51e2389....02d51",
        "client_app_key": "MDAxNmxvY2F0aWMz...D9rgv7_DySaiYgo", 
        "skill": "bt_ro_aisp_sbx_#2.0"
        }
    
    # a compact stringified json without any whitespaces
    json_payload = json.dumps(payload, separators=(',', ':')).encode("utf-8")

    digest = hashlib.sha256(json_payload).digest()
    b64_digest = base64.b64encode(digest).decode("utf-8")

    # service account email: this is auto-generated by GCP when creating a service account
    sa_email='service-account1@my-gcp-project.iam.gserviceaccount.com'

    # how long this JWS should be valid for.
    #   - each request will have its own JWS so this value should be small
    expiry_length=3600

    # build the payload for your signed Authorization header
    payload = {
        'iat': now,
        # expires after 'expiry_length' seconds.
        "exp": now + expiry_length,
        # iss (issuer) should match the service account's email address
        'iss': sa_email,
        # aud (audience) is alwasy ('api.finqware.com')
        'aud':  'api.finqware.com',
        # sub and email should match the service account's email address
        'sub': sa_email,
        'email': sa_email,
        # a Base64 encoded sha-256 hash of the request payload as described above
        'digest': b64_digest
    }

    # the signing/private key is inside this json file downloaded when creating
    # a public/private key pair for a service account
    sa_keyfile='my-gcp-private-key.json',

    # sign with your service account keyfile
    signer = google.auth.crypt.RSASigner.from_service_account_file(sa_keyfile)
    jwt = google.auth.jwt.encode(signer, payload)

    return jwt

if __name__ == '__main__':
  jwt = generate_jwt()
  print(jwt)

Last updated