5.3 KiB
title |
---|
Discord |
Support level: authentik
Allows users to authenticate using their Discord credentials
Preparation
The following placeholders will be used:
authentik.company
is the FQDN of the authentik install.
Discord
- Create an application in the Discord Developer Portal (This is Free) https://discord.com/developers/applications
- Name the Application
-
Select OAuth2 from the left Menu
-
Copy the Client ID and save it for later
-
Click to Reveal the Client Secret and save it for later
-
Click Add Redirect and add https://authentik.company/source/oauth/callback/discord/
Here is an example of a completed OAuth2 screen for Discord.
authentik
-
Under Directory -> Federation & Social login Click Create Discord OAuth Source
-
Name: Choose a name (For the example I used Discord)
-
Slug: discord (You can choose a different slug, if you do you will need to update the Discord redirect URLand point it to the correct slug.)
-
Consumer Key: Client ID from step 4
-
Consumer Secret: Client Secret from step 5
Here is an example of a complete authentik Discord OAuth Source
Save, and you now have Discord as a source.
:::note For more details on how-to have the new source display on the Login Page see here. :::
Checking for membership of a Discord Guild
:::info
Ensure that the Discord OAuth source in 'Federation & Social login' has the additional guilds
scope added under the 'Protocol settings'.
:::
Create a new 'Expression Policy' with the content below, adjusting the variables where required:
# To get the guild ID number for the parameters, open Discord, go to Settings > Advanced and enable developer mode.
# Right-click on the server/guild title and select "Copy ID" to get the guild ID.
ACCEPTED_GUILD_ID = "123456789123456789"
GUILD_NAME_STRING = "The desired server/guild name in the error message."
# Only change below here if you know what you are doing.
# Ensure flow is only run during OAuth logins via Discord
if context['source'].provider_type != "discord":
return True
# Get the user-source connection object from the context, and get the access token
connection = context.get("goauthentik.io/sources/connection")
if not connection:
return False
access_token = connection.access_token
guilds = requests.get(
"https://discord.com/api/users/@me/guilds",
headers= {
"Authorization": f"Bearer {access_token}",
}
).json()
user_matched = any(ACCEPTED_GUILD_ID == g["id"] for g in guilds)
if not user_matched:
ak_message(f"User is not a member of {GUILD_NAME_STRING}.")
return user_matched
Now bind this policy to the chosen enrollment and authentication flows for the Discord OAuth source.
Checking for membership of a Discord Guild role
:::info
Ensure that the Discord OAuth source in 'Federation & Social login' has the additional guilds guilds.members.read
scopes added under the 'Protocol settings'.
:::
Create a new 'Expression Policy' with the content below, adjusting the variables where required:
# To get the role and guild ID numbers for the parameters, open Discord, go to Settings > Advanced and
# enable developer mode.
# Right-click on the server/guild title and select "Copy ID" to get the guild ID.
# Right-click on the server/guild title and select server settings > roles, right click on the role and click
# "Copy ID" to get the role ID.
ACCEPTED_ROLE_ID = "123456789123456789"
ACCEPTED_GUILD_ID = "123456789123456789"
GUILD_NAME_STRING = "The desired server/guild name in the error message."
ROLE_NAME_STRING = "The desired role name in the error message."
# Only change below here if you know what you are doing.
GUILD_API_URL = f"https://discord.com/api/users/@me/guilds/{ACCEPTED_GUILD_ID}/member"
# Ensure flow is only run during OAuth logins via Discord
if context['source'].provider_type != "discord":
return True
# Get the user-source connection object from the context, and get the access token
connection = context.get("goauthentik.io/sources/connection")
if not connection:
return False
access_token = connection.access_token
guild_member_object = requests.get(
GUILD_API_URL,
headers= {
"Authorization": f"Bearer {access_token}",
}
).json()
# The response for JSON errors is held within guild_member_object['code']
# See: https://discord.com/developers/docs/topics/opcodes-and-status-codes#json
# If the user isn't in the queried guild, it gives the somewhat misleading code = 10004.
if "code" in guild_member_object:
if guild_member_object['code'] == 10004:
ak_message(f"User is not a member of {GUILD_NAME_STRING}.")
else:
ak_create_event("discord_error", source=context['source'], code= guild_member_object['code']})
ak_message("Discord API error, try again later.")
# Policy does not match if there is any error.
return False
user_matched = any(ACCEPTED_ROLE_ID == g for g in guild_member_object["roles"])
if not user_matched:
ak_message(f"User is not a member of the {ROLE_NAME_STRING} role in {GUILD_NAME_STRING}.")
return user_matched
Now bind this policy to the chosen enrollment and authentication flows for the Discord OAuth source.