Skip to content

Discord (OIDC)

This guide walks through running Carbon Panel with Discord as an OIDC identity provider. Discord supports OpenID Connect natively — no IdP container is needed.

  • Docker and Docker Compose
  • A Discord account
  1. Go to the Discord Developer Portal — Applications

  2. Click New Application, give it a name, and save

  3. In the left sidebar, click OAuth2

  4. Under Redirects, click Add Redirect and enter http://localhost:8080/api/v1/auth/oidc/callback

    • For production: use your public URL with HTTPS, e.g. https://panel.example.com/api/v1/auth/oidc/callback
  5. Copy the Client ID and Client Secret (click “Reset Secret” if you don’t have one yet)

Paste your Client ID and Client Secret into the compose file, then start the stack:

Terminal window
cd oidc/discord
docker compose up -d
oidc/discord/docker-compose.yaml
# SPDX-License-Identifier: MIT AND MPL-2.0
# This file includes DiscoPanel material under the MIT License,
# Copyright (c) 2025 Nicholas W. Heyer. The MIT license text is in LICENSE
# and still applies to that inherited material.
# Maintainer changes are licensed under the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain
# one at https://mozilla.org/MPL/2.0/.
# Carbon Panel + Discord (OIDC)
#
# This is a complete docker-compose with OIDC authentication pre-configured using Discord as the identity provider.
#
# Unlike Keycloak/Authelia examples, Discord is an external provider - no IdP container needed.
#
# PREREQUISITES:
# 1. Go to https://discord.com/developers/applications
# 2. Create or select an application
# 3. Go to "OAuth2" in the left sidebar
# 4. Copy the Client ID and Client Secret into the environment variables below
# 5. Under "Redirects", add: http://localhost:8080/api/v1/auth/oidc/callback
#
# RESTRICTING ACCESS:
# By default, anyone with a Discord account can log in.
# To restrict login to members of a specific Discord server, see the
# "Guild restriction" and "Role mapping" sections below.
services:
carbon-panel:
build:
context: ../../
dockerfile: docker/Dockerfile.carbon-panel
#image: athNdev/carbon-panel:dev
container_name: carbon-panel
restart: unless-stopped
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /tmp/carbon-panel:/app/data
environment:
- TZ=UTC
# ------------------------------------ AUTH CONFIG STARTS HERE FOR CARBON PANEL + DISCORD ------------------------------------
- CARBONPANEL_AUTH_LOCAL_ENABLED=true
- CARBONPANEL_AUTH_OIDC_ENABLED=true
# DISCORD OIDC ISSUER - DO NOT CHANGE
- CARBONPANEL_AUTH_OIDC_ISSUER_URI=https://discord.com
# PASTE YOUR DISCORD OAUTH CLIENT ID HERE (from Discord Developer Portal)
- CARBONPANEL_AUTH_OIDC_CLIENT_ID=REPLACE_ME
# PASTE YOUR DISCORD OAUTH CLIENT SECRET HERE (from Discord Developer Portal)
- CARBONPANEL_AUTH_OIDC_CLIENT_SECRET=REPLACE_ME
# Discord requires "openid", "identify", and "email" for basic OIDC login.
# Add "guilds" if you want to restrict access to a specific server (see below).
# Add "guilds.members.read" if you also want to map Discord server roles.
- CARBONPANEL_AUTH_OIDC_SCOPES=openid,identify,email
# THIS MUST MATCH EXACTLY WHAT YOU ENTERED IN DISCORD DEVELOPER PORTAL UNDER "Redirects"
# FOR PRODUCTION: change to your public domain (ie: https://mypanel.com/api/v1/auth/oidc/callback)
- CARBONPANEL_AUTH_OIDC_REDIRECT_URL=http://localhost:8080/api/v1/auth/oidc/callback
# Leave empty to skip automatic role mapping - users get default roles and can be promoted manually.
- CARBONPANEL_AUTH_OIDC_ROLE_CLAIM=
# ------------------------------------ GUILD RESTRICTION (OPTIONAL) ------------------------------------
#
# OPTION A: Restrict to members of a specific Discord server.
# 1. Add "guilds" to SCOPES above → openid,identify,email,guilds
# 2. Uncomment the lines below, replacing YOUR_GUILD_ID with your server's ID
# (enable Developer Mode in Discord, right-click the server → Copy Server ID)
#
# - CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_URL=https://discord.com/api/users/@me/guilds
# - CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_KEY=#.id
# - CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_NAME=guilds
# - CARBONPANEL_AUTH_OIDC_REQUIRED_CLAIM=guilds
# - CARBONPANEL_AUTH_OIDC_REQUIRED_VALUES=YOUR_GUILD_ID
#
# ------------------------------------ ROLE MAPPING (OPTIONAL) ------------------------------------
#
# OPTION B: Restrict to a guild AND map Discord server roles to Carbon Panel roles.
# 1. Add "guilds.members.read" to SCOPES above → openid,identify,email,guilds.members.read
# 2. Install your Discord application in the server (OAuth2 → URL Generator → select "bot" scope → invite)
# 3. Set EXTRA_CLAIMS_URL to the guild member endpoint with your server ID:
#
# - CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_URL=https://discord.com/api/users/@me/guilds/YOUR_GUILD_ID/member
# - CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_KEY=roles
# - CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_NAME=discord_roles
# - CARBONPANEL_AUTH_OIDC_ROLE_CLAIM=discord_roles
# - CARBONPANEL_AUTH_OIDC_ROLE_MAPPING={"DISCORD_ROLE_ID":"admin","OTHER_ROLE_ID":"moderator"}
# - CARBONPANEL_AUTH_OIDC_REJECT_UNMAPPED=true
#
# This also restricts access to guild members — non-members get a 403 from Discord's API.
# To find role IDs: Server Settings → Roles → right-click a role → Copy Role ID
Variable Purpose
CARBONPANEL_AUTH_OIDC_ENABLED Enables OIDC authentication
CARBONPANEL_AUTH_OIDC_ISSUER_URI Always https://discord.com — do not change
CARBONPANEL_AUTH_OIDC_CLIENT_ID Your Application ID from the Discord Developer Portal
CARBONPANEL_AUTH_OIDC_CLIENT_SECRET Your Client Secret from the Discord Developer Portal
CARBONPANEL_AUTH_OIDC_REDIRECT_URL The callback URL — must match exactly what you entered under Redirects
CARBONPANEL_AUTH_OIDC_SCOPES Must include openid, identify, and email. Add guilds or guilds.members.read for server restrictions

