External authorization

A Mesh server may be protected by an external authorization server, where the clients like Python SDK authenticate and request access tokens. Tokens obtained from the external authorization server are then sent in the Authorization header when making a call to the Mesh API.

This is required by the Mesh server if OAuth is enabled for the gRPC interface in the Mesh configuration file.

For security reasons authentication also requires TLS to be enabled, and you might therefore need Mesh’s TLS certificate in the below examples.

Token format

Mesh supports OAuth 2.0 JSON Web Token (JWT) access tokens. They need to meet the following requirements:

  • The access token signed using RSA algorithm.

  • Authorization is done using roles claim that must be part of the access token.

  • User’s claims: name and oid must be part of the access token.

Azure Active Directory (Azure AD) supports all OAuth 2.0 flows.

Example

from volue import mesh

# Most certificates won't work with IP addresses, therefore
# you'll need to be able to resolve the Mesh server by name,
# either through your DNS configuration, or through /etc/hosts.
with open("certificate.pem", "rb") as f:
    certificate = f.read()

token = "my_access_token"  # obtain it from authorization server

# mesh.domain.com is the address of the Mesh server.
connection = mesh.Connection.with_external_access_token(
    "mesh.domain.com:50051", certificate, token
)
print(connection.get_user_identity())

For more complex example please refer to connect_using_external_access_token.py:

from datetime import datetime

import helpers

from volue.mesh import Connection


def main(address, tls_root_pem_cert):
    """
    Showing how to authorize to gRPC Mesh server using externally obtained
    access token, e.g: a OAuth JWT. Obtaining the access token is out of scope
    for this example.

    Depending on your environment, e.g.: Azure AD, using libraries like
    Microsoft Authentication Library (MSAL) for getting the tokens is
    suggested.
    """

    token = "my_token"
    connection = Connection.with_external_access_token(
        address, tls_root_pem_cert, access_token=token
    )

    with connection.create_session() as session:
        # Print user information contained in the access token.
        user_identity = connection.get_user_identity()
        print(user_identity)

        # Read some time series data.
        # This requires the user has time series read permissions.
        timeseries_key = 1388
        timeseries = session.read_timeseries_points(
            timeseries_key, datetime(2014, 1, 1), datetime(2015, 1, 1)
        )
        print(timeseries.arrow_table.to_pandas())

        # For long running sessions it may be necessary to refresh the access
        # token.
        # Other possibility would be to catch grpc.RpcError with status code
        # UNAUTHENTICATED and then get new access token and update it in the
        # Mesh connection using `update_external_access_token`.
        connection.update_external_access_token("my_new_access_token")


if __name__ == "__main__":
    # This requires Mesh server to be running with enabled TLS and OAuth options.
    # Obtaining access token is out of the scope for this example.

    address, tls_root_pem_cert = helpers.get_connection_info()
    # main(address, tls_root_pem_cert)

Internals

Mesh validates access tokens that are sent with every call to the server. Validation means checking token’s:

  • RSA signature

  • integrity - to make sure no one tampered with it

  • expiration time

  • claims like audience, scope, etc.

Additionally it checks if user is permitted to access given API by checking the roles claim in the access token.

Access tokens have an expiration time, after which they’re no longer valid, and a new access token is required. To provide new access token create either a new connection or use volue.mesh.Connection.update_external_access_token().