Python > Web Development with Python > Working with APIs > API Authentication

API Authentication with OAuth 2.0 (Authorization Code Grant)

This snippet provides a conceptual outline of how to implement OAuth 2.0's Authorization Code Grant flow in Python. It focuses on the interaction between your application, the user, and the authorization server. A full implementation requires more complex code and might rely on specific OAuth 2.0 client libraries.

OAuth 2.0 Authorization Code Grant Flow

OAuth 2.0 allows third-party applications to obtain limited access to an HTTP service, either on behalf of a resource owner (user) or by allowing the third-party application to obtain access on its own behalf. The Authorization Code Grant flow is a common OAuth 2.0 flow suited for web applications. It involves redirecting the user to the authorization server, obtaining an authorization code, and then exchanging that code for an access token.

Step 1: Redirect User to Authorization Server

Construct the authorization URL, including your client ID, redirect URI, response type (code), and desired scopes. The user is then redirected to this URL (typically using a browser redirect). Replace YOUR_CLIENT_ID and YOUR_REDIRECT_URI with your actual client ID and redirect URI registered with the authorization server.

import webbrowser

CLIENT_ID = 'YOUR_CLIENT_ID'
REDIRECT_URI = 'YOUR_REDIRECT_URI'
AUTHORIZATION_ENDPOINT = 'https://example.com/oauth2/authorize'

authorization_url = f'{AUTHORIZATION_ENDPOINT}?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&scope=read'
webbrowser.open(authorization_url)

Step 2: Handle the Callback and Authorization Code

After the user authorizes your application, the authorization server redirects the user back to your application's redirect URI with an authorization code in the query parameters. Your application needs to handle this callback and extract the authorization code.

Step 3: Exchange Authorization Code for Access Token

Make a POST request to the token endpoint, providing the authorization code, redirect URI, client ID, and client secret. The authorization server validates these credentials and, if valid, returns an access token. Replace YOUR_CLIENT_SECRET with your actual client secret, and THE_AUTHORIZATION_CODE_FROM_THE_REDIRECT_URI with the authorization code you received.

import requests

TOKEN_ENDPOINT = 'https://example.com/oauth2/token'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
AUTHORIZATION_CODE = 'THE_AUTHORIZATION_CODE_FROM_THE_REDIRECT_URI'

data = {
    'grant_type': 'authorization_code',
    'code': AUTHORIZATION_CODE,
    'redirect_uri': REDIRECT_URI,
    'client_id': CLIENT_ID,
    'client_secret': CLIENT_SECRET
}

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

if response.status_code == 200:
    token_data = response.json()
    access_token = token_data['access_token']
    print(f'Access Token: {access_token}')
else:
    print(f'Error: {response.status_code}')
    print(response.text)

Step 4: Use the Access Token to Access Protected Resources

Include the access token in the Authorization header using the Bearer scheme when making requests to protected resources. The server validates the access token and, if valid, returns the requested data.

PROTECTED_RESOURCE_ENDPOINT = 'https://example.com/api/resource'

headers = {
    'Authorization': f'Bearer {access_token}'
}

response = requests.get(PROTECTED_RESOURCE_ENDPOINT, headers=headers)

if response.status_code == 200:
    resource_data = response.json()
    print(resource_data)
else:
    print(f'Error: {response.status_code}')
    print(response.text)

Simplified Complete Code Snippet (Conceptual)

This code combines the steps for demonstrative purposes. A full implementation needs robust callback handling and secure token storage.

# Note: This is a simplified outline.  A full implementation requires handling the callback, storing tokens securely, and error handling.

import webbrowser
import requests

CLIENT_ID = 'YOUR_CLIENT_ID'
CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
REDIRECT_URI = 'YOUR_REDIRECT_URI'
AUTHORIZATION_ENDPOINT = 'https://example.com/oauth2/authorize'
TOKEN_ENDPOINT = 'https://example.com/oauth2/token'
PROTECTED_RESOURCE_ENDPOINT = 'https://example.com/api/resource'