Discord’s OIDC tokens don’t include server membership data, but the access token can fetch it from Discord’s API. Carbon Panel supports this through the extra claims mechanism — a generic feature that fetches additional user data from a provider endpoint during login.

Add guilds to your scopes and configure the extra claims to pull guild membership:

- CARBONPANEL_AUTH_OIDC_SCOPES=openid,identify,email,guilds
- CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_URL=https://discord.com/api/users/@me/guilds
- CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_KEY=#.id
- CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_NAME=guilds
- CARBONPANEL_AUTH_OIDC_REQUIRED_CLAIM=guilds
- CARBONPANEL_AUTH_OIDC_REQUIRED_VALUES=YOUR_GUILD_ID

Replace YOUR_GUILD_ID with your Discord server’s ID. To find it: enable Developer Mode in Discord settings, then right-click the server name and select Copy Server ID.

EXTRA_CLAIMS_KEY is a gjson path — #.id extracts the id field from each object in the array. The result is stored as the guilds claim, and REQUIRED_CLAIM + REQUIRED_VALUES gate login on whether the guild ID is present.

Users who aren’t in the server will be turned away at login.

If you want login restricted to a server and want Discord roles to translate to Carbon Panel roles, use the guild member endpoint instead. This requires:

  1. Adding guilds.members.read to your scopes
  2. Installing your Discord application in the server (OAuth2 → URL Generator → select bot → use the invite link)
- CARBONPANEL_AUTH_OIDC_SCOPES=openid,identify,email,guilds.members.read
- CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_URL=https://discord.com/api/users/@me/guilds/YOUR_GUILD_ID/member
- CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_KEY=roles
- CARBONPANEL_AUTH_OIDC_EXTRA_CLAIMS_NAME=discord_roles
- CARBONPANEL_AUTH_OIDC_ROLE_CLAIM=discord_roles
- CARBONPANEL_AUTH_OIDC_ROLE_MAPPING={"DISCORD_ROLE_ID":"admin","OTHER_ROLE_ID":"moderator"}
- CARBONPANEL_AUTH_OIDC_REJECT_UNMAPPED=true

EXTRA_CLAIMS_KEY=roles pulls the roles array from the member response and stores it as the discord_roles claim. The role mapping then translates Discord role IDs to Carbon Panel roles. REJECT_UNMAPPED=true means users whose Discord roles don’t match any mapping entry are denied login.

Non-members are also rejected — Discord’s API returns a 403 for users who aren’t in the guild.

To find role IDs: go to Server Settings → Roles, right-click a role, and select Copy Role ID (requires Developer Mode).

Service URL Login
Carbon Panel http://localhost:8080 Log in via Discord
  • Update the redirect URI: change localhost:8080 to your public domain in both the compose file and the Discord Developer Portal
  • HTTPS: Discord allows http://localhost for development, but production deployments should use HTTPS
  • Disable local auth (optional): set CARBONPANEL_AUTH_LOCAL_ENABLED=false if you want OIDC-only login