Search code examples
pythonauthenticationoauthhttprequest

ChatWork does not give me access token


I am trying to make a small app to send messages to the ChatWork app. I manage to get the code from the authorization when I sign in, but when I try to use this code to generate the token, I am getting 401. So, really do not know what I am doing wrong. I appreciate your help. This is the code:

import requests
from urllib.parse import urlencode, urlparse, parse_qs
import hashlib
import base64
import secrets

# Your ChatWork OAuth 2.0 client ID and redirect URI
client_id = "my_client_ID"
client_secret = "my_client_secret"
redirect_uri = "https://example.com/"
state = "343ab3341331218786ef" # This is for CSRF staff

# URL for the OAuth 2.0 authorization and token endpoints
auth_endpoint = "https://www.chatwork.com/packages/oauth2/login.php"
token_endpoint = "https://oauth.chatwork.com/token"

# Generate a code verifier
code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).rstrip(b'=').decode('utf-8')

# Calculate the code challenge
code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode('utf-8')).digest()).decode('utf-8').replace('=', '')

# Parameters for the authorization request
params = {
    "response_type": "code",
    "client_id": client_id,
    "redirect_uri": redirect_uri,
    "scope": "rooms.all:read_write",
    "state": state,  
    "code_challenge": code_challenge,
    "code_challenge_method": "S256"
}

# Construct the authorization URL
auth_url = auth_endpoint + "?" + urlencode(params)

# Print the authorization URL
print("Open this URL in your browser and authorize the application:")
print(auth_url)

# After the user authorizes the application, they will be redirected to your redirect URI
# Parse the authorization code from the redirect URI
authorization_code = input("Enter the authorization code from the redirect URI (or leave empty if denied): ")
parsed_url = urlparse(authorization_code)
query_params = parse_qs(parsed_url.query)
code = query_params["code"][0]
print(code)

if not code:
    print("Authorization denied by user.")
    # Handle the denial, such as displaying a message to the user or redirecting them to a different page
else:
    # Parameters for the token request
    token_params = {
        "grant_type": "authorization_code",
        "code": code,
        "client_id": client_id,
        "redirect_uri": redirect_uri,
        "code_verifier": code_verifier
    }

    # Make a POST request to the token endpoint to exchange the authorization code for an access token
    response = requests.post(token_endpoint, data=token_params, headers={"Authorization": "Basic " + base64.b64encode(f"{client_id}:{client_secret}".encode('utf-8')).decode('utf-8')})
    print(response)

    # Parse the access token from the response
    access_token = response.json().get('access_token')
    print(access_token)

This is the documentation: http://download.chatwork.com/ChatWork_API_Documentation.pdf

The type of client has to be set up as confidential, otherwise you won't get client_secret.


Solution

  • I solved the issue. First, setting up the account as public, then change the response without encoding (The documentation was a bit misleading here). This is the full code working:

    import requests
    from urllib.parse import urlencode, urlparse, parse_qs
    import hashlib
    import base64
    import secrets
    
    # Your ChatWork OAuth 2.0 client ID and redirect URI
    client_id = "your_client_id"
    redirect_uri = "https://example.com/"
    state = "343ab3341331218786ef"
    
    # URL for the OAuth 2.0 authorization and token endpoints
    auth_endpoint = "https://www.chatwork.com/packages/oauth2/login.php"
    token_endpoint = "https://oauth.chatwork.com/token"
    
    # Generate a code verifier
    code_verifier = base64.urlsafe_b64encode(secrets.token_bytes(32)).rstrip(b'=').decode('utf-8')
    
    # Calculate the code challenge
    code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode('utf-8')).digest()).decode('utf-8').replace('=', '')
    
    # Parameters for the authorization request
    params = {
        "response_type": "code",
        "client_id": client_id,
        "redirect_uri": redirect_uri,
        "scope": "rooms.all:read_write",
        "state": state,  # Generate a random string for CSRF protection
        "code_challenge": code_challenge,
        "code_challenge_method": "S256"
    }
    
    # Construct the authorization URL
    auth_url = auth_endpoint + "?" + urlencode(params)
    
    # Print the authorization URL
    print("Open this URL in your browser and authorize the application:")
    print(auth_url)
    
    # After the user authorizes the application, they will be redirected to your redirect URI
    # Parse the authorization code from the redirect URI
    authorization_code = input("Enter the authorization code from the redirect URI (or leave empty if denied): ")
    parsed_url = urlparse(authorization_code)
    query_params = parse_qs(parsed_url.query)
    code = query_params["code"][0]
    print(code)
    
    if not code:
        print("Authorization denied by user.")
        # Handle the denial, such as displaying a message to the user or redirecting them to a different page
    else:
        # Parameters for the token request
        token_params = {
            "grant_type": "authorization_code",
            "client_id": client_id,
            "code": code,
            "redirect_uri": redirect_uri,
            "code_verifier": code_verifier
        }
    
        response = requests.post(token_endpoint, data=token_params)
        print(response.json())
    
        # Parse the access token from the response
        access_token = response.json().get('access_token')
        print(access_token)
        ```