Created
February 2, 2025 21:45
-
-
Save devashish2024/edcdc89330d020822b3e523d2fb4369e to your computer and use it in GitHub Desktop.
Chess.com OAuth JWT Implementation (Python)
This file contains hidden or 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 base64 | |
import hashlib | |
import secrets | |
import string | |
import requests | |
import urllib.parse | |
import json | |
from typing import Optional, Dict, Any | |
class ChessComOAuthHandler: | |
def __init__( | |
self, | |
client_id: str, | |
client_secret: Optional[str] = None, | |
scope: str = "openid profile", | |
redirect_uri: str = "http://localhost:3000/api/callback/chess" | |
): | |
self.client_id = client_id | |
self.client_secret = client_secret | |
self.scope = scope | |
self.redirect_uri = redirect_uri | |
self.token_endpoint = "https://oauth.chess.com/token" | |
self.code_verifier = self._generate_code_verifier() | |
self.code_challenge = self._generate_code_challenge() | |
def _parse_jwt(self, jwt_token): | |
parts = jwt_token.split('.') | |
base64_payload = parts[1] | |
base64_payload += '=' * ((4 - len(base64_payload) % 4) % 4) | |
decoded_payload = base64.urlsafe_b64decode(base64_payload).decode('utf-8') | |
parsed_payload = json.loads(decoded_payload) | |
return parsed_payload | |
def _generate_code_verifier(self, length: int = 64) -> str: | |
allowed_chars = string.ascii_letters + string.digits + "-._~" | |
return ''.join(secrets.choice(allowed_chars) for _ in range(length)) | |
def _generate_code_challenge(self) -> str: | |
sha256_hash = hashlib.sha256(self.code_verifier.encode('utf-8')).digest() | |
code_challenge = base64.urlsafe_b64encode(sha256_hash).decode('utf-8') | |
return code_challenge.replace('=', '') | |
def get_auth_url(self, state: Optional[str] = None) -> str: | |
params = { | |
'client_id': self.client_id, | |
'redirect_uri': self.redirect_uri, | |
'response_type': 'code', | |
'scope': self.scope, | |
'code_challenge': self.code_challenge, | |
'code_challenge_method': 'S256' | |
} | |
if state: | |
params['state'] = state | |
query = urllib.parse.urlencode(params) | |
return f"https://oauth.chess.com/authorize?{query}" | |
def exchange_code_for_tokens(self, authorization_code: str) -> Dict[str, Any]: | |
data = { | |
'grant_type': 'authorization_code', | |
'client_id': self.client_id, | |
'redirect_uri': self.redirect_uri, | |
'code': authorization_code, | |
'code_verifier': self.code_verifier | |
} | |
if self.client_secret: | |
data['client_secret'] = self.client_secret | |
response = requests.post(self.token_endpoint, data=data) | |
if response.status_code != 200: | |
raise Exception(f"Token exchange failed: {response.text}") | |
return response.json() | |
def main(): | |
handler = ChessComOAuthHandler( | |
client_id="" # your token | |
) | |
auth_url = handler.get_auth_url(state="random_state_string") | |
print(f"1. Visit this URL in your browser to authorize:\n{auth_url}\n") | |
print("2. After authorization, you'll be redirected to your callback URL.") | |
print("3. Copy the 'code' parameter from the URL and paste it here:") | |
authorization_code = input("Enter the code: ") | |
try: | |
tokens = handler.exchange_code_for_tokens(authorization_code) | |
jwt = tokens.get('id_token') | |
parsedJwt = handler._parse_jwt(jwt) | |
print("\nSuccess!") | |
print(json.dumps(parsedJwt, indent=4)) | |
except Exception as e: | |
print(f"\nError: {str(e)}") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This was generated with ChatGPT but seems to work like damn. What I get upon a successful response (this is what is logged:)
This is just an example of Chess.com OAuth API because I struggled hard to get to this. Maybe because I didn't though how easy would it be. But for those who need, this is it. (just modify a bit)