Using Webtask.io for Secure API Tokens
Single Page Applications are awesome. One downside is that static SPAs often have to authenticate with some service or API in order to coordinate some communication, access some data, or connect to other users, and that connection has an inherent security risk:
How do you connect to a secure service from an insecure (client side) source?
There are a multitude of ways to do this, but they usually involve setting up your own server to handle authentication or OAuth to the external service. Here's one way that I recently worked out.
My Goal
- Connect a javascript application to Respoke
- ... without creating my own server component
- ... safely and securely
The Respoke docs have a pretty clearcut way of authenticating - just require
their respoke-admin
module in your node server, call authenticate with your AppId and AppSecret, and get back a token, then pass that token to your client to start making API calls to Respoke.
Uh oh! Those steps assume I've got a server! What if I want to eliminate that part entirely? Here steps in webtask, an ephemeral, almost-entirely-stateless proxy-esque server for executing code on a server - but not your server. There's nothing to host, it's not constantly running, and you don't have to deploy anything. All you do is create an account, give it some code, get a secure token, and let your clients make requests to that code. Ok, so that was a lot. Let's take a step back:
-
Create a webtask account at webtask.io
-
Install their cli tools with
npm install -g wt-cli
, then follow instructions to authenticate
- This associates your local installation with your webtask.io account, allowing you to create new tasks that are associated with your account
- Create your webtask with
wt create task-code.js --secret my_app_secret=mysecretvalue my_app_id=myappid
- This will spit back a URL that can be included on your page and can be executed by anyone. The best part? your secret values are now encrypted and inaccessible from the client.
- When a client makes a request to this URL, they can include any request data associated with the request via query parameters, and your task can read that data via
ctx.data.[param]
- Your task code can also access the secret values provided when the task was created, so they don't have to be hard-coded into your code. These are also accessible off of the
ctx.data
object. - The new cli is really nice, because this allows creating a webtask that stores both the code and the token (previously, you'd have to get back a token encrypted with your account id and secret values, and pass it to your task)
Complete Working Example
So what does the code in my-task.js
actually look like? For my respoke app, it's this basic code, taken almost verbatim from their API documentation example:
There's one tiny complication to this - you can't require
npm modules with webtask, so any modules that your code requires (mine requires respoke-admin
) have to be included in your task's javascript file directly. This might take some work if you have nested dependencies, but what I did was start in-lining all required modules until it ran successfully, then minified the result. (If you know if a tool that does this, please let me know.)
So my end result is that I have a file called respoke-auth.js
:
And I can create my task with
wt create respoke-auth.js --secret my_respoke_app=[redacted] my_respoke_secret=[redacted]
And I get the url: https://webtask.it.auth0.com/api/run/wt-xander_dumaine-gmail_com-0/respoke-auth
that can be used in an unauthenticated, client-side context to get a secure auth token to my Respoke account. This example uses this whole flow to make a client connection to Respoke:
Caching and Updating
One downside to the way I created my webtask above is that in order to update my task code, I'd have to re-create my task entirely. This isn't ideal, so instead of passing the code file itself, I can host my code file, and provide the task a url, and it will fetch the code from the URL, each time it's executed.
wt create http://example.com/my-task.js --secret ....
This way, you can just update my-task.js
as necessary and not affect the webtask.
Bonus
Want a neat way to host that task file with virtually no work at all? Use surge.sh
npm install -g surge
surge
Surge will deploy your static files to their domain (or your own!) and host it for free, with basically no setup. You can do this with github pages, but it takes more setup and configuration.