Authorization
A large number of Dead by Daylight's private API endpoints require authentication with a valid Dead by Daylight account. Access is secured through token-based authentication, ensuring that only authorized users can retrieve the requested resources.
OAuth 2.0
Epic Online Services (EOS) uses the OAuth 2.0 protocol for authentication and authorization, supporting common-use cases for web servers and client-side applications. Epic has also introduced custom grant types for some specific use cases. You can learn more about this process here.
OAuth Server Endpoints
Endpoint for exchanging an authorization code for an access token. consumingClientId
refers to the client application making the request, codeChallenge
is the value derived from the code verifier (a cryptographically random string generated by the client), and codeChallengeMethod
specifies the method used to create the codeChallenge
. EOS employs the SHA-256 hashing algorithm to secure the code challenge in the Proof Key for Code Exchange (PKCE) flow.
Endpoint for obtaining an access token, refresh token, and other identity information after successfully exchanging an authorization code.
Endpoint for obtaining detailed information about a given access token. When a client provides a valid access token, the endpoint responds with metadata associated with it.
Endpoint that enables clients to implement a "log out" feature by invalidating tokens, ensuring that any associated security credentials or access rights are revoked. This endpoint implements RFC 7009 - OAuth 2.0 Token Revocation.
Errors
The endpoints listed above return error messages in accordance with the relevant RFC specifications.
Client Types
OAuth categorizes clients into two types: confidential clients and public clients.
Confidential Clients
Confidential clients are applications that can securely authenticate with the authorization server, such as those capable of keeping their registered client secret safe.
The client ID is a public identifier for applications registered with an OAuth 2.0 authorization server. It must be unique across all clients managed by the server to ensure requests are correctly attributed to the appropriate application.
The client secret is a confidential credential known only to the application and the authorization server. It functions as the application's password, ensuring secure communication between the application and the server.
These clients are able to use the authorization_code
, client_credentials
, exchange_code
, password
, and refresh_token
grant types.
Confidential clients can have ID tokens issued to them either symmetrically using their client secret (HS256) or asymmetrically using a private key (RS256), as they are capable of securely storing secrets.
Public Clients
Public clients, like applications running in a browser or on a mobile device, cannot securely store client secrets because these environments are not secure enough to protect them.
These clients can only use grant types that do not require a client secret, as they cannot securely store or protect the confidentiality of such credentials.
Since public clients cannot securely store secrets, ID tokens issued to them must be signed asymmetrically using a private key (RS256) and verified with the corresponding public key.
Tokens
When attempting to play Dead by Daylight, the client interacts with Epic Games' OAuth 2.0 authentication system to obtain access tokens, refresh tokens, and ID tokens.
Access Token
An access token is issued by the authorization server to grant the client access to protected resources on behalf of the user. This token is valid for 2 hours from the time of issuance.
Refresh Token
A refresh token is used to obtain a new access token without requiring the user to re-authenticate. This token remains valid for 8 hours from the time of issuance.
ID Token
An ID token is part of the OpenID Connect protocol, which provides a standardized method to authenticate and retrieve basic user information. It is used to verify the user's identity and contains user details in the form of claims (e.g., Epic Account ID, Epic Account display name, client ID used to authenticate the user with Epic Account Services, and other identity-related information). This token remains valid for 2 hours from the time it is issued.
Available Scopes
When the client attempts to connect to Dead by Daylight's servers, it requests specific scopes as part of the OAuth 2.0 authorization flow. The scope basic_profile friends_list openid presence
specifies the resources and permissions the client needs to access:
basic_profile
access allows the client to authenticate the user with Epic Account Services, retrieve information such as the user's screen name, and facilitate in-application purchases.friends_list
access allows the client to retrieve an Epic Account's friends list.openid
access allows the client to request an ID token.presence
access allows the client to retrieve an Epic Account's presence information, which details a user's current activity. This includes both basic status and game-specific status. Basic status provides general details, such as whether the user is online or offline and what game they are playing (if they have chosen to share this information). Game-specific status includes details unique to the game the user is playing.Grant Types
Authorization Code Grant
This grant allows both confidential and public clients to exchange an authorization code for an access token. After the user is redirected back to the client via the specified redirect URL, the application extracts the authorization code from the URL and uses it to request an access token. You can learn more this flow here.
Authentication using this method is only possible for clients that have a configured redirect URL. Since the Dead by Daylight client does not have a redirect URL, I will use fortnitePCGameClient
to illustrate this process. Notably, jaren.wtf's unofficial Epic Games Client Documentation states that fortnitePCGameClient
's client ID is ec684b8c687f479fadea3cb2ad83f5c6
, and its client secret is e1f31c211f28413186262d37a13fc84d
.
Method
1. Identify the client for which you need to obtain an access token.
2. Make sure you are logged into your Epic Games account.
3. Open https://www.epicgames.com/id/api/redirect?clientId=:clientId&responseType=code in your web browser, replacing :clientId
with the chosen client ID. In this case, use ec684b8c687f479fadea3cb2ad83f5c6
.
4. If the request is successful, then you will receive a response with the following structure:
{
"redirectUrl": string,
"authorizationCode": string,
"exchangeCode": null,
"sid": null,
"ssoV2Enabled": boolean
}
Key | Type | Description |
---|---|---|
redirectUrl |
String | The URL to which the user will be redirected after authentication. This URL contains the authorization code as a query parameter, which the client can later use to exchange for an access token. |
authorizationCode |
String | A temporary authorization code issued after the user successfully logs in. This code is used in the next step to request an access token from the authorization server. |
exchangeCode |
String (can be null) | A code used to exchange for an access token in specific OAuth flows. This field is null if the exchange code hasn't been issued yet or isn't required for the current flow. |
sid |
String (can be null) | Represents the session ID (SID) for the user's authentication session. It is null if not applicable or has not yet been assigned during the process. |
ssoV2Enabled |
Boolean | Indicates whether Single Sign-On (SSO) version 2 is enabled for this authentication flow. If true, then the system supports SSOv2, allowing the user to authenticate across multiple services without the need to re-enter credentials. |
Note that the authorization code expires after 5 minutes. If step 5 is not completed within 5 minutes of completing step 3, then a new authorization code will need to be generated.
5. Send a POST
request to https://account-public-service-prod.ol.epicgames.com/account/api/oauth/token:
Request Headers:
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {client_id:client_secret}
Note that the client_id:client_secret
pair needs to be encoded in Base64.
Request Body:
grant_type=authorization_code&code={authorizationCode}
Note that authorizationCode
is obtained from the response in step 4.
Example: Authenticating to fortnitePCGameClient
Request Headers:
Content-Type: application/x-www-form-urlencoded
Authorization: Basic ZWM2ODRiOGM2ODdmNDc5ZmFkZWEzY2IyYWQ4M2Y1YzY6ZTFmMzFjMjExZjI4NDEzMTg2MjYyZDM3YTEzZmM4NGQ=
Request Body:
grant_type=authorization_code&code={authorizationCode}
If the request is successful, then the response will have the following structure:
{
"access_token": string,
"expires_in": 7200,
"expires_at": string,
"token_type": "bearer",
"refresh_token": string,
"refresh_expires": 28800,
"refresh_expires_at": string,
"account_id": string,
"client_id": "ec684b8c687f479fadea3cb2ad83f5c6",
"internal_client": true,
"client_service": "prod-fn",
"scope": [
"basic_profile"
],
"displayName": string,
"app": "prod-fn",
"in_app_id": string,
"device_id": string,
"product_id": "prod-fn",
"application_id": string,
"acr": "urn:epic:loa:aal2",
"auth_time": string
}
Key | Type | Description |
---|---|---|
access_token |
String | The OAuth 2.0 access token, which grants temporary access to the application's protected resources. |
expires_in |
Number | The duration (in seconds) until the access token expires. |
expires_at |
String | The expiration timestamp of the access token, formatted in ISO 8601. |
token_type |
String | Indicates the type of token issued. |
refresh_token |
String | The token that can be used to request a new access token after the current one expires. |
refresh_expires |
Number | The duration (in seconds) before the token used to obtain a new access token expires. |
refresh_expires_at |
String | The expiration timestamp of the refresh token, formatted in ISO 8601. |
account_id |
String | The unique identifier for the user's account within Epic Games services. |
client_id |
String | The unique identifier of the client making the request, typically representing the application. |
internal_client |
Boolean | Indicates whether the client is part of Epic's internal systems. |
client_service |
String | The service associated with the client. |
scope |
Array | The permissions granted by the token, specifying the resources the client can access. |
displayName |
String | The user's display name associated with the account. |
app |
String | The application that is requesting the token. |
in_app_id |
String | The unique ID assigned to the user within the application. |
device_id |
String | The unique identifier of the device making the request. |
product_id |
String | The unique identifier of the product linked to the token. |
application_id |
String | The unique identifier of the application requesting the token. This may differ from client_id when multiple applications share the same client. |
acr |
String | The level of security or strength of the authentication method used. |
auth_time |
String | The timestamp, representing the moment when authentication took place, formatted in ISO 8601. |
Client Credentials Grant
This grant allows clients to obtain an access token without user context. It is used for accessing client-specific resources rather than user-related data. You can learn about its flow here.
Method
1. Identify the client for which you need to obtain an access token.
2. Send a POST
request to https://api.epicgames.dev/auth/v1/oauth/token:
Request Headers:
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {client_id:client_secret}
Note that the client_id:client_secret
pair needs to be encoded in Base64.
Request Body:
grant_type=client_credentials
Example: Authenticating to the Dead by Daylight Client
You can retrieve the Dead by Daylight client's ID and secret by monitoring its network traffic when launching the game through the Epic Games Launcher. Specifically, the "Authorization" request header in any requests sent to https://api.epicgames.dev/auth/v1/oauth/token or https://api.epicgames.dev/epic/oauth/v2/token will contain the value Basic eHl6YTc4OTFzSGQ4NDdVeEI0cG54WjMwT2hRRXFNZXQ6SXdYNEg4bmRDbmE0R1RpRDhMVFkyT3hqSDJncG5uYkt6cTRCaHFkL250RQ==
. You can use this website to decode the Base64-encoded text. In this case, decoding eHl6YTc4OTFzSGQ4NDdVeEI0cG54WjMwT2hRRXFNZXQ6SXdYNEg4bmRDbmE0R1RpRDhMVFkyT3hqSDJncG5uYkt6cTRCaHFkL250RQ==
reveals xyza7891sHd847UxB4pnxZ30OhQEqMet:IwX4H8ndCna4GTiD8LTY2OxjH2gpnnbKzq4Bhqd/ntE
, where xyza7891sHd847UxB4pnxZ30OhQEqMet
is the client ID and IwX4H8ndCna4GTiD8LTY2OxjH2gpnnbKzq4Bhqd/ntE
is the client secret.
Request Headers:
Content-Type: application/x-www-form-urlencoded
Authorization: Basic eHl6YTc4OTFzSGQ4NDdVeEI0cG54WjMwT2hRRXFNZXQ6SXdYNEg4bmRDbmE0R1RpRDhMVFkyT3hqSDJncG5uYkt6cTRCaHFkL250RQ==
Request Body:
grant_type=client_credentials
If the request is successful, then the response will have the following structure:
{
"access_token": string,
"token_type": "bearer",
"expires_at": string,
"features": [
"Achievements",
"AntiCheat",
"Ecom",
"Matchmaking",
"Metrics",
"Sanctions",
"Stats"
],
"organization_id": "o-2ctdycbd3jxm6a26vpz5d4xv872smu",
"product_id": "2b2299be8ae84d679d4dc57c55af1510",
"expires_in": 3599
}
Key | Type | Description |
---|---|---|
access_token |
String | The OAuth 2.0 access token, which grants temporary access to the application's protected resources. |
token_type |
String | Indicates the type of token issued. |
expires_at |
String | The expiration timestamp of the access token, formatted in ISO 8601. |
features |
Array | A list of features that are enabled for the access token. |
organization_id |
String | A unique identifier for the organization linked to the token. |
product_id |
String | The unique identifier of the product linked to the token. |
expires_in |
Number | The duration (in seconds) until the access token expires. |
Exchange Code Grant
This grant allows clients to exchange a short-lived authorization code for an access token. Since Epic has removed the endpoint that previously allowed obtaining an exchange code through a browser, the only way to acquire one now is by launching the selected game via the Epic Games Launcher. However, you can still retrieve the access token by capturing the game's network traffic as it launches. Specifically, by inspecting the request sent to https://api.epicgames.dev/epic/oauth/v2/token after launching the game, you will find a response structured as follows:
{
"scope": string,
"token_type": string,
"access_token": string,
"refresh_token": string,
"id_token": string,
"expires_in": number,
"expires_at": string,
"refresh_expires_in": number,
"refresh_expires_at": string,
"account_id": string,
"client_id": string,
"application_id": string,
"selected_account_id": string,
"merged_accounts": [],
"acr": string,
"auth_time": string
}
Key | Type | Description |
---|---|---|
scope |
String | The permissions granted by the token, specifying the resources the client can access. |
token_type |
String | Indicates the type of token issued. |
access_token |
String | The OAuth 2.0 access token, which grants temporary access to the application's protected resources. |
refresh_token |
String | The token that can be used to request a new access token after the current one expires. |
id_token |
String | A token that contains user-related information in the form of claims. |
expires_in |
Number | The duration (in seconds) until the access token expires. |
expires_at |
String | The expiration timestamp of the access token, formatted in ISO 8601. |
refresh_expires_in |
Number | The duration (in seconds) before the token used to obtain a new access token expires. |
refresh_expires_at |
String | The expiration timestamp of the refresh token, formatted in ISO 8601. |
account_id |
String | The unique identifier for the user's account within Epic Games services. |
client_id |
String | The unique identifier of the client making the request, typically representing the application. |
application_id |
String | The unique identifier of the application requesting the token. This may differ from client_id when multiple applications share the same client. |
selected_account_id |
String | The selected account ID when a user has multiple accounts linked to the service. |
merged_accounts |
Array | An array of account IDs that have been merged into the primary account. |
acr |
String | The level of security or strength of the authentication method used. |
auth_time |
String | The timestamp, representing the moment when authentication took place, formatted in ISO 8601. |
Example: Authenticating to the Dead by Daylight Client
Request Headers:
Host: api.epicgames.dev
Accept-Encoding: identity
Content-Type: application/x-www-form-urlencoded
Accept: application/json
Authorization: Basic eHl6YTc4OTFzSGQ4NDdVeEI0cG54WjMwT2hRRXFNZXQ6SXdYNEg4bmRDbmE0R1RpRDhMVFkyT3hqSDJncG5uYkt6cTRCaHFkL250RQ==
X-Epic-Correlation-ID: {X-Epic-Correlation-ID}
User-Agent: EOS-SDK/{X-EOS-Version} ({os_name}/{os_version}.{os_build}.{architecture}) DeadByDaylight/{version}
X-EOS-Version: {sdk_version}-{build_number}
Content-Length: {Content-Length}
, where X-Epic-Correlation-ID
is a unique identifier for tracking requests across Epic's services, X-EOS-Version
is the EOS SDK version followed by the build number, os_name
is the operating system name, os_version
is the operating system version, os_build
is the specific build of the operating system, architecture
is the system's architecture, version
is the game's version, sdk_version
is the EOS SDK version, build_number
is the EOS SDK build number, and Content-Length
is the size of the request body in bytes.
Request Body:
grant_type=exchange_code&scope=basic_profile+friends_list+presence+openid&exchange_code={exchange_code}&deployment_id={deployment_id}
, where exchange_code
is the exchange code, and deployment_id
is a unique identifier for a specific game deployment integrated with EOS.
{
"scope": "basic_profile friends_list openid presence",
"token_type": "bearer",
"access_token": string,
"refresh_token": string,
"id_token": string,
"expires_in": 7200,
"expires_at": string,
"refresh_expires_in": 28800,
"refresh_expires_at": string,
"account_id": string,
"client_id": "xyza7891sHd847UxB4pnxZ30OhQEqMet",
"application_id": string,
"selected_account_id": string,
"merged_accounts": [],
"acr": "AAL1",
"auth_time": string
}
Refresh Token Grant
This grant allows clients to exchange a refresh token for a new access token when the current one expires, enabling continuous access without requiring further user interaction. You can learn about its flow here.
Method for Authenticating to the Dead by Daylight Client
1. Identify the client for which you need to obtain a refresh token.
2. Typically, a refresh_token
is provided at the final step of the authorization code grant. However, since Dead by Daylight does not support authentication via this grant, you will instead receive a refresh_token
at the final step of the exchange code grant. This token remains valid for 8 hours and allows the client to obtain a new access token without requiring the user's consent again.
3. Launch Dead by Daylight from the Epic Games Launcher while your network traffic capture application is running.
4. When you reach the title screen (where Dead by Daylight prompts you to "PRESS SPACE TO CONTINUE"), switch back to your network traffic capture application.
5. Locate the session that uses the exchange_code
grant_type
. This will be the request sent to https://api.epicgames.dev/epic/oauth/v2/token.
6. In the response body, locate the refresh_token
key and its corresponding value. Right-click on the value and select "Copy".
7. Send a POST
request to https://account-public-service-prod.ol.epicgames.com/account/api/oauth/token:
Request Headers:
Content-Type: application/x-www-form-urlencoded
Authorization: Basic eHl6YTc4OTFzSGQ4NDdVeEI0cG54WjMwT2hRRXFNZXQ6SXdYNEg4bmRDbmE0R1RpRDhMVFkyT3hqSDJncG5uYkt6cTRCaHFkL250RQ==
Request Body:
grant_type=refresh_token&refresh_token={refresh_token}
Note that refresh_token
is obtained from the response in step 6.
8. If the request is successful, then you will receive a response with the following structure:
{
"access_token": string,
"expires_in": 7200,
"expires_at": string,
"token_type": "bearer",
"refresh_token": string,
"refresh_expires": 28800,
"refresh_expires_at": string,
"account_id": string,
"client_id": "xyza7891sHd847UxB4pnxZ30OhQEqMet",
"internal_client": false,
"client_service": "2b2299be8ae84d679d4dc57c55af1510",
"scope": [
"basic_profile",
"friends_list",
"openid",
"presence"
],
"displayName": string,
"app": "2b2299be8ae84d679d4dc57c55af1510",
"in_app_id": string,
"device_id": string,
"product_id": "2b2299be8ae84d679d4dc57c55af1510",
"sandbox_id": "611482b8586142cda48a0786eb8a127c",
"deployment_id": string,
"application_id": string,
"acr": "urn:epic:loa:aal1",
"auth_time": string
}
Key | Type | Description |
---|---|---|
access_token |
String | The OAuth 2.0 access token, which grants temporary access to the application's protected resources. |
expires_in |
Number | The duration (in seconds) until the access token expires. |
expires_at |
String | The expiration timestamp of the access token, formatted in ISO 8601. |
token_type |
String | Indicates the type of token issued. |
refresh_token |
String | The token that can be used to request a new access token after the current one expires. |
refresh_expires |
Number | The duration (in seconds) before the token used to obtain a new access token expires. |
refresh_expires_at |
String | The expiration timestamp of the refresh token, formatted in ISO 8601. |
account_id |
String | The unique identifier for the user's account within Epic Games services. |
client_id |
String | The unique identifier of the client making the request, typically representing the application. |
internal_client |
Boolean | Indicates whether the client is part of Epic's internal systems. |
client_service |
String | The service associated with the client. |
scope |
Array | The permissions granted by the token, specifying the resources the client can access. |
displayName |
String | The user's display name associated with the account. |
app |
String | The application that is requesting the token. |
in_app_id |
String | The unique ID assigned to the user within the application. |
device_id |
String | The unique identifier of the device making the request. |
product_id |
String | The unique identifier of the product linked to the token. |
sandbox_id |
String | The environment to which the API requests and responses belong. |
deployment_id |
String | A unique identifier for a specific game deployment integrated with EOS. |
application_id |
String | The unique identifier of the application requesting the token. This may differ from client_id when multiple applications share the same client. |
acr |
String | The level of security or strength of the authentication method used. |
auth_time |
String | The timestamp, representing the moment when authentication took place, formatted in ISO 8601. |