Last active
March 5, 2024 16:06
-
-
Save Terbau/9a07849fb30c0232af730265c327e27c to your computer and use it in GitHub Desktop.
(Partially outdated) epic games authflow
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import requests | |
# Constants. These should not be tampered with. | |
base = "https://www.epicgames.com" | |
base_public_service = "https://account-public-service-prod03.ol.epicgames.com" | |
launcher_token = "MzQ0NmNkNzI2OTRjNGE0NDg1ZDgxYjc3YWRiYjIxNDE6OTIwOWQ0YTVlMjVhNDU3ZmI5YjA3NDg5ZDMxM2I0MWE=" | |
fortnite_token = "ZWM2ODRiOGM2ODdmNDc5ZmFkZWEzY2IyYWQ4M2Y1YzY6ZTFmMzFjMjExZjI4NDEzMTg2MjYyZDM3YTEzZmM4NGQ=" | |
# Fill out. | |
email = "" | |
password = "" | |
two_factor_code = "" # Leave empty if you want to take an input from the console. | |
def authenticate(session): | |
# Request to fetch all cookies needed. With the request module all the | |
# cookies are automatically stored in the session cookie jar. | |
session.get(f"{base}/id/api/csrf") | |
res = session.get( | |
f"{base}/id/api/reputation", | |
headers={ | |
'x-xsrf-token': session.cookies.get("XSRF-TOKEN") | |
}, | |
cookies=session.cookies | |
) | |
if res.json()['verdict'] != 'allow': | |
# If captcha is enforced, it means that you won't be able to log | |
# to the account on the same ip for a while or on the account | |
# in general. It is not known exactly what causes this to happen | |
# but we know in general that it happens when you try to log in | |
# too many times (often regardless of which accounts). Theres no | |
# real good workarounds but there is other ways to log in | |
# like using device auth. This however is a little more complicated | |
# and does not fit in this simple example. | |
raise RuntimeError('Captcha was required for this login') | |
# Attempt to login with email and password. | |
res = session.post( | |
f"{base}/id/api/login", | |
headers={ | |
"x-xsrf-token": session.cookies.get("XSRF-TOKEN") | |
}, | |
data={ | |
"email": email, | |
"password": password, | |
"rememberMe": False, | |
"captcha": "" | |
}, | |
cookies=session.cookies | |
) | |
# is only true if an error occured | |
if res.status_code >= 400: | |
data = res.json() | |
error = data['errorCode'] | |
if error == 'errors.com.epicgames.account.invalid_account_credentials': | |
raise ValueError('Invalid credentials') | |
if error == 'errors.com.epicgames.common.two_factor_authentication.required': | |
# Since the user we are trying to log in as requires two factor authentication, | |
# we have to fetch a new xsrf token and use that to authenticate with mfa and | |
# for the rest of the requests. | |
session.get(f"{base}/id/api/csrf") | |
res = session.post( | |
f"{base}/id/api/login/mfa", | |
headers={ | |
"x-xsrf-token": session.cookies.get("XSRF-TOKEN") | |
}, | |
data={ | |
"code": two_factor_code or input("Please enter the 2fa code: "), | |
"method": "authenticator", | |
"rememberDevice": False # set to True if you want the device to be remembered | |
}, | |
cookies=session.cookies | |
) | |
if res.status_code >= 400: | |
mfa_data = res.json() | |
mfa_error = mfa_data['errorCode'] | |
errors = ( | |
'errors.com.epicgames.accountportal.mfa_code_invalid', # wrong code passed | |
'errors.com.epicgames.accountportal.validation' # invalid code passed (e.g. wrong amount of characters) | |
) | |
if mfa_error in errors: | |
raise ValueError('Invalid code passed') | |
# We need new csrf cookies again | |
session.get(f"{base}/id/api/csrf") | |
# Fetch exchange code. | |
res = session.post( | |
f"{base}/id/api/exchange/generate", | |
headers={ | |
"x-xsrf-token": session.cookies.get("XSRF-TOKEN") | |
}, | |
cookies=session.cookies | |
) | |
exchange_code = res.json()["code"] | |
# Exchange the code to fetch the launcher access token. | |
res = session.post( | |
f"{base_public_service}/account/api/oauth/token", | |
headers={ | |
"Authorization": f"basic {launcher_token}" | |
}, | |
data={ | |
"grant_type": "exchange_code", | |
"exchange_code": exchange_code, | |
"token_type": "eg1" | |
} | |
) | |
launcher_access_token = res.json()["access_token"] | |
# The following code will use the launcher access token to retrieve | |
# a fortnite access token. If you don't require fortnite permissions | |
# you can cut out the part below. | |
res = session.get( | |
f"{base_public_service}/account/api/oauth/exchange", | |
headers={ | |
"Authorization": f"Bearer {launcher_access_token}" | |
} | |
) | |
exchange_code = res.json()["code"] | |
res = session.post( | |
f"{base_public_service}/account/api/oauth/token", | |
headers={ | |
"Authorization": f"basic {fortnite_token}" | |
}, | |
data={ | |
"grant_type": "exchange_code", | |
"token_type": "eg1", | |
"exchange_code": exchange_code | |
} | |
) | |
# NOTE: Tokens expires after eight hours. | |
fortnite_access_token = res.json()["access_token"] | |
print(fortnite_access_token) | |
with requests.Session() as session: | |
authenticate(session) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment