Doh! I spent the past 30 minutes trying compile everything I’ve tried and the results I get back only to realize that I just did something stupid. It is working as it should. I was looking at the Message, not the Response. I’m back in business.
Though, since you’ve done something like this before, do you know how to avoid the COR error when I try to make the XMLHttpRequest back to dexcom from my html page instead of the Rule? It would be nice to do the full round trip in the HTML page rather than needing a Rule. But I do have it working in the Rule now.
I will post a tutorial once I get it working all the way.
Thanks for the push in the right direction. I always assume I’m doing something wrong and I’m usually right. 
For the curious, the WIP is as follows:
I use http://myopenhab.org/static/test.html as the redirect URL registered with Dexcom.
The code below is pretty sloppy and a WIP.
Here is test.html (I just copied the JS that parses out the arguments from a posting somewhere and haven’t reviewed it). I bet it can be done better.
<!DOCTYPE html>
<html>
<head>
<title>OAuth2 Catcher</title>
<script type="text/javascript">
function getAllUrlParams(url) {
// get query string from url (optional) or window
var queryString = url ? url.split('?')[1] : window.location.search.slice(1);
// we'll store the parameters here
var obj = {};
// if query string exists
if (queryString) {
// stuff after # is not part of query string, so get rid of it
queryString = queryString.split('#')[0];
// split our query string into its component parts
var arr = queryString.split('&');
for (var i=0; i<arr.length; i++) {
// separate the keys and the values
var a = arr[i].split('=');
// in case params look like: list[]=thing1&list[]=thing2
var paramNum = undefined;
var paramName = a[0].replace(/\[\d*\]/, function(v) {
paramNum = v.slice(1,-1);
return '';
});
// set parameter value (use 'true' if empty)
var paramValue = typeof(a[1])==='undefined' ? true : a[1];
// (optional) keep case consistent
paramName = paramName.toLowerCase();
paramValue = paramValue.toLowerCase();
// if parameter name already exists
if (obj[paramName]) {
// convert value to array (if still string)
if (typeof obj[paramName] === 'string') {
obj[paramName] = [obj[paramName]];
}
// if no array index number specified...
if (typeof paramNum === 'undefined') {
// put the value on the end of the array
obj[paramName].push(paramValue);
}
// if array index number specified...
else {
// put the value at that index number
obj[paramName][paramNum] = paramValue;
}
}
// if param name doesn't exist yet, set it
else {
obj[paramName] = paramValue;
}
}
}
return obj;
}
var code = getAllUrlParams().code;
</script>
</head>
<script>
document.write("Preparing to update AuthCode Item...")
var code = getAllUrlParams().code;
var xhr = new XMLHttpRequest();
xhr.open('POST', "https://myopenhab.org/rest/items/AuthCode");
xhr.setRequestHeader("Content-Type", "text/plain");
xhr.setRequestHeader("Accept", "application/json");
xhr.onreadystatechange = function() {
if(xhr.readyState == XMLHttpRequest.DONE && xhr.status == 200) {
document.write("Received " + code);
}
else if(xhr.status != 200) {
document.write("Error in callback: " + xhr.status + " " + xhr.responseText);
}
}
document.write("Sent " + code + "...");
xhr.send(code)
</script>
</html>
And the Rule:
import org.eclipse.xtext.xbase.lib.Functions
import java.net.URL
import java.nio.charset.StandardCharsets
import javax.net.ssl.HttpsURLConnection
import com.sun.org.apache.xml.internal.security.utils.Base64
import java.io.BufferedInputStream
import java.io.BufferedReader
import java.io.InputStreamReader
import java.text.SimpleDateFormat
import java.util.Date
val log = "dexcom"
val clientId = "CLIENT ID"
val clientSecret = "CLIENT SECRET"
val redirect = "https://myopenhab.org/static/test.html"
val tokenEndpoint = "https://sandbox-api.dexcom.com/v2/oauth2/token"
rule "Received authcode"
when
Item AuthCode received command
then
logInfo(log, "Starting to process authcode...")
val code = receivedCommand.toString
logInfo(log, "Received authcode: " + code)
val tokenURL = new URL(tokenEndpoint)
val HttpsURLConnection connection = tokenURL.openConnection() as HttpsURLConnection
val request = 'client_secret='+clientSecret+'&client_id='+clientId+'&code='+code+'&grant_type=authorization_code&redirect_uri='+redirect
logInfo(log, request)
connection.setRequestProperty('content-type', 'application/x-www-form-urlencoded')
connection.setRequestProperty('cache-control', 'no-cache')
connection.requestMethod = "POST"
connection.doOutput = true
connection.setDoInput = true
connection.outputStream.write(request.getBytes("UTF-8"))
val responseCode = connection.responseCode
logInfo(log, "HTTP Code: " + responseCode)
logInfo(log, "Message: " + connection.responseMessage)
val StringBuffer sb = new StringBuffer()
val inputStream = new BufferedInputStream(connection.getInputStream())
val BufferedReader br = new BufferedReader(new InputStreamReader(inputStream))
var String inputLine = ""
while ((inputLine = br.readLine()) != null) {
sb.append(inputLine)
}
logInfo(log, "Response: " + sb.toString)
end
rule "Received tokens"
when
Item Tokens received command
then
logInfo(log, receviedCommmand.toString)
end
``
Note, this was mostly shamelessly copied from https://community.openhab.org/t/icloud-device-data-integration-in-openhab/32329.