# 1. Redirect user to authorization server
authorization_url = f'{AUTHORIZATION_ENDPOINT}?client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&response_type=code&scope=read'
webbrowser.open(authorization_url)

# 2. (In a real application, handle the callback and extract the authorization code)
# For demonstration, assume the authorization code is 'AUTHORIZATION_CODE'
AUTHORIZATION_CODE = 'AUTHORIZATION_CODE'

# 3. Exchange authorization code for access token
data = {
    'grant_type': 'authorization_code',
    'code': AUTHORIZATION_CODE,
    'redirect_uri': REDIRECT_URI,
    'client_id': CLIENT_ID,
    'client_secret': CLIENT_SECRET
}
response = requests.post(TOKEN_ENDPOINT, data=data)
token_data = response.json()
access_token = token_data['access_token']

# 4. Use the access token to access protected resources
headers = {
    'Authorization': f'Bearer {access_token}'
}
response = requests.get(PROTECTED_RESOURCE_ENDPOINT, headers=headers)
resource_data = response.json()
print(resource_data)

Concepts Behind the Snippet

OAuth 2.0 is an authorization framework that enables third-party applications to obtain limited access to an HTTP service. It provides a secure way for users to grant access to their resources without sharing their credentials directly with the application. The Authorization Code Grant is one of the most common OAuth 2.0 flows, particularly suited for web applications. It involves a series of redirects and token exchanges to obtain an access token.

Real-Life Use Case

When you log in to a website using your Google or Facebook account, you're likely using OAuth 2.0. The website redirects you to the Google or Facebook authorization server, where you grant permission to access your profile information. After authorization, the website receives an access token that allows it to retrieve the authorized information from Google or Facebook without ever knowing your password.

Best Practices

  • Securely store client secrets and access tokens. Never hardcode them into your client-side code.
  • Validate the redirect URI to prevent authorization code interception attacks.
  • Use HTTPS for all communication with the authorization server and API endpoints.
  • Implement refresh tokens to allow your application to obtain new access tokens without requiring the user to re-authorize.
  • Use a dedicated OAuth 2.0 client library. These libraries handle many of the complexities of the protocol.

Interview Tip

Demonstrate a clear understanding of the OAuth 2.0 flow and its different grant types. Explain the importance of security considerations like secure token storage and redirect URI validation. Be prepared to discuss the trade-offs between different grant types and their suitability for different application types.

When to Use Them

OAuth 2.0 is appropriate when building web applications, mobile apps, or server-side applications that need to access protected resources on behalf of a user or on their own behalf. It is particularly useful when integrating with third-party APIs that require delegated authorization.

Memory Footprint

The memory footprint depends largely on the OAuth 2.0 library used, but in general it's not substantial. The most important data is the access token, which is typically a short string. Libraries might store additional metadata, but the overall memory usage is usually minimal.

Alternatives

  • JWT (JSON Web Tokens): Useful for stateless authentication and authorization, particularly in microservice architectures.
  • OpenID Connect: Built on top of OAuth 2.0, providing identity verification and user profile information.
  • API Keys: Suitable for simple APIs with lower security requirements.

Pros

  • More secure than API keys.
  • Allows delegated authorization.
  • Widely adopted and supported.

Cons

  • More complex to implement than API keys.
  • Requires interaction with an authorization server.
  • Can introduce additional latency due to redirects and token exchanges.

FAQ

  • What is the purpose of the 'scope' parameter in the authorization URL?

    The scope parameter specifies the level of access that the application is requesting. It allows the user to grant only specific permissions, rather than granting access to all of their data.
  • How do I handle refresh tokens in OAuth 2.0?

    When exchanging the authorization code for an access token, the authorization server may also return a refresh token. This refresh token can be used to obtain a new access token without requiring the user to re-authorize the application. Store refresh tokens securely and use them to automatically refresh access tokens when they expire.
  • What is the difference between 'client_id' and 'client_secret'?

    The client_id is a public identifier for your application. The client_secret is a confidential secret that is used to authenticate your application with the authorization server. The client secret must be kept confidential and never exposed to unauthorized parties.