PYTHON
Implementing OAuth 2.0 Client Credentials Flow in Python for Server-to-Server Auth
Securely obtain an access token using the OAuth 2.0 Client Credentials grant type in Python, ideal for server-to-server API integrations without user involvement.
import requests
import os
# Load environment variables for sensitive data
# pip install python-dotenv and create a .env file:
# CLIENT_ID=your_client_id
# CLIENT_SECRET=your_client_secret
# TOKEN_URL=https://your-oauth-server.com/oauth/token
from dotenv import load_dotenv
load_dotenv()
# Configuration from environment variables
CLIENT_ID = os.getenv('CLIENT_ID')
CLIENT_SECRET = os.getenv('CLIENT_SECRET')
TOKEN_URL = os.getenv('TOKEN_URL')
def get_oauth_token():
"""Obtains an OAuth 2.0 access token using the Client Credentials flow."""
if not all([CLIENT_ID, CLIENT_SECRET, TOKEN_URL]):
raise ValueError("Missing one or more OAuth configuration environment variables.")
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
payload = {
'grant_type': 'client_credentials',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET
}
try:
print(f"Requesting token from: {TOKEN_URL}")
response = requests.post(TOKEN_URL, headers=headers, data=payload)
response.raise_for_status() # Raise an exception for HTTP errors (4xx or 5xx)
token_data = response.json()
access_token = token_data.get('access_token')
expires_in = token_data.get('expires_in')
token_type = token_data.get('token_type')
if not access_token:
raise ValueError("Access token not found in response.")
print("Successfully obtained access token.")
print(f"Token Type: {token_type}, Expires In: {expires_in} seconds")
return access_token
except requests.exceptions.HTTPError as err:
print(f"HTTP Error: {err}")
print(f"Response: {err.response.text}")
return None
except requests.exceptions.RequestException as err:
print(f"Request Error: {err}")
return None
except ValueError as err:
print(f"Data Error: {err}")
return None
def call_protected_api(access_token, api_url):
"""Calls a protected API using the obtained access token."""
if not access_token:
print("No access token provided. Cannot call protected API.")
return None
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
try:
print(f"Calling protected API: {api_url}")
response = requests.get(api_url, headers=headers)
response.raise_for_status()
print("Protected API response:")
return response.json()
except requests.exceptions.HTTPError as err:
print(f"HTTP Error calling protected API: {err}")
print(f"Response: {err.response.text}")
return None
except requests.exceptions.RequestException as err:
print(f"Request Error calling protected API: {err}")
return None
# --- Example Usage ---
if __name__ == "__main__":
# Make sure your .env file has CLIENT_ID, CLIENT_SECRET, and TOKEN_URL
# For a real API, replace 'https://api.example.com/data' with your protected endpoint
PROTECTED_API_URL = 'https://api.example.com/data'
token = get_oauth_token()
if token:
print(f"Access Token: {token[:20]}...") # Print a snippet for security
api_response = call_protected_api(token, PROTECTED_API_URL)
if api_response:
print(api_response)
else:
print("Failed to obtain OAuth token.")
How it works: This Python snippet demonstrates how to implement the OAuth 2.0 Client Credentials grant type, a secure method for server-to-server API authentication where no user interaction is required. It uses the `requests` library to send a POST request to an OAuth token endpoint, including the `client_id` and `client_secret` to obtain an `access_token`. Once the token is acquired, it's used in the `Authorization` header as a Bearer token for subsequent requests to protected API resources. This flow is critical for applications that need to access API resources on their own behalf, rather than on behalf of a user.