OAuth2 and LabVIEW — The Evolution of an Example
This is part one of a
three four part blog post where I describe how to use OAuth2 (and PKCE) with LabVIEW. OAuth2 is used to authenticate with web services such as Google, Twitter, Facebook, and almost every major cloud-based service today.
I own a slightly faulty beverage refrigerator. What makes it slightly faulty is that it sometimes wants to be a beverage freezer—it starts cooling, and doesn’t stop. It only does this rarely, and is otherwise a nice enough refrigerator that fits conveniently in a spot in our laundry room, so I’m hesitant to replace it. Instead, being the engineer I am, I decided to address the issue with more technology!
I purchased a Wireless Sensor Tag and a Wemo Mini Smart Plug to solve the problem. The Wemo Wifi plug controls power to the refrigerator. The Wireless Tag monitors temperature and humidity in the fridge. I use an IFTTT recipe to turn on the power when the temperature is too high, and turn off the power when the temperature is too low. I ask it to keep the temperature within a four Fahrenheit degree temperature range. On average, it is on for one hour, off for four hours, and then repeats.
It works surprisingly well. I set the Wireless Tag to send its data to the cloud every five minutes. I can view temperature and humidity graphs over the last several months and know it’s working. IFTTT is imperfect as a control system, but has worked out more reliably than expected. It’s only missed the too-high/too-low alarm twice in the few months since I’ve had this setup, and I work around this by having the alarm continue to trigger every fifteen minutes until the temperature is back in range.
All in, I’ve spent about $90 to avoid buying a new, inexpensive refrigerator—but it was way more fun to do it this way!
I can’t help but wonder about using LabVIEW to replace IFTTT as the controller, or to use LabVIEW to analyze my months of temperature and humidity data—and that’s where this journey begins…
LabVIEW 2019 SP1 code for this example can be found on https://gitlab.com/bhpowell/oauth2-labview-tutorial.
What is OAuth2?
WirelessTag, being cloud-based and realizing their path to success involves connectivity to the rest of the world of “Internet of Things”, has a web service API. This is how IFTTT can know the temperature of my refrigerator and turn on and off a switch in my house.
This API has a security authentication system that uses the OAuth2 workflow. I’ve given permission to IFTTT to access my sensor, but I didn’t need to give IFTTT my WirelessTag username and password—and since it doesn’t have my password, it can’t maliciously login and sabotage my WirelessTag account.
OAuth2 is an industry standard, and commonly used for web and mobile applications.
A simplified version of the OAuth2 workflow is…
- A “client” (the app I’m writing) asks the “resource owner” (me) for permission to access a “resource server” (a server that contains data such as my temperature and humidity data).
- Typically, this means I have to login to the resource server with my credentials, and then an “authorization server” associated with the resource asks if it’s okay for “client” to access “resource server” directly.
- If I say yes, “client” is given an access token for API calls to “resource server”.
That’s basically it. There are complicating factors—various things can go wrong, tokens expire, access can be revoked. But we’ll get to those later.
One important step is that you must register the client app with the authorization server in advance. Basically, the authorization server wants to know what apps are connecting to it, and wants a way to turn off an app if it starts to cause problems. As an app developer, when you register your client app, the authorization server gives you a “secret”. This is kind of like a password for your app, so that when the client and server communicate with each other, the server knows who the client is. In the end, access to your data is only granted if your username and password are correct, and if the client ID and client secret are correct.
I won’t go into all of the security facets of this protocol, but this example is also going to show you how to use the PKCE extension to the OAuth2 workflow. This makes it even harder for malicious software to intercept the authorization protocol and steal an access token.
There are alternate workflows for getting a token that I may describe that in future blog posts.
OAuth2 in LabVIEW
Being a commonly-used workflow, I initially imagined that someone has already made it easy to use OAuth2 in LabVIEW. Like all software developers everywhere, I searched the web for the answer. I came up short. I found an older OAuth1 toolkit, and I found a partial OAuth2 example, but nothing that I felt was sufficiently useful. So, I set out to write my own solution, and with encouragement from Fabiola De la Cueva, I decided to write this blog post about it.
A Google Search quickly yielded a C# example (OAuth for Apps: Samples for Windows) that was close to what I wanted—just written in the wrong programming language. I came up with a plan:
- Confirm I could run the C# Google example that accesses Google APIs
- Confirm I could modify the example in C# to access WirelessTag data
- Reimplement the Google API example in LabVIEW
- Write a blog post about #3 <—- you are here
- Start writing LabVIEW code to access my WirelessTag data
- Write a blog post about #5
From Code to Example
My general approach to writing software is to get something working first, and then refine it/refactor it until I think it’s understandable, maintainable, and efficient. In this blog post, I want to explain that part of the process, too. In fact, there were a few “expedient” decisions I made that ought to be replaced with something more elegant, and I’m hoping I can spark a discussion about ways to improve the example. More on that as we go along.
Let’s get started.
Creating a LabVIEW Web Service
As I begin to translate C# to LabVIEW, I immediately face a difficult challenge… I need a web server that can be contacted by the authentication server. It’s not a simple, “I send you a request and you send me a response”. Instead, it’s, “I send you a request and tell you where to meet me later on.” And because all communications happen through Secure HTTP, that means I need a web server.
In C#, there’s an “HttpListener” class that makes this easy. In LabVIEW, I created a web service.
I’m not going to go into all the details about how to create LabVIEW web services. If you haven’t tried it before, I’d recommend NI’s tutorial for creating and access LabVIEW web services.
In our case, we only need to support one kind of request, so I called my web service “OAuth” and my endpoint “Redirect”. The URL to call it will be https://localhost:8001/OAuth/Redirect.
When I call the authentication endpoint, it will call me back at that URL, and pass information as parameters to the callback. It’ll look something like:
where “<state>” is a string used to help me keep track of which call I’ve made, and “<code>” is a string that I’ll need in later calls. There are a few other parameters that are passed, but they aren’t important right now.
In the first version of this VI, I copied the values for <state> and <code> into front panel indicators and let the LabVIEW Web Service method convert that to JSON for display in the web browser. It was a great way to debug the web service, since I could just enter a URL like https://localhost:8001/OAuth/Redirect?state=abc&code=123 and see the results in the web browser.
But eventually, I turned this into a “streaming” VI so that I could control the HTML output, and be more faithful to the original C# example. I needed a way to pass the keys and values from the query string back to LabVIEW.
Since I had label/value pairs (such as “state” and its value), I decided to use the new LabVIEW 2019 feature of Maps. I wrote a simple helper VI (“Parse Query String.vi”) which adds every key/value in the query string into an entry in the Map.
Question #1 for readers:
It seemed difficult to create a Map where both the label and value were strings. The default control uses int32’s for values, and I didn’t see an easy way to change the "value" datatype anywhere. I ended up using “Build Map” with two strings, and then creating a constant/control from that output. Is there an easier way?
Question #2 for readers:
For passing the map back to the rest of my program (which is outside the web service), I did the expedient thing and put it and the error cluster into globals.
I was trying to minimize the coupling between the web service and the rest of my app. I could have used a queue, but I’d either have to put the queue reference in a global, or pick a name and require both sides to use the same queue name.
I could have created another web service endpoint that I could call to retrieve the query strings, but I’d need to know when it was safe to call.
Basically, I couldn’t think of anything simpler than polling until the global “Query Strings” wasn’t empty (or an error occurred).
What would you have done?
Another expedient thing I did was to require you to start and stop the web service manually. The only way to programmatically start and stop a web service in LabVIEW is to build and deploy it as a separate application, and I felt like it made for a better example if I didn’t go down that path.
For now, you have to right click on “OAuth” in the Project Window and select “Start” to start the web service.
I often forget to do this, so when I run my app and after granting permission, I get a 404 error when the Redirect to my URL fails.
In Part 2, we'll write code that uses this callback. I'm interested to hear from you about the questions I've posed--please comment below.