Reference Guide

This package provides functionality to authenticate/authorize requests sent to Envase services. It also provides classes that can be extended to support other services. The main goal is to provide classes that can be used as targets to the auth parameter in the Requests Library that handle the authentication/authorization process, as well as the refresh of access tokens, so that clients don’t need to worry about those operations.

The problem that this library tries to solve is the fact that most authentication libraries only care about the authentication negotiation, and enforce that client applications and services follow a predetermine sequence of calls to retrieve and refresh tokens. This causes that most applications and services completely separate the process of authenticating from the process of sending authenticated requests, and forces the implementation to pass authentication information all over the place just to make sure the interface needed is available.

The following pseudocode shows the problem:

Warning

The following snippet is pseudocode and will not execute. The code doesn’t show how to use this library.

import request
import third_party_auth as tpa

class AuthenticationService:
    def __init__(self, client_id, client_secret):
        self._client_id = client_id
        self._client_secret = client_secret
        self._token = None

    def get_access_token(self):
        # Use the client information to get the access token
        self._token = tpa.get_access_token(self._client_id, self._client_secret)
        return self._token.access_token

    def refresh_token(self):
        self._token = tpa.refresh_token(self._token)
        return self._token.access_token

# The client usually does something like this.

client_id = 'the-client-id'
client_secret = 'the-client-secret'
service = AuthenticationService(client_id, client_secret)
token = get_access_token(service)
response = send_request(service, token)

def get_access_token(service):
    return service.get_access_token()

