Secrets Store General Availability

GDay Creators,

Today we’re launching the Secrets Store. Announced at RDC 2023, this service lets you keep Secrets - for example, API Keys - separate from your code. Previously in beta, we’re now making it available to everyone.

What is the Secrets Store?

Roblox HttpService allows game servers to send HTTP requests to external services, usually requiring authentication. The most popular way is API Key authentication, when the secret is sent as a request header. Previously, creators had to store secrets as plain text in Luau scripts, or in Datastores.

Now you can leverage the Roblox Secrets Store to prevent API key leaks. We’re releasing a new method GetSecret, provided by the HttpService, which returns a secret that can be used in the HttpService:RequestAsync function call. The secret content is not printable, by design. Secret(SecretId) is printed instead of the actual content. Secrets are available in Production (game servers) or in the Team Create environment. For security reasons, experiences running locally cannot use Secrets.

Creating and updating Secrets

Navigate to your Experience in the Creator Hub and find the Secrets page under Configure.

Secret content cannot be retrieved through the Creator Hub. Secrets are encrypted using your Experience public key before they are sent to Roblox. Encryption is performed locally in your browser. When the game server starts, it retrieves all associated secrets from the Secrets Store and decrypts the content.

You can change the Secret content and domain restrictions:

Note: updated secrets are not pushed to currently running game servers. If you create a new secret, update or delete an existing one, you need to restart the game server for new values to take effect. This protects your experience from global outages, should the secret content happen to be invalid.

Using Secrets

Secrets Store provides a safer replacement for plain text secrets in the source code. For example, if you had a Yelp integration with the hardcoded API Key:

local yelpApiKey = "CZhtkLDpNYXgPH9Ml6shqh2OwykChw"

You can replace it with the following, provided that you uploaded your Yelp secret for the experience:

local yelpApiKey = HttpService:GetSecret("yelp")

It is possible to store the secret together with some extra text (e.g. Bearer CZhtkLDpNYXgPH9Ml6shqh2OwykChw). However, storing just the key and applying a transformation in the Luau script source code may be more convenient.

Transformations

There are two basic transformations, addPrefix and addSuffix, that you can apply to the secret content. The former inserts a string at the beginning of the secret content, designed to prepend header names. For example, Bearer string, as in the Yelp example below:

local yelpApiKey = HttpService:GetSecret("yelp_api_key")

local url = "https://api.yelp.com/v3/businesses/search?location=" 
   .. location .. "&term=restaurants&categories=&price=2&sort_by=best_match&limit=5"

local response = HttpService:RequestAsync({
    Url = url,
    Method = "GET",
    Headers = {
          ["accept"] = "application/json",
          ["Authorization"] = yelpApiKey:addPrefix("Bearer ")
    }
})

Use addSuffix to append a string to the secret. Below is an example of creating a URL containing an API key. Be aware that secret content must be URL encoded for this to work.

local mySiteApiKey = HttpService:GetSecret("my_site")
local url = "https://apis.mysite.com/?apiKey="
local suffix = "&request=join&user=myname"

local urlWithKey = mySiteApiKey:addPrefix(url)
local resultingUrl = urlWithKey:addSuffix(suffix)

Domain Restriction

Every secret is associated with a domain name. If the domain name is empty, the secret cannot be sent over the network (and therefore could not be used as an API key). Set the domain name to star (*) to allow sending the secret anywhere. You can limit the URL to a specific domain name (e.g. apis.myservice.com), or subdomains of a domain (e.g. *.myservice.org). Using the star anywhere except the first character is not supported.

Limitations

  • Secrets cannot be used in the HTTP request body.
  • Secret content cannot be larger than 1024 bytes.
  • There is a limit of 500 secrets per experience.
  • For group-owned experience, only the group owner is allowed to view and edit Secrets.

Next steps

  • We’re working on expanding OpenCloud APIs support for Secret Store
  • We’re looking into a way to use Secrets locally
  • We’ll be filtering URLs in the Network Server console if it contains a Secret
  • We are also looking to implement advanced permissions for group-owned experiences to provide more flexibility than limiting access to group owners.
  • Last, but not least, we’re considering upgrading HttpService with mutual TLS (mTLS, also known as “client certificates”), with Secrets Store used for private keys.

