Hashing Secret + Payload for SSO

I’m attempting to follow the official SSO guide. I’m using Golang on my server, and I’m trying to match the HMAC-SHA256 hash of the payload + secret to the sig, but I’m getting different values. How are you doing your hashing? Are you breaking the payload down to the raw, unsigned content and rehashing it?

What does your code look like?

Did you base64 encode the payload?

And did you get the parameter order right? Different languages / libraries have different parameter orders (key, message) or (message, key). That is what fools me every time.

1 Like

After parsing the payload it appears to be in base64 by default, but the 256SHA has of the base64 encoded payload isn’t correct. I’m using the example secret and URL from the OG post.

The following code gives me the following output:

 payloadURL = bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI=

sig = 2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56
payloadRaw = nonce=cb68251eefb5211e58c00ff1395f0c0b
payload256 = KCiqKYmXIrNaLxkdNO+bPOaV4Obu7EfetG1YjXDHy1Y=

My code:

testURL := "http://www.example.com/discourse/sso?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D%0A&sig=2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56"	
	ssoSecret := "d836444a9e4084d5b224a60c208dce14"

	// grab the payload and sig from the URL query
	u, err := url.Parse(testURL)
	if err != nil {
		log.Fatal(err)
	}

	q := u.Query()
	payloadURL := strings.Trim(fmt.Sprint(q["sso"]), "=[]")
	sig := strings.Trim(fmt.Sprint(q["sig"]), "[]")
	
	fmt.Printf("payloadURL = %s\n", payloadURL)
	fmt.Printf("sig = %s\n", sig)

	// get the raw payload from the base64 version
	payloadRaw, err := base64.StdEncoding.DecodeString(payloadURL)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("payloadRaw = %s\n", payloadRaw)
	
	key := []byte(ssoSecret)
	message := []byte(payloadURL)
	hash := hmac.New(sha256.New, key)
	hash.Write(message)
	payload256 := base64.StdEncoding.EncodeToString(hash.Sum(nil))
	if err != nil {
		log.Fatal(err)
	}
	
	fmt.Printf("payload256 = %s\n", payload256)

	// sig is hex encoded, so hex encode the hashed payload so we can compare.
	//hashAsString := hex.EncodeToString(hash.Sum(nil))

	// compare the hex-encoded hash of payload to the hex-encoded sig
	if strings.Compare(payload256, sig) != 0 {
		log.Fatal(err)
	}

Update: I fixed this after encoding my resulting HMAC-SHA256 hash to hex (the signature is also hex encoded. Also see this post that says that the examples in the SSO guide are incorrect. So I changed this code:

key := []byte(ssoSecret)
message := []byte(payloadURL)
hash := hmac.New(sha256.New, key)
hash.Write(message)
payload256 := hex.EncodeToString(hash.Sum(nil))
if err != nil {
	log.Fatal(err)
}

Where does payload256 come from?

Sorry, I’ve updated the OP with cleaner code.

What is that %0A doing there just before &sig? That’s a URLencoded linefeed… that is why there is a blank line in your debug output after you print the payloadURL, it is still tacked on at the end.

1 Like

Good catch! I fixed that here by adding the newline character to the .Trim() parameters:

payloadURL := strings.Trim(fmt.Sprint(q["sso"]), "[]\n")

So my output is now:

payloadURL = bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI=
sig = 2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56
payloadRaw = nonce=cb68251eefb5211e58c00ff1395f0c0b
payload256 = HOFJT5RIS29qCSvpsVzMHNr7H4Rgo4OPuw4Ig8Q5BHE=

You should look at where the newline is actually coming from and avoid it being added.

Also, the payload should have more name=value pairs than just the nonce?

1 Like

This is just the example stuff from the Discourse SSO guide, so I can’t tell where the newline is from. Apparently the guide is wrong (according to this post), and it looks like there was a copy/paste error in the example.

Maybe there is a bit too much copy pasting from different versions.

But looking at your post just above this one, your payloadURL is not urlencoded and payload256 is not hex encoded but base64 encoded.

Maybe you can repost your current code and your current output.

1 Like