Ask a Question
Back to All

Struggling to verify corrigo webhook tokens


The docs here are really light..

I'm struggling to get a valid outcome.

I've got my three pieces of info:

  1. data: I've split this out of the of token (the bit to the left of the <---->). I have successfully base64urldecoded it. eg here:
    '{"AuthenticationType":"Bearer","NameClaimType":"<http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name","RoleClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name","Claims":[{"Type":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name","Value":"><redacted>","ValueType":"<http://www.w3.org/2001/XMLSchema#string","Issuer":"LOCAL> AUTHORITY","OriginalIssuer":"LOCAL AUTHORITY"},{"Type":"urn:oauth:scope","Value":"","ValueType":"<http://www.w3.org/2001/XMLSchema#string","Issuer":"LOCAL> AUTHORITY","OriginalIssuer":"LOCAL AUTHORITY"},{"Type":"Aud","Value":"CorrigoProDirect","ValueType":"<http://www.w3.org/2001/XMLSchema#string","Issuer":"LOCAL> AUTHORITY","OriginalIssuer":"LOCAL AUTHORITY"}],"Properties":{"Dictionary":{".issued":"Wed, 28 Feb 2024 02:03:24 GMT",".expires":"Wed, 28 Feb 2024 02:23:24 GMT"}}}'
  2. sign: I've split this out of the token (the bit to the right of the <---->). Naively base64urldecoding it didn't work. I needed to first pad it with =. This spat out a bytestring.
  3. cert: I downloaded this from corrigo and have this in pem format.

From here, I'm expecting it all to validate, but it doesn't.

Here's my python code:

import base64
import x509

def padded_urlsafe_b64decode(input: str) -> bytes:
    """Same as base64.urlsafe_b64decode, but pads with '=' first."""
    p = 4 - (len(input) % 4)
    return base64.urlsafe_b64decode(input + "=" * p)

# From CorrigoProDirect admin.
cert = b"-----BEGIN CERTIFICATE-----\nMII...eVt\n-----END CERTIFICATE-----"
# From incoming webhook event.
token = 'eyJ...fX19<---->diu...PTw'

data, sign = token.split('<---->')

data_decoded = base64.urlsafe_b64decode(data)
sign_decoded = padded_urlsafe_b64decode(sign)

public_key = x509.load_pem_x509_certificate(cert).public_key()
public_key.verify(sign_decoded, data_decoded, padding.PKCS1v15(), hashes.SHA256())

I'm getting InvalidSignature coming out of the verify method.


  1. Do you have any examples of this working, so that i can compare my intermediate steps?
  2. Having to manually pad the sign before decoding seems suspicious, am I doing the right thing here?
  3. Am I using the correct padding and hashing algorithms? I've just guessed these as they don't seem to be mentioned anywhere.

I've seen some similar discussions started here, but nothing useful gleaned from those.