Ojasa Mirai

Ojasa Mirai

Python

Loading...

Learning Level

🟢 Beginner🔵 Advanced
REST API BasicsHTTP RequestsStatus CodesJSON SerializationError HandlingAPI AuthenticationRate LimitingBuilding APIsWeb Scraping Basics
Python/Apis Json/Api Authentication

🔐 API Authentication — Securing Access to Protected Resources

Many APIs require authentication to control who can access data and what they can do. Authentication proves your identity to the server, ensuring secure communication and preventing unauthorized access. Understanding different authentication methods is essential for working with modern web services.


🎯 Why Authentication Matters

Authentication serves several purposes:

  • **Security**: Only authorized users can access protected resources
  • **Rate Limiting**: Track usage per user or API key
  • **Accountability**: Know who accessed what and when
  • **Permissions**: Different users have different access levels
import requests

# Without authentication - likely fails
response = requests.get('https://api.example.com/private-data')
print(response.status_code)  # Probably 401 Unauthorized

# With authentication - succeeds
headers = {'Authorization': 'Bearer YOUR_TOKEN_HERE'}
response = requests.get('https://api.example.com/private-data', headers=headers)
print(response.status_code)  # 200 OK

🔑 API Key Authentication

The simplest form of authentication. You get a unique key and include it with each request.

API Key in Header

import requests

api_key = 'YOUR_API_KEY_HERE'

headers = {
    'X-API-Key': api_key
    # or 'Authorization': f'ApiKey {api_key}'
}

response = requests.get(
    'https://api.example.com/data',
    headers=headers
)

print(response.json())

API Key as Query Parameter

import requests

api_key = 'YOUR_API_KEY_HERE'

params = {
    'api_key': api_key
}

response = requests.get(
    'https://api.example.com/data',
    params=params
)

print(response.json())

Real-World Example: OpenWeatherMap API

import requests

api_key = 'YOUR_OPENWEATHERMAP_API_KEY'

response = requests.get(
    'https://api.openweathermap.org/data/2.5/weather',
    params={
        'q': 'London',
        'appid': api_key,
        'units': 'metric'
    }
)

if response.status_code == 200:
    weather = response.json()
    print(f"Temperature: {weather['main']['temp']}°C")
    print(f"Description: {weather['weather'][0]['description']}")
else:
    print(f"Error: {response.status_code}")

🎫 Bearer Token Authentication

Bearer tokens are commonly used for OAuth 2.0 and JWT (JSON Web Token) authentication.

Using Bearer Tokens

import requests

# Get token from login endpoint
login_response = requests.post(
    'https://api.example.com/login',
    json={
        'email': 'user@example.com',
        'password': 'password123'
    }
)

if login_response.status_code == 200:
    token = login_response.json()['token']

    # Use token for authenticated requests
    headers = {
        'Authorization': f'Bearer {token}'
    }

    response = requests.get(
        'https://api.example.com/user/profile',
        headers=headers
    )

    user = response.json()
    print(f"User: {user['name']}")
else:
    print("Login failed")

Handling Token Expiration

import requests
import time

class APIClient:
    def __init__(self, base_url, email, password):
        self.base_url = base_url
        self.email = email
        self.password = password
        self.token = None
        self.token_expiry = 0

    def refresh_token(self):
        """Get a new token"""
        response = requests.post(
            f'{self.base_url}/login',
            json={
                'email': self.email,
                'password': self.password
            }
        )

        if response.status_code == 200:
            data = response.json()
            self.token = data['token']
            self.token_expiry = time.time() + data.get('expires_in', 3600)
            return True

        return False

    def get_headers(self):
        """Get headers with valid token"""
        if time.time() >= self.token_expiry:
            self.refresh_token()

        return {
            'Authorization': f'Bearer {self.token}'
        }

    def get(self, endpoint):
        """Make authenticated GET request"""
        response = requests.get(
            f'{self.base_url}/{endpoint}',
            headers=self.get_headers()
        )

        if response.status_code == 401:
            # Token expired, refresh and retry
            self.refresh_token()
            response = requests.get(
                f'{self.base_url}/{endpoint}',
                headers=self.get_headers()
            )

        return response.json() if response.ok else None

# Using the client
client = APIClient(
    'https://api.example.com',
    'user@example.com',
    'password123'
)

user = client.get('user/profile')
if user:
    print(f"User: {user}")

🔐 Basic Authentication

Username and password sent with each request (usually over HTTPS).

import requests
from requests.auth import HTTPBasicAuth

username = 'john_doe'
password = 'secure_password'

# Method 1: Using HTTPBasicAuth
response = requests.get(
    'https://api.example.com/data',
    auth=HTTPBasicAuth(username, password)
)

# Method 2: Tuple shorthand
response = requests.get(
    'https://api.example.com/data',
    auth=(username, password)
)

# Method 3: Manual header (base64 encoded)
import base64

credentials = base64.b64encode(f'{username}:{password}'.encode()).decode()
headers = {
    'Authorization': f'Basic {credentials}'
}

response = requests.get(
    'https://api.example.com/data',
    headers=headers
)

print(response.json())

🔄 OAuth 2.0 Authentication

OAuth 2.0 is a standard for secure third-party authentication without sharing passwords.

OAuth 2.0 Authorization Code Flow

import requests
from urllib.parse import urlencode, parse_qs
from urllib.request import urlopen

