How to Link Discord to FiveM and Use Roles for Permissions

Published on | Updated

Link Discord to FiveM with txAdmin's bot or Badger_Discord_API, then turn Discord roles into ace permissions with DiscordAcePerms, with every config line.

Two players standing between parked sports cars on a city street at night, with the Vinewood sign lit on the hill behind them

Your community lives in Discord, and you want the FiveM server to know who is who: only Discord members get in, the Staff role gets admin commands, the Police role can clock in. This guide shows how FiveM sees a player's Discord account, the bot you need, the resources that read roles, and the exact lines that turn a Discord role into an ace permission. Every setting comes from the resources' own docs and source code, checked on 4 November 2026.

Quick answer: FiveM links Discord on the player's side by itself: when the Discord desktop app runs on the same PC, the server sees a discord: identifier with the player's Discord user ID (the web app does not work). On the server you need a Discord bot in your Discord server. To let in only Discord members, or only members with certain roles, use txAdmin's built-in bot. To use Discord roles for permissions in FiveM, install Badger_Discord_API with your bot token and server ID, then DiscordAcePerms, and map each role ID to an ace group such as group.admin or qbcore.admin. For one fixed admin, one line in server.cfg is enough: add_principal identifier.discord:YOUR_ID group.admin.

How to Link Discord to FiveM as a Player

FiveM has no linking page for Discord. Every player who connects brings a list of identifiers, and the Cfx.re docs for GetPlayerIdentifiers list discord among them, next to license, fivem, steam and ip. The client picks it up from the Discord desktop app: txAdmin's own rejection message tells players to "open the Discord Desktop app and try again (the Web app won't work)."

When a player says your server cannot find their Discord, the fix is on their PC:

  1. Close FiveM completely.
  2. Start the Discord desktop app and sign in with the account that is in your Discord server.
  3. Start FiveM again and reconnect.

To see what the server receives, use txAdmin's /info Discord command, which can show admins a player's identifiers, or this test command in a server script:

-- server.lua in one of your own resources
RegisterCommand('discordid', function(source)
    if source == 0 then return end -- run it in game, not in the console
    local id = GetPlayerIdentifierByType(source, 'discord')
    print(('%s: %s'):format(GetPlayerName(source), id or 'no discord identifier'))
end, false)

The result looks like discord:123456789012345678. Everything below works with that number.

Create the Discord Bot and Copy Your IDs

Server-side integrations talk to Discord through a bot account. From Discord's getting started guide:

  1. In the Discord Developer Portal, click Create App, enter a name and press Create.
  2. On the Bot page, click Reset Token and copy the token. Discord shows it only once and warns never to share it or check it into version control.
  3. On the Installation page, under Guild Install, add the applications.commands and bot scopes and pick the bot's permissions. Open the Install Link in your browser and choose Add to server.
  4. In Discord's settings, turn on Developer Mode. Right-click your server icon and choose Copy ID: that is the server ID, which the resources call the guild ID. Roles and users get a Copy ID option too.

Three rules before you paste the token anywhere:

  • txAdmin's bot needs the Server Members intent. Switch it on at the Bot page under Privileged Gateway Intents, or txAdmin reports that the bot "does not have a required privileged intent." Badger's install guide names no intent; that resource reads one member at a time through Discord's REST API.
  • Use two bots for txAdmin and Badger_Discord_API. txAdmin's settings say "Do not reuse the same token for another bot", and txAdmin switches its bot off when it holds Administrator, Manage Roles, Kick Members, Ban Members or other moderator permissions.
  • Keep tokens in server-only files. Badger_Discord_API loads its config.lua as a server script. Files under client_script go into the packfile every player downloads, per the Cfx.re manifest docs.

Option 1: txAdmin's Discord Bot and Allowlist

txAdmin has a Discord bot built in (v8.1.2 was its latest GitHub release on 4 November 2026). It decides who may join; it does not turn roles into in-game permissions. In txAdmin, open Settings:

  1. Discord tab: switch Discord Bot to Enabled, paste the Token, fill in the Guild/Server ID and, optionally, a Warnings Channel ID. Save.
  2. Allowlist tab: pick the Allowlist Mode and write the Allowlist Instructions that rejected players see.
Allowlist ModeWho can join
DisabledEveryone who is not banned
Admin-only (maintenance mode)Players whose fivem: or discord: identifier is attached to a txAdmin admin
Discord Server MemberPlayers with a discord: identifier who are in your Discord server
Discord Server RolesMembers of your Discord server with at least one role from Allowlisted Discord Roles (role IDs, comma separated)
Approved LicensePlayers whose license: identifier an admin approved on the Allowlist page or with the /allowlist bot command
External Allowlist ResourceAnother resource you run decides

The two Discord modes stay disabled until the bot is enabled. The bot also adds slash commands to your Discord: /allowlist request approves a request ID such as R1234 from a player who was turned away in Approved License mode, /allowlist member adds a member to the approvals, /info looks a player up, and /status add posts a status embed that txAdmin updates every minute. Our txAdmin guide covers the rest of the panel. On our FiveM hosting txAdmin comes pre-installed, so this option only needs the bot token and your server ID.

