Discord Social SDK
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Pages
Authentication

The SDK supports two ways of authenticating users:

  1. There is a standard OAuth2 flow to allow users to authenticate with an existing Discord account.
  2. For users that don't have Discord accounts, there is an authentication flow that allows users to authenticate using an external provider, and connect them to a limited Discord accounts, which we call "provisional accounts".

Also see Account Linking with Discord for a step-by-step guide on setting up account linking with Discord, and Using Provisional Accounts for a step-by-step guide on using provisional accounts with non-Discord authentication providers.

Existing Discord Account Authorization Flow

Desktop & Mobile Authorization

Discord supports the standard OAuth2 flow. You can find our full documentation on our developer portal. But our SDK also provides a few helper methods for you.

If you’re not familiar with OAuth2, some basic background: At a high level the goal of OAuth2 is to allow a user to connect two applications together and share data between them. In this case, allowing a game to access some of their Discord data.

The way this works is the application makes a request to Discord, which will prompt the user, on Discord, to authorize the connection. The user will see what functionality and data the app is requesting, and can approve that request. Once that is done, the user is redirected to a url configured by your application, and that redirect url contains a “code” in it. This code can be exchanged with the other party (in this case Discord), to get back two “tokens”. One of these is an “access token”, which lasts for about 7 days, and can be used to authenticate the user and take actions on their behalf. The other is a “refresh token”, which can be used to generate a new access token after it has expired.

We’ve made two tweaks to the “standard OAuth2” flow though that should help make the experience a lot better for players:

  1. If the user has the Discord client running and the game supports Discord’s overlay (on Windows only), then the OAuth2 modal will show up in game and most players won’t even need to leave your game.
  2. The SDK will handle the redirects transparently for you and the player (if you configure it). This means players that don’t have Overlay support won’t have to worry about a random Chrome tab being opened.

Using the overlay (Windows only)

The current version of Discord’s overlay is disabled by default, so that games don’t crash. For testing purposes, you can manually add your game and enable the overlay in your Discord Settings -> Games. 

Once you’re ready to launch, we’ll need to verify the overlay works well for your game and add it to a list of overlay-supported games, which will make it enabled by default for users. We’re also working on improvements to remove this requirement.

Also related to the overlay, if your game’s main window is not the same process as the one running the integration you may need to set the window PID using the discordpp::Client::SetGameWindowPid method.

To prevent CSRF attacks during auth, Discord attaches a state and checks it for you when performing the authorization. You can override state in the request arguments if you want for your own flow, but please be mindful to keep it a secure, random value.

Configure Redirects

As mentioned, the SDK will handle OAuth redirects for you. But for this to work, you will need to add http://127.0.0.1/callback (desktop) and discord-APP_ID:/authorize/callback (mobile; replace APP_ID with your Discord application id) as a redirect url to your Discord application in the developer portal. You can find that by opening your application on the Discord developer portal and clicking on the OAuth2 tab.

Using the SDK helper methods

The discordpp::Client::Authorize method is where you'll start. This will kick off the flow by reaching out to Discord, either through our app if it's running or a browser if not, and asking the player to authorize the request to connect. 

One of the required arguments to discordpp::Client::Authorize is scopes, which is the set of permissions that you are requesting. We recommend using discordpp::Client::GetDefaultCommunicationScopes or discordpp::Client::GetDefaultPresenceScopes depending on your use case, but you can choose whatever scopes you need.

After you’ve received approval from the player to access their account, you’ll receive a code back from our SDK. Depending on your desired destination for account credentials, you may wish to send this code to your backend for processing and storage on a player’s account.

If you don’t have a server, that’s cool too. You'll want to first enable Public Client on your Discord application's OAuth2 tab on the Discord developer portal. You can then leverage the discordpp::Client::GetToken method to exchange the code for a token using just the client. Codes from this flow can also be used with the account merging flow for provision accounts (explained in detail in a below section).

If you are using discordpp::Client::GetToken, keep in mind that you will be required to specify what is called a “code challenge” and “code verifier” in your requests. We’ll spare you the boring details of how that works (woo… crypto), as we’ve made a simple function to create these for you, discordpp::Client::CreateAuthorizationCodeVerifier.

