├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── generator.py ├── icon.ico └── requirements.txt /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | cover/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | .pybuilder/ 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | # For a library or package, you might want to ignore these files since the code is 88 | # intended to run in multiple environments; otherwise, check them in: 89 | # .python-version 90 | 91 | # pipenv 92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 95 | # install all needed dependencies. 96 | #Pipfile.lock 97 | 98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 99 | __pypackages__/ 100 | 101 | # Celery stuff 102 | celerybeat-schedule 103 | celerybeat.pid 104 | 105 | # SageMath parsed files 106 | *.sage.py 107 | 108 | # Environments 109 | .env 110 | .venv 111 | env/ 112 | venv/ 113 | ENV/ 114 | env.bak/ 115 | venv.bak/ 116 | 117 | # Spyder project settings 118 | .spyderproject 119 | .spyproject 120 | 121 | # Rope project settings 122 | .ropeproject 123 | 124 | # mkdocs documentation 125 | /site 126 | 127 | # mypy 128 | .mypy_cache/ 129 | .dmypy.json 130 | dmypy.json 131 | 132 | # Pyre type checker 133 | .pyre/ 134 | 135 | # pytype static type analyzer 136 | .pytype/ 137 | 138 | # Cython debug symbols 139 | cython_debug/ 140 | 141 | # static files generated from Django application using `collectstatic` 142 | media 143 | static 144 | 145 | # Windows thumbnail cache files 146 | Thumbs.db 147 | Thumbs.db:encryptable 148 | ehthumbs.db 149 | ehthumbs_vista.db 150 | 151 | # Dump file 152 | *.stackdump 153 | 154 | # Folder config file 155 | [Dd]esktop.ini 156 | 157 | # Recycle Bin used on file shares 158 | $RECYCLE.BIN/ 159 | 160 | # Windows Installer files 161 | *.cab 162 | *.msi 163 | *.msix 164 | *.msm 165 | *.msp 166 | 167 | # Windows shortcuts 168 | *.lnk 169 | 170 | *~ 171 | 172 | # temporary files which can be created if a process still has a handle open of a deleted file 173 | .fuse_hidden* 174 | 175 | # KDE directory preferences 176 | .directory 177 | 178 | # Linux trash folder which might appear on any partition or disk 179 | .Trash-* 180 | 181 | # .nfs files are created when an open file is removed but is still being accessed 182 | .nfs* 183 | 184 | # General 185 | .DS_Store 186 | .AppleDouble 187 | .LSOverride 188 | 189 | # Icon must end with two \r 190 | Icon 191 | 192 | # Thumbnails 193 | ._* 194 | 195 | # Files that might appear in the root of a volume 196 | .DocumentRevisions-V100 197 | .fseventsd 198 | .Spotlight-V100 199 | .TemporaryItems 200 | .Trashes 201 | .VolumeIcon.icns 202 | .com.apple.timemachine.donotpresent 203 | 204 | # Directories potentially created on remote AFP share 205 | .AppleDB 206 | .AppleDesktop 207 | Network Trash Folder 208 | Temporary Items 209 | .apdisk 210 | 211 | # IDE 212 | .vscode 213 | 214 | # Credentials 215 | **device_auths.json** -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | “Commons Clause” License Condition v1.0 2 | Copyright Oli 2019-2021 3 | 4 | The Software is provided to you by the Licensor under the 5 | License, as defined below, subject to the following condition. 6 | 7 | Without limiting other conditions in the License, the grant 8 | of rights under the License will not include, and the License 9 | does not grant to you, the right to Sell the Software. 10 | 11 | For purposes of the foregoing, “Sell” means practicing any or 12 | all of the rights granted to you under the License to provide 13 | to third parties, for a fee or other consideration (including 14 | without limitation fees for hosting or consulting/ support 15 | services related to the Software), a product or service whose 16 | value derives, entirely or substantially, from the functionality 17 | of the Software. Any license notice or attribution required by 18 | the License must also include this Commons Clause License 19 | Condition notice. 20 | 21 | Software: DeviceAuthGenerator 22 | 23 | License: Apache 2.0 Modified. 24 | 25 | --------------------------------------------------------------------- 26 | 27 | 28 | Apache License 29 | Version 2.0, January 2004 30 | http://www.apache.org/licenses/ 31 | 32 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 33 | 34 | 1. Definitions. 35 | 36 | "License" shall mean the terms and conditions for use, reproduction, 37 | and distribution as defined by Sections 1 through 9 of this document. 38 | 39 | "Licensor" shall mean the copyright owner or entity authorized by 40 | the copyright owner that is granting the License. 41 | 42 | "Legal Entity" shall mean the union of the acting entity and all 43 | other entities that control, are controlled by, or are under common 44 | control with that entity. For the purposes of this definition, 45 | "control" means (i) the power, direct or indirect, to cause the 46 | direction or management of such entity, whether by contract or 47 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 48 | outstanding shares, or (iii) beneficial ownership of such entity. 49 | 50 | "You" (or "Your") shall mean an individual or Legal Entity 51 | exercising permissions granted by this License. 52 | 53 | "Source" form shall mean the preferred form for making modifications, 54 | including but not limited to software source code, documentation 55 | source, and configuration files. 56 | 57 | "Object" form shall mean any form resulting from mechanical 58 | transformation or translation of a Source form, including but 59 | not limited to compiled object code, generated documentation, 60 | and conversions to other media types. 61 | 62 | "Work" shall mean the work of authorship, whether in Source or 63 | Object form, made available under the License, as indicated by a 64 | copyright notice that is included in or attached to the work 65 | (an example is provided in the Appendix below). 66 | 67 | "Derivative Works" shall mean any work, whether in Source or Object 68 | form, that is based on (or derived from) the Work and for which the 69 | editorial revisions, annotations, elaborations, or other modifications 70 | represent, as a whole, an original work of authorship. For the purposes 71 | of this License, Derivative Works shall not include works that remain 72 | separable from, or merely link (or bind by name) to the interfaces of, 73 | the Work and Derivative Works thereof. 74 | 75 | "Contribution" shall mean any work of authorship, including 76 | the original version of the Work and any modifications or additions 77 | to that Work or Derivative Works thereof, that is intentionally 78 | submitted to Licensor for inclusion in the Work by the copyright owner 79 | or by an individual or Legal Entity authorized to submit on behalf of 80 | the copyright owner. For the purposes of this definition, "submitted" 81 | means any form of electronic, verbal, or written communication sent 82 | to the Licensor or its representatives, including but not limited to 83 | communication on electronic mailing lists, source code control systems, 84 | and issue tracking systems that are managed by, or on behalf of, the 85 | Licensor for the purpose of discussing and improving the Work, but 86 | excluding communication that is conspicuously marked or otherwise 87 | designated in writing by the copyright owner as "Not a Contribution." 88 | 89 | "Contributor" shall mean Licensor and any individual or Legal Entity 90 | on behalf of whom a Contribution has been received by Licensor and 91 | subsequently incorporated within the Work. 92 | 93 | 2. Grant of Copyright License. Subject to the terms and conditions of 94 | this License, each Contributor hereby grants to You a perpetual, 95 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 96 | copyright license to reproduce, prepare Derivative Works of, 97 | publicly display, publicly perform, sublicense, and distribute the 98 | Work and such Derivative Works in Source or Object form. 99 | 100 | 3. Grant of Patent License. Subject to the terms and conditions of 101 | this License, each Contributor hereby grants to You a perpetual, 102 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 103 | (except as stated in this section) patent license to make, have made, 104 | use, offer to sell, sell, import, and otherwise transfer the Work, 105 | where such license applies only to those patent claims licensable 106 | by such Contributor that are necessarily infringed by their 107 | Contribution(s) alone or by combination of their Contribution(s) 108 | with the Work to which such Contribution(s) was submitted. If You 109 | institute patent litigation against any entity (including a 110 | cross-claim or counterclaim in a lawsuit) alleging that the Work 111 | or a Contribution incorporated within the Work constitutes direct 112 | or contributory patent infringement, then any patent licenses 113 | granted to You under this License for that Work shall terminate 114 | as of the date such litigation is filed. 115 | 116 | 4. Redistribution. You may reproduce and distribute copies of the 117 | Work or Derivative Works thereof in any medium, with or without 118 | modifications, and in Source or Object form, provided that You 119 | meet the following conditions: 120 | 121 | (a) You must give any other recipients of the Work or 122 | Derivative Works a copy of this License; and 123 | 124 | (b) You must cause any modified files to carry prominent notices 125 | stating that You changed the files; and 126 | 127 | (c) You must retain, in the Source form of any Derivative Works 128 | that You distribute, all copyright, patent, trademark, and 129 | attribution notices from the Source form of the Work, 130 | excluding those notices that do not pertain to any part of 131 | the Derivative Works; and 132 | 133 | (d) If the Work includes a "NOTICE" text file as part of its 134 | distribution, then any Derivative Works that You distribute must 135 | include a readable copy of the attribution notices contained 136 | within such NOTICE file, excluding those notices that do not 137 | pertain to any part of the Derivative Works, in at least one 138 | of the following places: within a NOTICE text file distributed 139 | as part of the Derivative Works; within the Source form or 140 | documentation, if provided along with the Derivative Works; or, 141 | within a display generated by the Derivative Works, if and 142 | wherever such third-party notices normally appear. The contents 143 | of the NOTICE file are for informational purposes only and 144 | do not modify the License. You may add Your own attribution 145 | notices within Derivative Works that You distribute, alongside 146 | or as an addendum to the NOTICE text from the Work, provided 147 | that such additional attribution notices cannot be construed 148 | as modifying the License. 149 | 150 | (e) You may not steal the source code or any other content related to 151 | PartyBot w/o providing credit to the original owner/s. Meaning you 152 | cannot redistribute it without providing full credit and you also 153 | cannot market the product as your own w/o explicit permission from 154 | the owner/s. 155 | 156 | You may add Your own copyright statement to Your modifications and 157 | may provide additional or different license terms and conditions 158 | for use, reproduction, or distribution of Your modifications, or 159 | for any such Derivative Works as a whole, provided Your use, 160 | reproduction, and distribution of the Work otherwise complies with 161 | the conditions stated in this License. 162 | 163 | 5. Submission of Contributions. Unless You explicitly state otherwise, 164 | any Contribution intentionally submitted for inclusion in the Work 165 | by You to the Licensor shall be under the terms and conditions of 166 | this License, without any additional terms or conditions. 167 | Notwithstanding the above, nothing herein shall supersede or modify 168 | the terms of any separate license agreement you may have executed 169 | with Licensor regarding such Contributions. 170 | 171 | 6. Trademarks. This License does not grant permission to use the trade 172 | names, trademarks, service marks, or product names of the Licensor, 173 | except as required for reasonable and customary use in describing the 174 | origin of the Work and reproducing the content of the NOTICE file. 175 | 176 | 7. Disclaimer of Warranty. Unless required by applicable law or 177 | agreed to in writing, Licensor provides the Work (and each 178 | Contributor provides its Contributions) on an "AS IS" BASIS, 179 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 180 | implied, including, without limitation, any warranties or conditions 181 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 182 | PARTICULAR PURPOSE. You are solely responsible for determining the 183 | appropriateness of using or redistributing the Work and assume any 184 | risks associated with Your exercise of permissions under this License. 185 | 186 | 8. Limitation of Liability. In no event and under no legal theory, 187 | whether in tort (including negligence), contract, or otherwise, 188 | unless required by applicable law (such as deliberate and grossly 189 | negligent acts) or agreed to in writing, shall any Contributor be 190 | liable to You for damages, including any direct, indirect, special, 191 | incidental, or consequential damages of any character arising as a 192 | result of this License or out of the use or inability to use the 193 | Work (including but not limited to damages for loss of goodwill, 194 | work stoppage, computer failure or malfunction, or any and all 195 | other commercial damages or losses), even if such Contributor 196 | has been advised of the possibility of such damages. 197 | 198 | 9. Accepting Warranty or Additional Liability. While redistributing 199 | the Work or Derivative Works thereof, You may choose to offer, 200 | and charge a fee for, acceptance of support, warranty, indemnity, 201 | or other liability obligations and/or rights consistent with this 202 | License. However, in accepting such obligations, You may act only 203 | on Your own behalf and on Your sole responsibility, not on behalf 204 | of any other Contributor, and only if You agree to indemnify, 205 | defend, and hold each Contributor harmless for any liability 206 | incurred by, or claims asserted against, such Contributor by reason 207 | of your accepting any such warranty or additional liability. 208 | 209 | END OF TERMS AND CONDITIONS 210 | 211 | APPENDIX: How to apply the Apache License to your work. 212 | 213 | To apply the Apache License to your work, attach the following 214 | boilerplate notice, with the fields enclosed by brackets "[]" 215 | replaced with your own identifying information. (Don't include 216 | the brackets!) The text should be enclosed in the appropriate 217 | comment syntax for the file format. We also recommend that a 218 | file or class name and description of purpose be included on the 219 | same "printed page" as the copyright notice for easier 220 | identification within third-party archives. 221 | 222 | Copyright 2019-2021 Oli 223 | 224 | Licensed under the Apache License, Version 2.0 (the "License"); 225 | you may not use this file except in compliance with the License. 226 | You may obtain a copy of the License at 227 | 228 | http://www.apache.org/licenses/LICENSE-2.0 229 | 230 | Unless required by applicable law or agreed to in writing, software 231 | distributed under the License is distributed on an "AS IS" BASIS, 232 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 233 | See the License for the specific language governing permissions and 234 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

