Need help with code_verifier and code_challenge in an OAuth2 authentication process

Hi, the I'm using the following code to get the code_verifier and code_challenge strings for an OAUTH2 authentication, which wasn't working but unknown to me because until a few days ago, the code_verifier string was well, never verified by the authenticator (duh!). Now it does this verification so I need to fix the code to make it work for real

_code_verifier = StringUtil.convertEncodedString(Cryptography.randomBytes(86/2), {
	:fromRepresentation => StringUtil.REPRESENTATION_BYTE_ARRAY,
	:toRepresentation => StringUtil.REPRESENTATION_STRING_HEX,
});

var code_verifier_bytes = StringUtil.convertEncodedString(_code_verifier, {
	:fromRepresentation => StringUtil.REPRESENTATION_STRING_PLAIN_TEXT,
	:toRepresentation => StringUtil.REPRESENTATION_BYTE_ARRAY,
});

var hmac = new Cryptography.HashBasedMessageAuthenticationCode({
	:algorithm => Cryptography.HASH_SHA256,
	:key => code_verifier_bytes
});

var code_challenge = StringUtil.convertEncodedString(hmac.digest(), {
	:fromRepresentation => StringUtil.REPRESENTATION_BYTE_ARRAY,
	:toRepresentation => StringUtil.REPRESENTATION_STRING_BASE64,
});

Reason I say it doesn't work is two fold. First, well the authentication process now returns 400 with "invalid code_verifier" and when I enter the code_verifier in online converters like https://tonyxu-io.github.io/pkce-generator/ and https://referbruv.com/utilities/pkce-generator-online/, I get a different answer than them for code_challenge. Anybody knows what's wrong with the code because myself, I've pound at it for a few hours and still come empty :-( I'm using ConnecytIQ 4.1.5 SDK if it matters but I tried a few and get the same result (I didn't try more recent ones because of type definition errors that I'll tackle another time).

BTW, I know I need to make the code_challenge URL friendly, which I do later but it shouldn't affect what is returned (beside for + / and = characters, which are replaced with - _ and 'skipped').

Thanks.

  • Still working on this. I believe it's something wrong (or I'm doing wrong) with the HashBasedMessageAuthenticationCode - HASH_SHA256 routine because if I plug the code_challenge returned by the https://tonyxu-io.github.io/pkce-generator/ website instead of the value calculated above (ie, SHA256 + Base64 encoding), I get a successful connection (but hmm, that ain't an option lol)

    To pin point which of the hashing or encoding function is giving me an issue, I dumped the digest from hmac (the one computed by the code above) into a binary file that I sent to https://www.base64encode.org/ and the Base64 encoded value returned is the same as Base64 given by the code above so the encoding is working fine. Only thing left is the SHA256 hash function isn't returning the same hash as what is expected by everyone else.

    So, anybody know if the HashBasedMessageAuthenticationCode function is buggy or am I using it wrong?

    Thanks.

  • I'm not sure but try this

    - key should be your secret key not data

    - after create hmc you have to use hmc.update(code_verifier_bytes)

    - than hmc.digest() should be good

  • With a fresh head this afternoon, found the problem in less than 15 minutes lol. Mind you, my hours yesterday helped me understand the cryptography routines in the Garmin SDK though :-)

    Turns out, the original use of HashBasedMessageAuthenticationCode was wrong. There is NO key here and when I looked at the simply 'hash' fonction, I completely skipped yesterday that you pass it the hash method. I wrongfully thought the 'key' here, like the original writer of the code, was the string to hash. I changed the code to this and it works. I'll let the original writer of the code know so he can fix his if he so whishes.

    var hmac = new Cryptography.Hash({ :algorithm => Cryptography.HASH_SHA256 });
    hmac.update(code_verifier_bytes);
    

    Plus, since the EncodeBase64 routine doesn't make it URL safe (couldn't find a method for that), I added this to fix that Base64. Might not be pretty but it works :-)

    // Need to make code_challenge URL safe. '+' becomes '-', '/' becomes '_' and '=' are skipped
    var cc_array = code_challenge.toCharArray();
    var cc_len = code_challenge.length();
    var code_challenge_fixed = "";
    
    for (var i = 0; i < cc_len; i++) {
    	switch (cc_array[i]) {
    		case '+':
    			code_challenge_fixed=code_challenge_fixed + '-';
    			break;
    
    		case '/':
    			code_challenge_fixed=code_challenge_fixed + '_';
    			break;
    
    		case '=':
    			break;
    
    		default:
    			code_challenge_fixed=code_challenge_fixed + cc_array[i].toString();
    	}
    }	
    

  • You might want to make the url safe bit a function, then just call that passing your code verifier or code challenge.  I to am doing PKCE auth, but getting -104 due to lack of phone connection during code exchange for token!