Once you've received your token, you'll want to set the token in the SDK, you can use discordpp::Client::UpdateToken to do that. At this point, you're authorized and ready to go! You’ll also likely want to store the access token and refresh token for the player somewhere.

Please note that access_token values do expire. You’ll need to make use of the refresh_token to refresh the player’s token.

(Server to Server) Exchanging a code for an access token and refresh token

If you are not using the discordpp::Client::GetToken method, you'll need to exchange the code mentioned above with our server on your server. To do that, you'll want to make a request to our API's OAuth2 Token endpoint.

Access Token Exchange Example

import requests
API_ENDPOINT = 'https://discord.com/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
def exchange_code(code, redirect_uri):
data = {
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': redirect_uri
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()
return r.json()

Access Token Exchange Response

{
"access_token": "<access token>",
"token_type": "Bearer",
"expires_in": 604800,
"refresh_token": "<refresh token>",
"scope": "sdk.social_layer"
}

Console Authorization

Discord supports the standard OAuth2 device authorization flow.

If you’re not familiar with OAuth2, some basic background: At a high level the goal of OAuth2 is to allow a user to connect two applications together and share data between them. In this case, allowing a game to access some of their Discord data. The way this works is the application makes a request to Discord, which will prompt the user, on console, to scan a QR code or enter a code on Discord. The user will see what functionality and data the app is requesting, and can approve that request. Once that is done, the user is told to go back to the application, and the application will exchange a device code. This code can be exchanged with Discord to get back two “tokens”. One of these is an “access token”, which lasts for about 7 days, and can be used to authenticate the user and take actions on their behalf. The other is a “refresh token”, which can be used to generate a new access token after it has expired.

We’ve made two tweaks to the “standard OAuth2 device authorization” flow though that should help make the experience a lot better for players:

  1. The SDK will handle rendering overlay UI to players for authorization. This is done with using an embedded browser in-game.
  2. For public clients (clients without a server), the SDK will handle device code operations for you entirely and return an access token and refresh token.

Using the SDK helper methods

The quickest way to get started is to leverage the discordpp::Client::GetTokenFromDevice method, which will handle the entire process for you. You'll want to first enable Public Client on your Discord application's OAuth2 tab on the Discord developer portal. You can then leverage the discordpp::Client::GetTokenFromDevice method to exchange the code for a token using just the client.

If you have a server, you'll want to eventually leverage your server to make device + user codes, and then call discordpp::Client::OpenAuthorizeDeviceScreen followed by discordpp::Client::CloseAuthorizeDeviceScreen once authorization has finished.

Once you've received your token, you'll want to set the token in the SDK, you can use discordpp::Client::UpdateToken to do that. At this point, you're authorized and ready to go! You’ll also likely want to store the access token and refresh token for the player somewhere.

Please note that access_token values do expire. You’ll need to make use of the refresh_token to refresh the player’s token.

(Server to Server) Making device and user codes

If you are not using the discordpp::Client::GetTokenFromDevice method, you'll need to first obtain the device and user codes mentioned above with our server on your server. To do that, you'll want to make a request to our API's OAuth2 Device Authorization endpoint.

After obtaining these codes, you'll use them to perform device authorization.

First, you'll prompt the user for authorization by calling discordpp::Client::OpenAuthorizeDeviceScreen with the user_code returned. This will prompt them to scan a QR code or enter a code on a Discord website, which will have them login and authorize your game. You'll also need to start polling at interval and exchange the returned device_code with our OAuth2 token endpoint in the exchanging device code section.

Device Authorize Request Example

import requests
API_ENDPOINT = 'https://discord.com/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
SCOPE = 'sdk.social_layer'
def authorize_device():
data = {
'scope': SCOPE
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/device/authorize' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()
return r.json()

Device Authorize Request Response

{
"device_code": "<device code>",
"user_code": "<user code>",
"verification_uri": "https://discord.com/activate",
"verification_uri_complete": "https://discord.com/activate?user_code=<user code>",
"expires_in": 300,
"interval": 5
}

(Server to Server) Exchanging device code

If you are not using the discordpp::Client::GetTokenFromDevice method, you'll need to exchange device codes mentioned above with our server on your server after a user has approved the authorization from their device. To do that, you'll want to make a request to our API's OAuth2 Token endpoint.

You'll want to poll this endpoint every interval until the code expires after expires_in or succeeds. These values are obtained via the authorize request response above. If the code expires, you'll want to start over with a new authorization request or cancel/close the authorization.

Once you've received your token, you'll want to first close the authorize device screen with discordpp::Client::CloseAuthorizeDeviceScreen and then set the token in the SDK with discordpp::Client::UpdateToken. At this point, you're authorized and ready to go! You’ll also likely want to store the access token and refresh token for the player somewhere.

Please note that access_token values do expire. You’ll need to make use of the refresh_token to refresh the player’s token.

Access Token Exchange Example

import requests
API_ENDPOINT = 'https://discord.com/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
def exchange_device_code(device_code):
data = {
'grant_type': 'urn:ietf:params:oauth:grant-type:device_code',
'device_code': device_code
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()
return r.json()

Access Token Exchange Response

{
"access_token": "<access token>",
"token_type": "Bearer",
"expires_in": 604800,
"refresh_token": "<refresh token>",
"scope": "sdk.social_layer"
}

Provisional Account Authorization Flow

What Are Provisional Accounts?

Provisional accounts are a way for users that have not signed up for Discord to still access Discord functionality. They are "placeholder" Discord accounts that can be created for the user by the application created earlier. Provisional accounts exist so that your users can engage with Discord APIs and systems without the friction creating their own Discord account.

Instead of using Discord to authenticate these users, we instead rely on the game developer to act as the identity provider and generate an authorization token from that. As such, provisional accounts and their data are unique per Discord application.

Provisional accounts can be migrated or merged into "full" Discord accounts at a later time should the user choose to do that.

Some more miscellaneous details:

  • Provisional accounts are stable/persist for a given application and external identity.
  • Accounts are created for the provided identity if one doesn't currently exist.
  • Over the course of a game user's lifetime, they may link or unlink their Discord account. As such, the Discord account and provisional account associated with a game user may change over time. Keep this in mind when persisting any Discord/Provisional account IDs.
  • A provisional account can only be associated with a single external identity for your game.
  • A Discord account can only be associated with a single provisional account for your game at one time. If a user unlinks, a new provisional account is created for this user.

Application Setup

In order to use provisional accounts, you will need some additional configuration on the application created earlier. You’ll need to configure which identity provider you want to use to create provision accounts from. Currently, Discord supports OIDC, Steam session tickets, or EOS access/id tokens.

There is no way to configure this in the developer portal yet, so reach out to us with the following information when ready:

  • Discord Application ID
  • External Provider Type (OIDC, Steam, EOS)
    • We're also exploring other providers, so please reach out if you need something different!
  • For Steam:
    • Steam App ID
  • For EOS:
    • EOS Client ID
  • For OIDC:
    • Issuer - This is a URL
      • The provided issuer needs to have OIDC configuration available at <issuer_url>/.well-known/openid-configuration, as described in the OIDC specification
      • The configuration document should be well formed, particularly the following fields should be defined: issuer, authorization_endpoint, token_endpoint, jwks_uri, and id_token_signing_alg_values_supported
        • authorization_endpoint and token_endpoint aren’t actually used by Discord but are required by spec. If you want to put placeholder values here it wouldn’t harm your ability to use the provisional accounts feature. We may remove this requirement in the future.
        •  issuer, authorization_endpoint, token_endpoint, jwks_uri are all expected to be https urls (including placeholders). 
        • we only allow asymmetrical signing algorithms for the id token:
          • RS256, RS384, RS512, ES256, ES384, ES512, PS256, PS384, PS512
          • you must use signed id tokens, we don’t support unsigned ones
    • Audience - This is a string that represents your client identifier on the identity provider, it is used to validate the aud field in the JWT

Retrieving Provisional Account Tokens

Provisional accounts are authenticated via external credentials like OIDC ID tokens, Steam session tickets, or EOS access/id tokens. We're also exploring other providers, so please reach out if you need something different!

Using these credentials, we'll create a limited Discord just for your game and try to set the username for you according to the following:

  • For OIDC, a provisional account’s display name will be the value of the preferred_username claim, if specified in the ID token. This field is optional and should be between 1 and 32 characters. If not specified, the user’s display name will default to the user’s unique username, which is generated by Discord on creation. 
  • For Steam session tickets, the display name of the user’s Steam account is used as the provisional account’s display name.
  • For EOS Auth Access Tokens or ID Tokens, the name of the user’s Epic account is used as the provisional account’s display name. EOS Connect ID Tokens do not expose any username, and thus the game will need to configure the display name with discordpp::Client::UpdateProvisionalAccountDisplayName.

Using the SDK helper method

The quickest way to get started is to leverage the discordpp::Client::GetProvisionalToken method, which will handle the entire process for you. You'll want to first enable Public Client on your Discord application's OAuth2 tab on the Discord developer portal. You can then leverage the discordpp::Client::GetProvisionalToken method for a token using just the client.

If you have a server, you'll want to eventually leverage your server to exchange these external credentials for a provisional account token.

Once you've received your token, you'll want to set the token in the SDK, you can use discordpp::Client::UpdateToken to do that. At this point, you're authorized and ready to go! It is suggested that these provisional tokens are not stored, since they have short TTLs. Once expired you'll need to obtain a new one.

(Server to Server) Exchanging external credentials

If you are not using the discordpp::Client::GetProvisionalToken method, you'll need to make a request to our API's provisional account token endpoint.

External Auth Types

External Auth Type Value of the External Auth Token
OIDC OpenID Connect ID token.
STEAM_SESSION_TICKET A Steam auth ticket for web generated with discord as the identity.
EPIC_ONLINE_SERVICES_ACCESS_TOKEN Access token for Epic Online Services. Supports EOS Auth access tokens.
EPIC_ONLINE_SERVICES_ID_TOKEN ID token for Epic Online Services. Supports both EOS Auth + Connect ID tokens.

External Credentials Exchange Example

import requests
API_ENDPOINT = 'https://discord.com/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
EXTERNAL_AUTH_TYPE = 'OIDC'
def get_provisional_account_token(external_auth_token):
data = {
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'external_auth_type': EXTERNAL_AUTH_TYPE,
'external_auth_token': external_auth_token
}
r = requests.post('%s/partner-sdk/token' % API_ENDPOINT, json=data, headers=headers)
r.raise_for_status()
return r.json()

External Credentials Exchange Response

{
"access_token": "<access token>",
"id_token": "<id token>",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "<refresh token>", # only provided for OIDC when *not* a public client
"scope": "sdk.social_layer"
}

Possible errors

Error Code Description
530000 Your Discord application has not been granted the permission to use provisional accounts.
530001 The ID token JWT you have provided is expired. You will need to get another one issued from the identity provider.
530002 The issuer in the ID token JWT you have provided does not match what you have configured.
530003 The audience in the ID token JWT you have provided does not match the audience you specified in your OIDC configuration. Either update your configuration or pass in an ID token that was issued to your application.
530004 The ID token you provided was issued too long ago. Discord will not accept ID tokens issued beyond a week ago. You will need to get a new ID token issued from the identity provider.
530006 Discord failed to generate a unique username within the allotted time. This is not a terminal error, and should resolve itself upon a retry.
530007 Your client secret is invalid. Double check what you are sending or regenerate your client secret.

Refreshing Tokens

Using the SDK helper method

The quickest way to refresh tokens is to leverage the discordpp::Client::RefreshToken method, which will handle the entire process for you. You'll want to first enable Public Client on your Discord application's OAuth2 tab on the Discord developer portal. You can then leverage the discordpp::Client::RefreshToken method for a token using just the client.

If you have a server, you'll want to eventually leverage your server to exchange these external credentials for a provisional account token.

(Server to Server) Refreshing access tokens

If you are not using the discordpp::Client::RefreshToken method, you'll need to make a request to our API's token endpoint to refresh tokens.

Refresh Token Exchange Example

import requests
API_ENDPOINT = 'https://discord.com/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
def refresh_token(refresh_token):
data = {
'grant_type': 'refresh_token',
'refresh_token': refresh_token
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()
return r.json()

Refresh Token Exchange Response

{
"access_token": "<access token>",
"token_type": "Bearer",
"expires_in": 604800,
"refresh_token": "<refresh token>",
"scope": "sdk.social_layer"
}

Revoking Tokens

(Server to Server) Revoking access/refresh tokens

If you'd like to revoke access or refresh tokens for any reason (they were compromised, the user wishes to disconnect), you can send a request to the token revocation endpoint. If any valid access or refresh token is revoked, all of your game's access and refresh tokens for the user are immediately revoked.

Token Revocation Example

import requests
API_ENDPOINT = 'https://discord.com/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
def revoke_token(access_or_refresh_token):
data = {
'token': access_or_refresh_token
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/token/revoke' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()

Merging/Unmerging Provisional Accounts

Provisional accounts can be “upgraded” to full Discord accounts through a merge process, and provisional accounts can be “downgraded” from a full Discord account through an unmerge process. The following sections describe how to use these features.

Merging using the SDK helper methods

The quickest way to merge accounts is to leverage the discordpp::Client::GetTokenFromProvisionalMerge (Desktop & Mobile) or discordpp::Client::GetTokenFromDeviceProvisionalMerge (Console) method, which will handle the entire process for you. You'll want to first enable Public Client on your Discord application's OAuth2 tab on the Discord developer portal. You can then leverage the discordpp::Client::GetTokenFromProvisionalMerge or discordpp::Client::GetTokenFromDeviceProvisionalMerge method using just the client.

If you have a server, you'll want to eventually leverage your server for the merge operation.

(Server to Server) Merging using the API

If you are not using the discordpp::Client::GetTokenFromProvisionalMerge or discordpp::Client::GetTokenFromDeviceProvisionalMerge method, you'll need to make a request to our API's OAuth2 token endpoint from your server.

(Desktop & Mobile) Merge Request Example

import requests
API_ENDPOINT = 'https://discord.com/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
EXTERNAL_AUTH_TYPE = 'OIDC'
def exchange_code_with_merge(code, redirect_uri, external_auth_token):
data = {
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': redirect_uri,
'external_auth_type': EXTERNAL_AUTH_TYPE,
'external_auth_token': external_auth_token
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()
return r.json()

(Console) Merge Request Example

import requests
API_ENDPOINT = 'https://discord.com/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
EXTERNAL_AUTH_TYPE = 'OIDC'
def exchange_device_code_with_merge(device_code):
data = {
'grant_type': 'urn:ietf:params:oauth:grant-type:device_code',
'device_code': device_code,
'external_auth_type': EXTERNAL_AUTH_TYPE,
'external_auth_token': external_auth_token
}
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
r = requests.post('%s/oauth2/token' % API_ENDPOINT, data=data, headers=headers, auth=(CLIENT_ID, CLIENT_SECRET))
r.raise_for_status()
return r.json()

Merge Request Response

{
"access_token": "<access token>",
"token_type": "Bearer",
"expires_in": 604800,
"refresh_token": "<refresh token>",
"scope": "sdk.social_layer"
}

(Discord Users) Unmerging using the Discord app

A user can unmerge their account by removing access to your application on their Discord User Settings -> Authorized Apps page.

(Server to Server) Unmerging using the unmerge endpoint

A developer can unmerge a user's account by sending a request to the unmerge endpoint on our API.

Unmerge Request Example

import requests
API_ENDPOINT = 'https://discord.com/api/v10'
CLIENT_ID = '332269999912132097'
CLIENT_SECRET = '937it3ow87i4ery69876wqire'
EXTERNAL_AUTH_TYPE = 'OIDC'
def unmerge_provisional_account(external_auth_token):
data = {
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'external_auth_type': EXTERNAL_AUTH_TYPE,
'external_auth_token': external_auth_token
}
r = requests.post('%s/partner-sdk/provisional-accounts/unmerge' % API_ENDPOINT, json=data, headers=headers)
r.raise_for_status()

Associating Discord Accounts with External Identities

Discord provides the option to associate a game identity with a Discord account even if there is no existing provisional account. An example use case for this may be that you are using provisional accounts, but you want to present a “link with Discord” prompt before a provisional account has been created for that game identity and, as a result, enforce a uniqueness constraint on Discord accounts by external identity for your game.

To associate a Discord account with a game identity, you can leverage the merge provisional account operations listed above in lieu of normal authorization token exchange operations. Because there is no existing provisional account associated with the provided game identity, the merge operation is skipped.