DeviceAuthGenerator

2 | 3 |

4 | 5 | Python 6 | 7 | 8 | PEP8 9 | 10 |

11 | 12 |

Program to easily create device auths for use in Epic Games API authentication.

13 | 14 | --- 15 | 16 | ## Discord Support: 17 | 18 | 19 | --- 20 | ## Example Usage: 21 | 22 | 23 | ## Usage: 24 | DeviceAuthGenerator is pretty simple to use. You can either use run the Python script directly or use the pre-compiled 25 | executable in the releases. 26 | 1. Install the requirements _(only applies to the Python script, you don't need to install requirements for the executable)_. 27 | 28 | ``` 29 | pip install -U -r requirements.txt 30 | ``` 31 | 32 | 2. Run DeviceAuthGenerator, either being `generator.py` or `DeviceAuthGenerator.exe`. 33 | 34 | 3. Login the the Epic Games account you wish to generate device auths for when prompted. 35 | 36 | 3. Wait 5 or less seconds for device auths to be generated. They will then be pasted into the console, copied to 37 | clipboard & saved in `device_auths.json` which is compatible out of the box with 38 | fortnitepy. 39 | 40 | ## Example responses: 41 | ### Console 42 | ```json 43 | Generated device auths for: xMistt. 44 | { 45 | "device_id": "c403e1ea918b4414b01f6292ee7bbad2", 46 | "account_id": "ab0f2bb71b1d4e73ac467bd1b1072061'", 47 | "secret": "61E9F2025EA14493A63CD94AD1B9C569", 48 | "user_agent": "DeviceAuthGenerator/1.0.0 Windows/10", 49 | "created": { 50 | "location": "London, England", 51 | "ip_address": "215.42.168.146", 52 | "datetime": "2021-05-15T16:57:46.372Z" 53 | } 54 | } 55 | 56 | ``` 57 | ___ 58 | ### File 59 | ```json 60 | { 61 | "xmistt@partybot.com": { 62 | "device_id": "c403e1ea918b4414b01f6292ee7bbad2", 63 | "account_id": "ab0f2bb71b1d4e73ac467bd1b1072061", 64 | "secret": "61E9F2025EA14493A63CD94AD1B9C569", 65 | "user_agent": "DeviceAuthGenerator/1.0.0 Windows/10", 66 | "created": { 67 | "location": "London, England", 68 | "ip_address": "215.42.168.146", 69 | "datetime": "2021-05-15T16:57:46.372Z" 70 | } 71 | } 72 | } 73 | ``` 74 | ## License: 75 | By downloading this, you agree to the Commons Clause license and that you're not allowed to sell this repository or any code from this repository. For more info see https://commonsclause.com/. -------------------------------------------------------------------------------- /generator.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | """ 4 | “Commons Clause” License Condition v1.0 5 | Copyright Oli 2019-2021 6 | 7 | The Software is provided to you by the Licensor under the 8 | License, as defined below, subject to the following condition. 9 | 10 | Without limiting other conditions in the License, the grant 11 | of rights under the License will not include, and the License 12 | does not grant to you, the right to Sell the Software. 13 | 14 | For purposes of the foregoing, “Sell” means practicing any or 15 | all of the rights granted to you under the License to provide 16 | to third parties, for a fee or other consideration (including 17 | without limitation fees for hosting or consulting/ support 18 | services related to the Software), a product or service whose 19 | value derives, entirely or substantially, from the functionality 20 | of the Software. Any license notice or attribution required by 21 | the License must also include this Commons Clause License 22 | Condition notice. 23 | 24 | Software: DeviceAuthGenerator 25 | 26 | License: Apache 2.0 Modified. 27 | """ 28 | 29 | import asyncio 30 | import webbrowser 31 | import json 32 | import platform 33 | import os 34 | import sys 35 | 36 | import aiohttp 37 | import pyperclip 38 | 39 | 40 | __version__ = "1.1.1" 41 | 42 | # "Constants" ? I don't know. 43 | SWITCH_TOKEN = "OThmN2U0MmMyZTNhNGY4NmE3NGViNDNmYmI0MWVkMzk6MGEyNDQ5YTItMDAxYS00NTFlLWFmZWMtM2U4MTI5MDFjNGQ3" 44 | IOS_TOKEN = "MzQ0NmNkNzI2OTRjNGE0NDg1ZDgxYjc3YWRiYjIxNDE6OTIwOWQ0YTVlMjVhNDU3ZmI5YjA3NDg5ZDMxM2I0MWE=" 45 | 46 | 47 | class EpicUser: 48 | def __init__(self, data: dict = {}): 49 | self.raw = data 50 | 51 | self.access_token = data.get("access_token", "") 52 | self.expires_in = data.get("expires_in", 0) 53 | self.expires_at = data.get("expires_at", "") 54 | self.token_type = data.get("token_type", "") 55 | self.refresh_token = data.get("refresh_token", "") 56 | self.refresh_expires = data.get("refresh_expires", "") 57 | self.refresh_expires_at = data.get("refresh_expires_at", "") 58 | self.account_id = data.get("account_id", "") 59 | self.client_id = data.get("client_id", "") 60 | self.internal_client = data.get("internal_client", False) 61 | self.client_service = data.get("client_service", "") 62 | self.display_name = data.get("displayName", "") 63 | self.app = data.get("app", "") 64 | self.in_app_id = data.get("in_app_id", "") 65 | 66 | async def get_email(self) -> None: 67 | async with aiohttp.ClientSession() as session: 68 | async with session.request( 69 | method="GET", 70 | url="https://account-public-service-prod03.ol.epicgames.com/" 71 | f"account/api/public/account/displayName/{self.display_name}", 72 | headers={"Authorization": f"bearer {self.access_token}"}, 73 | ) as request: 74 | data = await request.json() 75 | 76 | return data["email"] 77 | 78 | 79 | class EpicGenerator: 80 | def __init__(self) -> None: 81 | self.http: aiohttp.ClientSession 82 | 83 | self.access_token = "" 84 | self.user_agent = f"DeviceAuthGenerator/{__version__} {platform.system()}/{platform.version()}" 85 | 86 | async def start(self) -> None: 87 | self.http = aiohttp.ClientSession(headers={"User-Agent": self.user_agent}) 88 | 89 | self.access_token = await self.get_access_token() 90 | 91 | print( 92 | f"DeviceAuthGenerator v{__version__} made by xMistt // Oli. Ask for help in PartyBot." 93 | ) 94 | await asyncio.sleep(3) 95 | os.system("cls" if sys.platform.startswith("win") else "clear") 96 | 97 | while True: 98 | print("Opening device code link in a new tab.") 99 | 100 | device_code = await self.create_device_code() 101 | webbrowser.open( 102 | f"https://www.epicgames.com/activate?userCode={device_code[0]}", 103 | new=1, 104 | ) 105 | 106 | user = await self.wait_for_device_code_completion(code=device_code[1]) 107 | device_auths = await self.create_device_auths(user) 108 | 109 | os.system("cls" if sys.platform.startswith("win") else "clear") 110 | pretty_device_auths = json.dumps(device_auths, sort_keys=False, indent=4) 111 | print(f"Generated device auths for: {user.display_name}.") 112 | print(pretty_device_auths) 113 | 114 | pyperclip.copy(pretty_device_auths) 115 | await self.save_device_auths(device_auths=device_auths, user=user) 116 | 117 | print("\n") 118 | print( 119 | "They have been copied to the clipboard & saved in device_auths.json." 120 | ) 121 | choice = input("Do you want to generate another device auth? (Y/N): ") 122 | 123 | if choice.lower().strip() != "y": 124 | break 125 | else: 126 | os.system("cls" if sys.platform.startswith("win") else "clear") 127 | print("Closing DeviceAuthGenerator...") 128 | await asyncio.sleep(1) 129 | 130 | await self.http.close() 131 | sys.exit() 132 | 133 | async def get_access_token(self) -> str: 134 | async with self.http.request( 135 | method="POST", 136 | url="https://account-public-service-prod.ol.epicgames.com/account/api/oauth/token", 137 | headers={ 138 | "Content-Type": "application/x-www-form-urlencoded", 139 | "Authorization": f"basic {SWITCH_TOKEN}", 140 | }, 141 | data={ 142 | "grant_type": "client_credentials", 143 | }, 144 | ) as request: 145 | data = await request.json() 146 | 147 | return data["access_token"] 148 | 149 | async def create_device_code(self) -> tuple: 150 | async with self.http.request( 151 | method="POST", 152 | url="https://account-public-service-prod03.ol.epicgames.com/account/api/oauth/deviceAuthorization", 153 | headers={ 154 | "Authorization": f"bearer {self.access_token}", 155 | "Content-Type": "application/x-www-form-urlencoded", 156 | }, 157 | ) as request: 158 | data = await request.json() 159 | 160 | return data["user_code"], data["device_code"] 161 | 162 | async def wait_for_device_code_completion(self, code: str) -> EpicUser: 163 | os.system("cls" if sys.platform.startswith("win") else "clear") 164 | print("Waiting for completion.") 165 | 166 | while True: 167 | async with self.http.request( 168 | method="POST", 169 | url="https://account-public-service-prod03.ol.epicgames.com/account/api/oauth/token", 170 | headers={ 171 | "Authorization": f"basic {SWITCH_TOKEN}", 172 | "Content-Type": "application/x-www-form-urlencoded", 173 | }, 174 | data={"grant_type": "device_code", "device_code": code}, 175 | ) as request: 176 | token = await request.json() 177 | 178 | if request.status == 200: 179 | break 180 | else: 181 | if ( 182 | token["errorCode"] 183 | == "errors.com.epicgames.account.oauth.authorization_pending" 184 | ): 185 | pass 186 | elif token["errorCode"] == "errors.com.epicgames.not_found": 187 | pass 188 | else: 189 | print(json.dumps(token, sort_keys=False, indent=4)) 190 | 191 | await asyncio.sleep(5) 192 | 193 | async with self.http.request( 194 | method="GET", 195 | url="https://account-public-service-prod03.ol.epicgames.com/account/api/oauth/exchange", 196 | headers={"Authorization": f"bearer {token['access_token']}"}, 197 | ) as request: 198 | exchange = await request.json() 199 | 200 | async with self.http.request( 201 | method="POST", 202 | url="https://account-public-service-prod03.ol.epicgames.com/account/api/oauth/token", 203 | headers={ 204 | "Authorization": f"basic {IOS_TOKEN}", 205 | "Content-Type": "application/x-www-form-urlencoded", 206 | }, 207 | data={ 208 | "grant_type": "exchange_code", 209 | "exchange_code": exchange["code"], 210 | }, 211 | ) as request: 212 | auth_information = await request.json() 213 | 214 | return EpicUser(data=auth_information) 215 | 216 | async def create_device_auths(self, user: EpicUser) -> dict: 217 | async with self.http.request( 218 | method="POST", 219 | url="https://account-public-service-prod.ol.epicgames.com/" 220 | f"account/api/public/account/{user.account_id}/deviceAuth", 221 | headers={ 222 | "Authorization": f"bearer {user.access_token}", 223 | "Content-Type": "application/json", 224 | }, 225 | ) as request: 226 | data = await request.json() 227 | 228 | return { 229 | "device_id": data["deviceId"], 230 | "account_id": data["accountId"], 231 | "secret": data["secret"], 232 | "user_agent": data["userAgent"], 233 | "created": { 234 | "location": data["created"]["location"], 235 | "ip_address": data["created"]["ipAddress"], 236 | "datetime": data["created"]["dateTime"], 237 | }, 238 | } 239 | 240 | async def save_device_auths(self, device_auths: dict, user: EpicUser) -> None: 241 | if os.path.isfile("device_auths.json"): 242 | with open("device_auths.json", "r") as fp: 243 | current = json.load(fp) 244 | else: 245 | current = {} 246 | 247 | email = await user.get_email() 248 | current[email] = device_auths 249 | 250 | with open("device_auths.json", "w") as fp: 251 | json.dump(current, fp, sort_keys=False, indent=4) 252 | 253 | def run(self) -> None: 254 | loop = asyncio.get_event_loop() 255 | loop.run_until_complete(self.start()) 256 | loop.run_forever() 257 | 258 | 259 | gen = EpicGenerator() 260 | gen.run() 261 | -------------------------------------------------------------------------------- /icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jackblk/DeviceAuthGenerator/f5ae60043540dbb347fa2f478684d6b3911df0f8/icon.ico -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp 2 | pyperclip --------------------------------------------------------------------------------