class OAuth2Client:
    def __init__(self, client_id, client_secret, redirect_uri):
        self.client_id = client_id
        self.client_secret = client_secret
        self.redirect_uri = redirect_uri
        self.token = None

    def get_authorization_url(self, auth_url):
        """Generate URL for user to authorize"""
        params = {
            'client_id': self.client_id,
            'redirect_uri': self.redirect_uri,
            'response_type': 'code',
            'scope': 'read write'
        }
        return f"{auth_url}?{urlencode(params)}"

    def exchange_code_for_token(self, token_url, code):
        """Exchange authorization code for access token"""
        data = {
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'code': code,
            'redirect_uri': self.redirect_uri,
            'grant_type': 'authorization_code'
        }

        response = requests.post(token_url, data=data)

        if response.status_code == 200:
            self.token = response.json()['access_token']
            return True

        return False

    def get_with_token(self, resource_url):
        """Make authenticated request with token"""
        headers = {
            'Authorization': f'Bearer {self.token}'
        }

        response = requests.get(resource_url, headers=headers)
        return response.json() if response.ok else None

# Using OAuth 2.0
oauth = OAuth2Client(
    client_id='YOUR_CLIENT_ID',
    client_secret='YOUR_CLIENT_SECRET',
    redirect_uri='https://myapp.com/callback'
)

# Step 1: Direct user to authorization URL
auth_url = oauth.get_authorization_url('https://provider.com/oauth/authorize')
print(f"Visit: {auth_url}")

# Step 2: After user authorizes, you get code from redirect
code = 'AUTHORIZATION_CODE_HERE'

# Step 3: Exchange code for token
if oauth.exchange_code_for_token('https://provider.com/oauth/token', code):
    # Step 4: Use token to access resources
    user = oauth.get_with_token('https://api.provider.com/user')
    print(f"User: {user}")

🔒 Best Practices for Authentication

Store Credentials Safely

import os
from dotenv import load_dotenv

# Load from environment variables
load_dotenv()  # pip install python-dotenv

api_key = os.getenv('API_KEY')
api_secret = os.getenv('API_SECRET')

# ❌ Never hardcode credentials
# api_key = 'abc123def456'

# Make request with safe credentials
headers = {
    'X-API-Key': api_key
}

response = requests.get('https://api.example.com/data', headers=headers)

Create Reusable Authentication Classes

import requests
from typing import Dict, Optional

class AuthenticatedAPIClient:
    """API client with built-in authentication"""

    def __init__(self, base_url: str, auth_type: str, credentials: Dict):
        self.base_url = base_url
        self.auth_type = auth_type
        self.credentials = credentials
        self.session = requests.Session()
        self._setup_auth()

    def _setup_auth(self):
        """Configure session with authentication"""
        if self.auth_type == 'api_key':
            self.session.headers.update({
                'X-API-Key': self.credentials['api_key']
            })
        elif self.auth_type == 'bearer':
            self.session.headers.update({
                'Authorization': f"Bearer {self.credentials['token']}"
            })
        elif self.auth_type == 'basic':
            self.session.auth = (
                self.credentials['username'],
                self.credentials['password']
            )

    def get(self, endpoint: str, **kwargs) -> Optional[Dict]:
        """Make authenticated GET request"""
        try:
            response = self.session.get(
                f'{self.base_url}/{endpoint}',
                timeout=5,
                **kwargs
            )
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"Error: {e}")
            return None

    def post(self, endpoint: str, data: Dict, **kwargs) -> Optional[Dict]:
        """Make authenticated POST request"""
        try:
            response = self.session.post(
                f'{self.base_url}/{endpoint}',
                json=data,
                timeout=5,
                **kwargs
            )
            response.raise_for_status()
            return response.json()
        except requests.exceptions.RequestException as e:
            print(f"Error: {e}")
            return None

# Using the client with API key
client = AuthenticatedAPIClient(
    base_url='https://api.example.com',
    auth_type='api_key',
    credentials={'api_key': 'YOUR_API_KEY'}
)

data = client.get('users')

Handle 401 Unauthorized Gracefully

import requests

def make_authenticated_request(url, headers, max_retries=1):
    """Make request and handle 401 errors"""

    for attempt in range(max_retries):
        response = requests.get(url, headers=headers, timeout=5)

        if response.status_code == 401:
            print("Authentication failed. Check your credentials.")
            return None

        if response.status_code == 403:
            print("Authenticated but permission denied.")
            return None

        if response.ok:
            return response.json()

        print(f"Error: {response.status_code}")
        return None

    return None

# Usage
headers = {'Authorization': 'Bearer INVALID_TOKEN'}
data = make_authenticated_request('https://api.example.com/data', headers)

✅ Key Takeaways

MethodUse CaseExample
API KeySimple, public APIs`headers = {'X-API-Key': key}`
Basic AuthInternal APIs`auth=(username, password)`
Bearer TokenOAuth 2.0, JWT`Authorization: Bearer token`
OAuth 2.0Third-party servicesMulti-step authorization
Store SafelyAll methodsUse environment variables
Handle 401All methodsCheck credentials when unauthorized

🔗 What's Next?

Learn about rate limiting and how to work within API constraints.

Next: Rate Limiting →


Ready to practice? Try challenges or explore resources


Resources

Python Docs

Ojasa Mirai

Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.

Learn Deep • Build Real • Verify Skills • Launch Forward

Courses

PythonFastapiReactJSCloud

© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn