Val Town lets you run code incredibly easily. It could be your code, but it can also be other people’s code. This article provides a summary of how permissions work in Val Town.
- The basics
- Exposing your vals to the internet
- Public code referencing private data
- Using another’s vals as a library
- Using another’s vals as an API
To have a working understanding of the permissions system, there are only two rules that you need to remember:
- If you want to use another person’s function with access to your own secrets, pass those secrets as arguments.
- If you want to use another person’s function with access to the other person’s secrets, call it via an API.
Exposing your vals to the internet
Public vals are great because they can be called from anywhere, anytime, instantly. They can also be called by anyone.
Since anyone can call your public endpoints, if they interact with some data that should only be changed by yourself, you will need to make sure that those endpoints check for some kind of secret that only you know.
Here’s an example of a val exposed using the
If I called it without supplying the secret, I’ll be denied access:
By supplying the secret in a header, I’m allowed access:
The rest of this article will focus on various common combinations of public and private vals that you’re likely to come across and how those interact with the permissions system.
Public code referencing private data
It is safe for a a public val to reference one of your private vals or one of your secrets. Private vals and secrets are like environment variables in this way — others can see that they’re being used, but not their values.
For example, I created a private val,
example3. You won’t be able to see or reference
example3 but I can use it in
example4 which is public.
You can infer that the value of
"Stevie" because of how it’s used here. This is why you have to be careful about publishing vals that reference private data. Typically you will reference private data in a way that makes it impossible for others to infer what it is, like you would with an environment variable credentials. Below I am passing my secrets to an Upstash Redis store. You can see that I’m using these secrets and the output of this computation, but you can’t get those values, nor can you rerun this script with my secrets.
Using another’s vals as a library
Using another’s val is like using a library from npm. The code runs entirely in your sandbox and they don’t get any access to your evaluation logs. In this way it is safe to pass other’s code your private data and secrets.
There is still one exploit to be wary of, that you likewise need to be wary of when using any package on npm, and that is that the library author could maliciously rewrite the function to do something nefarious with your private data, like send it to themselves. Package ecosystems have built up a number of ways to combat this threat, such a version pinning, package scanning, and reporting.
We will soon be rolling out version pinning to help alleviate this issue, but we can confidently say that this exploit has yet to be abused in Val Town. However if you would like to be as protected as possible, we recommend forking any function you want to run onto your account to effectively pin that version.
To further protect your private data, we restrict anyone else’s vals to access your private state. Any call to
@me.secrets.foo would fail unless you are the author of the val that is making this call. The appropriate pattern to get secrets from other users on Val Town is to input them as arguments to your function, as in
@patrickjm.gpt3 used above.
Using another’s vals as an API
Sometimes you don’t want a library — you want an API. For example, you may want to call someone’s function and it relies upon using their own private data, such as one of their API keys. For example instead of passing my own OpenAI key to
@patrickjm.gpt3, I want to rely on his API key, which generously provides a small amount of free usage. You can do this by using the Val Town Run API, which turns any public val into a callable REST API. We also have a couple of helper functions to make this easier, but it’s important to know that under the hood, it’s just a normal HTTP API call.
The recommend way to do this is to use our build-in
api function. It’s magical in a couple of ways:
- It allows you to specify the name of the val you want to call without quoting it.
- It gives you proper TypeScript help for the args of the val you’re calling
- It is slightly faster than using the Run API directly because it doesn’t go out to the public internet and back to our server
api method can be approximated by this
runValAPI function, which simply calls a public val via the Run API.