Skip to content

proxystore.globus

Globus OAuth tools.

ProxyStore provides the proxystore-globus-auth CLI tool to give consent to the ProxyStore Globus Application.

# basic authentication
proxystore-globus-auth
# delete old tokens
proxystore-globus-auth --delete
# give consent for specific collections
proxystore-globus-auth --collections COLLECTION_UUID COLLECTION_UUID ...
# specify additional scopes
proxystore-globus-auth --scopes SCOPE SCOPE ...

Based on Parsl's implementation and the Globus examples.

GlobusAuthFileError

Bases: Exception

Exception raised if the Globus Auth token file cannot be read.

load_tokens_from_file

load_tokens_from_file(
    filepath: str,
) -> dict[str, dict[str, Any]]

Load a set of saved tokens.

Source code in proxystore/globus.py
def load_tokens_from_file(filepath: str) -> dict[str, dict[str, Any]]:
    """Load a set of saved tokens."""
    with open(filepath) as f:
        tokens = json.load(f)

    return tokens

save_tokens_to_file

save_tokens_to_file(
    filepath: str, tokens: globus_sdk.OAuthTokenResponse
) -> None

Save a set of tokens for later use.

Source code in proxystore/globus.py
def save_tokens_to_file(
    filepath: str,
    tokens: globus_sdk.OAuthTokenResponse,
) -> None:
    """Save a set of tokens for later use."""
    with open(filepath, 'w') as f:
        json.dump(tokens.by_resource_server, f, indent=4)

authenticate

authenticate(
    client_id: str,
    redirect_uri: str,
    requested_scopes: Iterable[str] | None = None,
) -> globus_sdk.OAuthTokenResponse

Perform Native App auth flow.

Source code in proxystore/globus.py
def authenticate(
    client_id: str,
    redirect_uri: str,
    requested_scopes: Iterable[str] | None = None,
) -> globus_sdk.OAuthTokenResponse:
    """Perform Native App auth flow."""
    client = globus_sdk.NativeAppAuthClient(client_id=client_id)
    client.oauth2_start_flow(
        redirect_uri=redirect_uri,
        refresh_tokens=True,
        requested_scopes=requested_scopes,
    )

    url = client.oauth2_get_authorize_url()
    print(f'Please visit the following url to authenticate:\n{url}')

    auth_code = input('Enter the auth code: ').strip()
    return client.oauth2_exchange_code_for_tokens(auth_code)

get_authorizer

get_authorizer(
    client_id: str, tokens_file: str, redirect_uri: str
) -> globus_sdk.RefreshTokenAuthorizer

Get an authorizer for the Globus SDK.

Raises:

Source code in proxystore/globus.py
def get_authorizer(
    client_id: str,
    tokens_file: str,
    redirect_uri: str,
) -> globus_sdk.RefreshTokenAuthorizer:
    """Get an authorizer for the Globus SDK.

    Raises:
        GlobusAuthFileError: If `tokens_file` cannot be parsed.
    """
    try:
        tokens = load_tokens_from_file(tokens_file)
    except OSError as e:
        raise GlobusAuthFileError(
            f'Error loading tokens from {tokens_file}: {e}.',
        ) from e

    transfer_tokens = tokens['transfer.api.globus.org']
    auth_client = globus_sdk.NativeAppAuthClient(client_id=client_id)

    return globus_sdk.RefreshTokenAuthorizer(
        transfer_tokens['refresh_token'],
        auth_client,
        access_token=transfer_tokens['access_token'],
        expires_at=transfer_tokens['expires_at_seconds'],
        on_refresh=functools.partial(save_tokens_to_file, tokens_file),
    )

proxystore_authenticate

proxystore_authenticate(
    proxystore_dir: str | None = None,
    collections: list[str] | None = None,
    additional_scopes: list[str] | None = None,
) -> None

Perform auth flow for ProxyStore native app.

Source code in proxystore/globus.py
def proxystore_authenticate(
    proxystore_dir: str | None = None,
    collections: list[str] | None = None,
    additional_scopes: list[str] | None = None,
) -> None:
    """Perform auth flow for ProxyStore native app."""
    proxystore_dir = home_dir() if proxystore_dir is None else proxystore_dir
    tokens_file = os.path.join(proxystore_dir, _TOKENS_FILE)
    os.makedirs(proxystore_dir, exist_ok=True)

    scopes = _get_proxystore_scopes(collections, additional_scopes)

    tokens = authenticate(
        client_id=_APPLICATION_ID,
        redirect_uri=_REDIRECT_URI,
        requested_scopes=scopes,
    )
    save_tokens_to_file(tokens_file, tokens)

get_proxystore_authorizer

get_proxystore_authorizer(
    proxystore_dir: str | None = None,
) -> globus_sdk.RefreshTokenAuthorizer

Get an authorizer for the ProxyStore native app.

Source code in proxystore/globus.py
def get_proxystore_authorizer(
    proxystore_dir: str | None = None,
) -> globus_sdk.RefreshTokenAuthorizer:
    """Get an authorizer for the ProxyStore native app."""
    proxystore_dir = home_dir() if proxystore_dir is None else proxystore_dir
    tokens_file = os.path.join(proxystore_dir, _TOKENS_FILE)

    return get_authorizer(
        client_id=_APPLICATION_ID,
        tokens_file=tokens_file,
        redirect_uri=_REDIRECT_URI,
    )

main

main(argv: Sequence[str] | None = None) -> int

Perform Globus authentication.

This function is the entrypoint for the proxystore-globus-auth CLI tool.

Source code in proxystore/globus.py
def main(argv: Sequence[str] | None = None) -> int:
    """Perform Globus authentication.

    This function is the entrypoint for the `proxystore-globus-auth` CLI tool.
    """
    parser = argparse.ArgumentParser(
        'ProxyStore Globus Auth Tool',
        formatter_class=argparse.ArgumentDefaultsHelpFormatter,
    )
    parser.add_argument(
        '--collections',
        nargs='+',
        help='Collection UUIDs to request scopes for.',
    )
    parser.add_argument(
        '--scopes',
        nargs='+',
        help='Additional scopes to request.',
    )
    parser.add_argument(
        '--delete',
        action='store_true',
        help='Delete existing authentication tokens.',
    )
    args = parser.parse_args(argv)

    if args.delete:
        tokens_file = os.path.join(home_dir(), _TOKENS_FILE)
        if os.path.exists(tokens_file):
            os.remove(tokens_file)
            print('Deleted tokens file.')
            return 0
        else:
            print('No tokens file found.')
            return 1

    try:
        get_proxystore_authorizer()
    except GlobusAuthFileError:
        print(
            'Performing authentication for the ProxyStore Globus Native app.',
        )
        proxystore_authenticate(
            collections=args.collections,
            additional_scopes=args.scopes,
        )
        get_proxystore_authorizer()
        print('Globus authorization complete.')
        return 0
    else:
        print(
            'Globus authorization is already completed. To re-authenticate, '
            'delete your tokens (proxystore-globus-auth --delete) and try '
            'again.',
        )
        return 1