Token Storage

Fair Research Login automatically saves and loads tokens as needed to reduce the number of logins. This behavior can be further customized to suit an apps needs.

Simple Storage

Existing token storage objects exist and can be used if the customization needs are simple. JSONTokenStorage below can be used to store the tokens as JSON in a location of the user’s choice, in the example below the local location ‘mytokens.json’:

from fair_research_login import NativeClient

# Supported built-in storage mechanisms
from fair_research_login import JSONTokenStorage  # noqa

app = NativeClient(
    # Registered client on http://developers.globus.org
    client_id='7414f0b4-7d05-4bb6-bb00-076fa3f17cf5',
    token_storage=JSONTokenStorage('mytokens.json')
)

Advanced Storage

Further customizing the login behavior can be done by writing a new object that follows the protocol for storage. A custom storage object must have three methods that match the signatures below for write_tokens, read_tokens, and clear_tokens.

import json
import os
from fair_research_login import NativeClient


class MyTokenStorage(object):
    FILENAME = 'my_tokens.json'

    def write_tokens(self, tokens):
        """
        Write tokens to disk. 'tokens' above will be in this format:
        {
            'auth.globus.org': {
                'scope': 'openid profile email',
                'access_token': '<token>',
                'refresh_token': None,
                'token_type': 'Bearer',
                'expires_at_seconds': DEFAULT_EXPIRE,
                'resource_server': 'auth.globus.org'
            },
            <More Token Dicts>
        }
        Some configs, like ConfigParser on python 2.7, do not allow nested
        sections. In that case you can use these tools:

        from native_client.token_storage import flat_pack, flat_unpack
        """
        with open(self.FILENAME, 'w+') as fh:
            json.dump(tokens, fh, indent=2)

    def read_tokens(self):
        """
        Read and return tokens from disk. Returned tokens MUST be of the
        format below:
        {
            'auth.globus.org': {
                'scope': 'openid profile email',
                'access_token': '<token>',
                'refresh_token': None,
                'token_type': 'Bearer',
                'expires_at_seconds': DEFAULT_EXPIRE,
                'resource_server': 'auth.globus.org'
            },
            <More Token Dicts>
        }
        Note: This is the same format returned by the property:
        globus_sdk.auth.token_response.OAuthTokenResponse.by_resource_server

        No need to check expiration, that's handled by NativeClient.
        """
        try:
            with open(self.FILENAME) as fh:
                return json.load(fh)
        except Exception:
            return {}

    def clear_tokens(self):
        """
        Delete tokens from where they are stored. Before this method is called,
        tokens will have been revoked. This is both for cleanup and to ensure
        inactive tokens are not accidentally loaded in the future.
        """
        os.remove(self.FILENAME)


# Provide an instance of your config object to Native Client. The only
# restrictions are your client MUST have the three methods above,
# or it will throw an AttributeError.
app = NativeClient(client_id='7414f0b4-7d05-4bb6-bb00-076fa3f17cf5',
                token_storage=MyTokenStorage())