FiveM API Keys and Secrets
FiveM resources may need external credentials such as a Steam Web API key, Discord bot token, webhook URL, or vendor API key. Keep these values on the server, load them through the method supported by the resource, and never send them to a client script.
Looking for the key required to start FXServer? Use the separate FiveM license key setup. This page covers optional integration credentials only.
Choose where to store a secret
Use this order of preference:
- A secrets manager or protected environment file supported by the service.
- A server-only resource configuration excluded from Git.
- A non-replicated convar loaded from a protected
secrets.cfg.
Do not use setr or sets for secrets. Replicated and server-info convars are
not private storage.
Protected secrets.cfg
If a resource reads its credentials with GetConvar, keep secret values in a
separate file:
# server.cfg
exec secrets.cfg# secrets.cfg — never commit this file
set steam_webApiKey "replace-with-steam-web-api-key"
set myresource_discordToken "replace-with-discord-bot-token"Protect the file on Linux:
sudo chown fivem:fivem /opt/fivem/server-data/secrets.cfg
sudo chmod 600 /opt/fivem/server-data/secrets.cfgIgnore local secret files:
server.cfg
secrets.cfg
.env
.env.*
*.key
*.tokenA standard convar can still be read by server resources. Give untrusted resources no access to a server that holds valuable credentials.
Steam Web API key
Some resources use a Steam Web API key to query Steam profiles or work with Steam identifiers.
Create the key
- Open the Steam Web API key page .
- Sign in with the Steam account that will own the key.
- Register the domain requested by Steam.
- Store the key in your secrets manager or protected config.
Configure FiveM
The standard server convar is:
set steam_webApiKey "replace-with-steam-web-api-key"Only configure it when a resource or authentication flow actually needs it. A Steam API key does not replace the Cfx.re registration key.
Read it from a server script
local steamApiKey = GetConvar('steam_webApiKey', '')
if steamApiKey == '' then
print('Steam Web API integration is disabled: key not configured')
return
endNever include the key in an HTTP URL that you log. Redact request URLs and headers before writing integration errors.
Discord bot tokens
A Discord bot token authenticates an application as a bot. It is not the same as a Discord application ID, guild ID, role ID, or webhook URL.
Create and authorize a bot
- Open the Discord Developer Portal .
- Create or select an application.
- Open Bot and generate the token.
- Enable only the privileged intents the integration requires.
- Use the OAuth2 installation flow to grant the minimum required permissions.
- Store the token immediately; do not paste it into
server.cfgunless the resource specifically documents a protected convar.
Resource configuration
Different resources load Discord credentials differently. Follow the resource’s current documentation and keep its server-only config out of Git:
-- server/config.lua — load on the server only
return {
token = GetConvar('myresource_discordToken', ''),
guildId = 'replace-with-guild-id'
}Do not add this file to shared_scripts or client_scripts. Client-delivered
resource files are not secret.
Discord webhooks
A webhook URL is also a credential: anyone with the URL can normally post to that webhook.
local webhookUrl = GetConvar('myresource_discordWebhook', '')
local function sendWebhook(payload)
if webhookUrl == '' then
return
end
PerformHttpRequest(webhookUrl, function(statusCode)
if statusCode < 200 or statusCode >= 300 then
print(('Discord webhook failed with HTTP %s'):format(statusCode))
end
end, 'POST', json.encode(payload), {
['Content-Type'] = 'application/json'
})
endDo not log webhookUrl, request headers, or complete failed request objects.
Validate configuration without exposing it
Check whether required values exist:
local requiredConvars = {
'steam_webApiKey',
'myresource_discordToken'
}
for _, name in ipairs(requiredConvars) do
local isConfigured = GetConvar(name, '') ~= ''
print(('%s configured: %s'):format(name, isConfigured))
endThis reports presence only. Avoid printing lengths, prefixes, suffixes, or masked fragments that make secrets easier to reconstruct.
Rotate a compromised credential
- Revoke or reset the credential in its provider dashboard.
- Store the replacement in the protected configuration.
- Restart only the services or resources that need to reload it.
- Test the integration without logging the new value.
- Search Git history, deployment logs, tickets, and chat for the exposed value.
- Remove retained copies where possible.
Rotate credentials when they are exposed, when access ownership changes, or when the provider’s policy requires it. Arbitrary rotation without a tested rollover process can cause avoidable outages.
Common failures
The value is empty in GetConvar
- Confirm
exec secrets.cfgruns before the resource starts. - Confirm the convar name and capitalization match.
- Confirm txAdmin is loading the expected profile and
server.cfg. - Confirm the secret file is readable by the FXServer service account.
Discord returns 401 Unauthorized
The bot token is invalid, revoked, or loaded incorrectly. Reset it in the Discord Developer Portal and update the protected configuration.
Discord returns 403 Forbidden
The token is valid, but the bot or webhook lacks permission for the requested action or channel. Adjust the specific permission instead of granting administrator access.
Steam integration fails
Confirm the Steam key is active, the request uses the expected Steam identifier format, and Steam’s API is reachable. Do not assume every FiveM player exposes a Steam identifier.