Option 2: Badger_Discord_API for Role Checks in Your Scripts

Badger_Discord_API by JaredScar (Badger) reads Discord data for other scripts: a player's roles, name, nickname and avatar, and your server's role list. It can also add or remove roles and set nicknames. Its manifest says version 1.6, the repository was last changed in May 2024, and the README warns that some methods may not fully work, so test on a development server first.

  1. Download it from GitHub and put the folder in resources, named exactly Badger_Discord_API. A GitHub zip unpacks as Badger_Discord_API-main, and with that name the resource prints "This resource must be named Badger_Discord_API for it to work properly with other scripts".
  2. Fill in the Config block at the top of config.lua. Leave the Config.Splash block under it in place, because server.lua reads it when the resource starts:
Config = {
	Guild_ID = '123456789012345678', -- your Discord server ID
	Multiguild = false,
	Guilds = {
		["name"] = "guild_id",
	},
	Bot_Token = 'YOUR_BOT_TOKEN',
	RoleList = {},
	DebugScript = false,
	CacheDiscordRoles = true,
	CacheDiscordRolesTime = 60, -- seconds a player's roles stay cached
}
  1. Add ensure Badger_Discord_API to server.cfg, above every resource that uses it.

By default, Config.Splash shows every connecting player a welcome card for 10 seconds; set Enabled = false there to skip it.

RoleList is optional and gives role IDs a name, such as ['Admin'] = 597446815054430219. Write role IDs, not role names: the README notes that names break as soon as someone renames the role in Discord.

The exports are server-side. This check lets only players with your Police role go on duty:

-- server.lua of your own resource
local POLICE_ROLE = '123456789012345678' -- Copy ID on the role in Discord

local function hasDiscordRole(src, roleId)
    local roles = exports.Badger_Discord_API:GetDiscordRoles(src)
    if not roles then return false end -- no discord identifier, not in your Discord, or an API error
    for i = 1, #roles do
        if tostring(roles[i]) == roleId then return true end
    end
    return false
end

RegisterCommand('policeduty', function(source)
    if source == 0 then return end
    if hasDiscordRole(source, POLICE_ROLE) then
        print(GetPlayerName(source) .. ' may go on duty')
    else
        print(GetPlayerName(source) .. ' does not have the Police role')
    end
end, false)

Roles stay cached for CacheDiscordRolesTime seconds (60 by default), so a role you give in Discord reaches the server within about a minute. Giving roles from the game (AddRole, RemoveRole, SetRoles) needs Manage Roles on the bot, per Discord's Modify Guild Member docs, and the README says these calls return error 403 when the member ranks above the bot, so drag the bot's role above the roles it changes.

Discord Roles for Permissions in FiveM: Map Roles to Ace Groups

FiveM permissions are aces. In the Cfx.re server commands, add_ace gives a principal a permission and add_principal makes one principal inherit from another. A Discord account is a principal too: identifier.discord: plus the user ID. For one fixed person you need nothing else:

# server.cfg
add_ace group.admin command allow
add_principal identifier.discord:123456789012345678 group.admin

For whole roles, use DiscordAcePerms by the same author. When a player connects it reads their roles through Badger_Discord_API and runs add_principal identifier.discord:<id> <group> for each role in your list. When they leave, it removes those entries.

  1. Install Badger_Discord_API first, as above.
  2. Put the folder in resources and name it exactly DiscordAcePerms (a GitHub zip unpacks as DiscordAcePerms-master), because the add_ace lines below use that resource name.
  3. Add these lines to server.cfg. The two add_ace lines come from Badger's install steps; without them the resource cannot grant anything.
add_ace resource.DiscordAcePerms command.add_principal allow
add_ace resource.DiscordAcePerms command.remove_principal allow

ensure Badger_Discord_API
ensure DiscordAcePerms
  1. In DiscordAcePerms' config.lua, set Server_Name, Discord_Link and Website_Link (it points to badger.store by default), then fill roleList with pairs of a Discord role ID and an ace group.

The group names depend on your framework:

FrameworkGroups to map Discord roles toDefined in
QBCoreqbcore.mod, qbcore.admin, qbcore.godQBCore's txAdmin recipe server.cfg and QBCore.Config.Server.Permissions
Qboxgroup.support, group.mod, group.adminpermissions.cfg in Qbox's txAdmin recipe
Standalone or vMenuYour own group.<name> entriesYour add_ace lines in server.cfg

For QBCore, the mapping looks like this:

-- DiscordAcePerms/config.lua, inside Config
roleList = {
    {123456789012345678, "qbcore.mod"},   -- Moderator role
    {234567890123456789, "qbcore.admin"}, -- Admin role
    {345678901234567890, "qbcore.god"},   -- Owner role
},