def send_request(service, token):
    headers = {
        'Authorization': token
    }
    response = request.get('https://server.com/api, headers=headers)
    if response.status_code == http.HTTPStatusCodes.Forbidden:
        # Refresh and retry
        token = service.refresh_token()
        return send_request(service, token)
    return response.json()

The problem is that in most cases the function that retrieves the access token is far away from the function that sends the request, and the application needs to insure that the service and token are passed around, so that if the token has expired, it can be refreshed.

The solution is to encapsulate the process of retrieving and managing access tokens in a single class that insures the token is maintained valid. This library provides classes that solve this problem.

This library provides the concept of an IAuthorizer interface, which handles the full negotiation of tokens and their refresh when and if needed. The interface also takes care of updating request with the necessary information when needed. The following is pseudocode showing how the example above is solved with this library:

import en_core.data as data

client_info = data.ClientInfo('the-client-id', 'the-client-secret')
authorizer = SomeConcreteAuthorizer(client_info)
send_request(authorizer)

def send_request(authorizer):
    response = request.get('https://server.com/api, auth=authorizer)
    return response.json()

The implementation of IAuthorizer ensures the request is properly authorized before is sent to the server. It also takes care of refreshing the access token when needed. Client applications and services only need to worry about managing the life-time of the authorizer when needed.

Data Structures

en_auth.data

This module provides data structures and constants used during authentication.

AUTHORIZATION_HEADER

The standard Authorization header name.

API_KEY_HEADER

The common X-Api-Header name.

EXPIRATION_GAP

An expiration buffer used to insure that the access token doesn’t expire right after the expiration has been checked.

class ClientInfo(client_id: str, client_secret: str, api_key: str = '')

Data structure that contains the authentication/authorization parameters for a client. The structure also supports an optional api_key for clients that may require it.

Parameters
  • client_id (str) – Client id for authorization.

  • client_secret (str) – Client secret for authorization

  • api_key (str) – Optional API key parameter for clients that might require it.

to_basic_auth()

Returns a tuple of the client_id and client_secret that can be used as basic authentiation/authorization.

Returns

Basic authentication/authorization from the information specified.

class UserCredentials(user_name: str, password: str)

This class represents the credentials of a user that can be used with clients that require to log a user for authentication/authorization.

user_name

The user name required to log in.

password

The user password required to log in.

Base Classes

en_auth.base

This module provides base classes and general functionality to authorize HTTP requests. Base classes have been designed to be inherited and allow derived classes to implement a specific abstract interface to insure the correct functioning of the base classes.

class Authorizer(client_info)

Base class for Authorization object that implements the callable() interface to support instances to be target of the auth parameter of the exposed functions and Session objects in the Request python library.

This is an ABC (Abstract Base Class) that cannot be directly instantiated. Instead, users should use one of the provided authorizers, or implement their own by deriving from this class.

The class manages the life-time of authorization tokens by providing an abstract interface that derived classes must implement. Derived classes that implement the exposed abstract interface will inherit the functionality to insure that access tokens are retrieve and refreshed as needed.

The class requires the client information to be specified during contruction. Derived classes can extend their contruction to allow additional parameters, but they should initialize the client information parameter.

Parameters

client_info (ClientInfo) – Client information object that contains the id and secret of the client. It can also contain an optional API key.

__call__(request)

This method allows instances of this class to be used as the target to the auth parameter in the Request python library. The function takes the request from the library and adds the Authorization header, as well as the X-Api-Key header if it was provided in the client information.

Parameters

request (Request) –

Request object that will be processed by the Request library.

Returns

Returns the modified request.

property access_token

Provides the current access token. Client applications are not required to access this parameters to send calls. Instead, they will set the object as the value to the auth parameter on their call to Request

abstract authorize()

Derived classes must implement this method to return an object representing authorization token. This authorization token must expose an access_token property/attribute that contains the string value for the access token that will be included in the header.

The value returned by this function will be passed as parameters of the other abstract interface methods.

Returns

An authorization token object that contains the access_token

property client_id

Returns the client id specified in the client information during initialization.

Warning

Do not expose the client secret in this class unless you have a very good reason and you got approval to do it.

abstract expired(token)

This method must be implemented by derived classes to check if the specified token has expired. The function must return True if the token is expired or False otherwise.

abstract refresh(token)

This method must be implemented by derived classes to refresh the current token when the token has expired. The function takes the existing token as parameter, and should return a new refreshed token. The returned token must contain an access_token property.

OAuth2 Support

en_auth.oauth2

This module provides authorization classes for applications and services that use OAuth2 with the Envase authorization/authentication service.

Important

If your application or service is using this module, the requests library must be installed as a dependency. This library doesn’t install it to allow clients to select the authorizer type without installing unsued dependencies.

class ServiceAccountAuthorizer(client_info, environment, _test_client=None)

This authorizer handles the authorization negotiation for Envase clients using service accounts (client credentials). It implements the Authorizer interface that authorizes the client, and allows to refresh tokens when they expire.

The class is initialized with the client information and the environment indentifier for which to negotiate the token.

Parameters
  • client_info (ClientInfo) – Client information used to generate access tokens.

  • environment (str) – Environment identifier to know which pool to use for authentication.

The following example shows how this class can be used:

import en_auth.oauth2 as auth
import en_auth.data as data
import requests

config = get_config()
client_id = config.get('CLIENT_ID')
client_secret = config.get('CLIENT_SECRET')
environment = config.get('ENVIRONMENT')

client_info = data.ClientInfo(client_id, client_secret)
authorizer = auth.ServiceAccountAuthorizer(client_info, environment)

response = requests.get('https://envase.protected.url.com/api/resource', auth=authorizer)

Provided that client id and secret are valid for client credentials, the request will be authorized regardless of the status of authentication. The authorizer will handle the necessary negotiation to retrieve or refresh access tokens, so that the application doesn’t need to worry about that process.

authorize()

Generates a token containing the access_token required for authorized requests.

Returns

Token object that contains the access_token used for authorization.

expired(token)

Returns whether the token is expired or not.

Parameters

token (Token) – The token retrieved from authorize() during authorization.

Returns

True if the token has expired or False otherwise.

refresh(_not_used_token)

Generates a new token that can be used for authentication.

Parameters

token (Token) – The token retrieved from authorize() during authorization. This implementation does not use the token parameter.

Returns

A new token object that contains the access_token used for authorization.

SRP Support

en_auth.srp

This module implements the Authorizer interface to use SRP the (Secure Remote Password) negotiation protocol with a Cognito AWS instance. Trusted clients enabled for SRP can use this authorizer to log in a user and gain an access token required for subsequent calls to Envase services.

Important

If your application or service is using this module, it needs to add the pycognito library as a dependency. This library doesn’t install the dependency to allow client applications and services to select the appropriate authorization protocol without installing unused dependencies.

class SrpAuthorizer(client_info, credentials, environment, _test_client=None)

This authorizer handles the authorization negotiation using the SRP (Secure Remote Password) protocol. The SRP protocol allows an application to log in a user with the authorization/authentication system and provide its identity information in the access token.

Envase applications and services that require access to user owned resources can use this protocol to retrieve the access token. This class will take care of renewing tokens when necessary.

The class is initialized using the ClientInfo for the client and the Credentials of the user. The class also requires to specified the environment for which the application will require authentication.

Parameters
  • client_info (ClientInfo) – Client information (client id and secret) for the application or service initiating authentication.

  • credentials (Credentials) – User information for the user to log in.

  • environment (str) – Environment identifier for the environment to which the application will authenticate.

The following example shows how this class can be used:

import en_auth.srp as auth
import en_auth.data as data
import requests

config = get_config()
client_id = config.get('CLIENT_ID')
client_secret = config.get('CLIENT_SECRET')
user_name = config.get('USER_NAME')
pwd = config.get('USER_PWD')
environment = config.get('ENVIRONMENT')

client_info = data.ClientInfo(client_id, client_secret)
credentials = data.Credentials(user_name, pwd)
authorizer = auth.SrpAuthorizer(client_info, credentials, environment)

response = requests.get('https://envase.protected.url.com/api/resource', auth=authorizer)
authorize()

Generates a token containing the access_token required for authorized requests.

Returns

A token object that exposes the access token.

expired(token)

Returns whether the token is expired or not.

Parameters

token (Token) – The token retrieved from authorize() during authorization.

Returns

True if the token has expired or False otherwise.

refresh(_not_used_token)

Refreshes the token and returns it, so authorized requests can continue.

Parameters

token (Token) – The token retrieved from authorize() during authorization.

Returns

A new refreshed token that can be use during authorization.

report_invalid_client()

Raises an InvalidClientError. This method is for internal puposes only and client applications should not call the method.

report_invalid_credentials()

Raises an InvalidCredentialsError. This method is for internal puposes only and client applications should not call the method.

report_unknown_aws_error(status_code, message)

Raises an AuthorizationError. This method is for internal puposes only and client applications should not call the method.

Exceptions

en_auth.exceptions

This module provides the exceptions that will be raised during the authentication/authorization process. Classes that extend the functionality of this library should use the exceptions provided on this module.

exception AuthorizationError(status_code, message)

This exception is raised when the authorization/authentication process cannot be completed for unknown reasons. The class exposes information about what happened as the message, as well as the status code returned by the authorization service.

Parameters
  • status_code (int) – The status code returned by the authorization service.

  • message (str) – Information provided by the authorization service.

exception InvalidClientError(client_info)

This exception is raised when the client information provided is not valid for authentication/authorization.

Parameters

client_info (ClientInfo) – The client information that caused the problem.

exception InvalidCredentialsError(credentials)