Thank you for your feedback so far! Please reply to this post with any questions or concerns.

Cheers,
The Roblox Creator Services Team

289 Likes

This topic was automatically opened after 11 minutes.

This is an amazing update! I can finally store my keys securely without worrying about leaking them

32 Likes

Finally, no more hacky DataStore key storage or worse plaintext.

25 Likes

This is an amazing feature me and my team were looking forward to use :DD

Would this change in the future or will it stay limited to the owner due to security concerns? This feature would be more feasible if it was allowed to certain developers working under a studio (lead devs).

22 Likes

Nice job, I hope this is used more and more by teams to help with backdoor hacking from bad members. :tada:

18 Likes

We would absolutely love to see this introduced. Should we make a feature request so that the desire and use cases are in the system?

17 Likes

Good use for API Keys and other private information u might not want to share. But uhh, can team create members see your secrets? If not, then that’s a really good feature to fully protect your API keys, even from development members.

14 Likes

Super useful, no longer have to worry about accidently leaking my keys!

14 Likes

Is this a typo? I get this works because of some __index shenanigans, but you should really match the actual method name defined here

15 Likes

There was a beta group? Never got a notification that I was added and didn’t get added, weird.

Anyways, like I said, this is an amazing feature. Thanks to the Roblox Staff that developed it.

Couple of questions:

  1. Do we know if OpenCloud will support OAuth or just API keys?
  2. Is there a way to get every secret that is under a user? I’m still developing a feature for myself (might open source it later on) and going to see if I can use this externally for other resources as well!
  3. Will there be a way for us to create secrets from OpenCloud or will we have to register them in Creator Dashboard?
10 Likes

Since it isn’t a Luau Datatype but rather a Roblox one, I don’t understand why they made the Secret 's methods camelCase

11 Likes

They are PascalCase, its a typo that works because the Instance __index has some interesting legacy stuff where camelCase keys get converted to PascalCase (dont rely on this behaviour, its hacky af)

6 Likes

This will be fixed, they weren’t intended to be camelCase in the design, someone made a typo when implementing it. (don’t worry if you’re already using it, we won’t break the camelCase one)

10 Likes

Is it possible to use Secrets with GetAsync and PostAsync?

6 Likes

We are working on it - it’s listed in the Next Steps section.

We have it in the internal system - but reminding us never hurts!

No. Secrets are not printable. Secrets are end-to-end encrypted: when you submit a Secret, it is encrypted by your browser, using your Experience Public Key. It stays encrypted until your game server needs to use it. Your game server decrypts it with the Private Key, which is not available to the Creator Hub. That is why it is not possible to view Secret content in the Creator Hub.

Secrets Store API endpoints will support both OAuth, and API keys, as all OpenCloud APIs should.

Currently, Secrets are associated with Experiences, not Users or Groups. We consider implementing User and Group owned Secrets, but have no specific timeline.

This is out first priority, see the Next Steps list.

12 Likes

Is there a way to combine secrets for multiple games? Currently, I have two games that are under a group that use my internal API that need an API key.

Amazing! Can’t wait to see it.

6 Likes

How reliable is the “GetSecret” API? Should we prepare/expect for calls to fail?

10 Likes

This is totally great, for safety and convenience aside, this will certainly help a lot! Thank you very much for this feature

5 Likes

Firstly, thank you all for your work on this feature. We heavily make use of API keys in our games and look forward to using this soon. My original version of this message was more negative and I realized it better shortly after posting it, sorry about that.


What’s the reasoning for limiting to group owner until the permission is added? It should be okay to allow anyone with edit permissions for now, and then swap to the other permission when it’s in.

Also, how will this work for people who have access to creating OpenCloud keys for groups? Will I be able to bypass the secrets permission because I have this other permission?

Hopefully soon, unfortunately seems that it’s difficult to add more permissions as it is now. I appreciate more granular permissions, but don’t want it to feel like a constant minefield or arbitrary limitations such as group owner only.

7 Likes