This works because qb-core creates an ace for each level when it starts (add_ace qbcore.admin admin allow), and its HasPermission function asks IsPlayerAceAllowed(source, 'admin'). Still choosing a framework? Our ESX vs QBCore vs Qbox comparison sets them side by side.

ESX Legacy keeps each player's group in its own database and adds the matching group.<name> principal for the player's license when a character loads. A Discord role mapped through DiscordAcePerms adds ace rights next to that, but scripts that read the ESX group still see the value stored in ESX.

To check the setup, join the server. With Print_Perm_Grants_And_Removals = true (the default), the console prints a line such as [DiscordAcePerms] (playerConnecting) Added <name> to role group qbcore.admin. The resource prints that line just before it runs add_principal, so it also appears when the command is refused. To confirm the grant, while that player is online, test_ace identifier.discord:234567890123456789 admin in the server console should come back as allowed.

Permissions are set when a player connects. After a role change, the player can type /refreshPerms (on by default, once per 10 minutes through Refresh_Throttle = 600) or reconnect. If DiscordAcePerms cannot read someone's roles, for example because they never joined your Discord, it shows a card with a link to your Discord and a Play button. They can still play, just without the mapped permissions, so add txAdmin's Discord Server Member mode if membership must be required.

Send Server Logs to a Discord Channel

Logs need no bot. As Discord's help article describes it, open Server Settings, go to Integrations, click Create Webhook, pick the log channel and press Copy Webhook URL. Post to that URL from a server script. Discord's Execute Webhook endpoint takes content of up to 2000 characters, an optional username and up to 10 embeds. The token is part of the URL, so anyone with the URL can post in that channel: keep it server-side.

-- server.lua (never in a client script)
local WEBHOOK = 'https://discord.com/api/webhooks/WEBHOOK_ID/WEBHOOK_TOKEN'

local function sendLog(message)
    PerformHttpRequest(WEBHOOK, function(status)
        if status ~= 200 and status ~= 204 then
            print(('Discord webhook failed with status %s'):format(status))
        end
    end, 'POST', json.encode({ username = 'Server logs', content = message:sub(1, 2000) }),
    { ['Content-Type'] = 'application/json' })
end

AddEventHandler('playerDropped', function(reason)
    sendLog(('%s left the server: %s'):format(GetPlayerName(source), reason))
end)

A busy log channel gets hard to search. Fivemanage keeps the same kind of events in a dashboard you can filter by player, event or time, and our Fivemanage guide shows how to set it up.

Troubleshooting

What you seeLikely causeFix
Badger_Discord_API error 401, "Your Discord Token is probably wrong"Token mistyped or reset in the portalPaste the current token into Bot_Token and restart the resource
Error 403 on AddRole or SetNicknameThe member's role is above the bot's roleMove the bot's role higher in Server Settings, Roles
"This resource must be named Badger_Discord_API"Folder still called Badger_Discord_API-mainRename the folder and update ensure
No "Added ... to role group" line in the consoleBadger_Discord_API cannot read the player's roles, a role ID in roleList is wrong, or DiscordAcePerms starts before Badger_Discord_APICheck the console for Badger_Discord_API errors, copy the role IDs again and ensure Badger_Discord_API first
The "Added" line shows, but test_ace says deniedThe two add_ace resource.DiscordAcePerms lines are missing, so the server refuses its add_principal commandAdd both lines to server.cfg and restart the server
txAdmin: "for your safety the bot has been disabled"The txAdmin bot holds Administrator, Manage Roles or another moderator permissionRemove those permissions, and use a second bot for role changes

FAQ

How do I link Discord to FiveM? As a player you do nothing in FiveM itself. Open the Discord desktop app and sign in before you start FiveM, and servers receive your Discord user ID as a discord: identifier. Discord in a browser does not count. If a server still cannot find you, close FiveM, restart Discord and check you use the account that joined the server's Discord.

How do I use Discord roles for permissions in FiveM? Install Badger_Discord_API with your bot token and server ID, then DiscordAcePerms. In its roleList, pair each Discord role ID with an ace group, such as qbcore.admin on QBCore or group.admin on Qbox, and add the two add_ace resource.DiscordAcePerms lines to server.cfg.

Can txAdmin and Badger_Discord_API share one bot? No. txAdmin says not to reuse its token for another bot, and it disables its bot when the bot has Manage Roles, which Badger needs for adding roles. Create a second application in the Developer Portal.

Do role changes in Discord apply while a player is online? txAdmin checks membership and roles when a player joins. DiscordAcePerms also sets permissions on join; after a change the player can use /refreshPerms once every 10 minutes, or reconnect.

Do I need separate hosting for these Discord bots? No. txAdmin's bot runs inside txAdmin, and Badger_Discord_API talks to Discord from the FiveM server. Only a bot you write yourself, such as a ticket bot, runs as its own process; our Discord bot hosting runs Node.js, Python and Java bots.

Sources

All opened on 4 November 2026: