Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions docs/user_guide/usage_patterns/client_identities/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.. _userguide_client_identities:

Using Client Identities
Comment thread
sirosen marked this conversation as resolved.
Outdated
=======================
Comment thread
sirosen marked this conversation as resolved.
Outdated

Clients registered in Globus can be used as "service accounts",
Comment thread
sirosen marked this conversation as resolved.
Outdated
distinct actors with their own identities.
This is useful for a wide range of automation tasks, in which users want to
leverage Globus APIs, but without handling login flows and user credentials.
Comment thread
sirosen marked this conversation as resolved.
Outdated

To make use of Client Identities in this way, the client must be registered as a
"service account", capable of performing a *client credentials grant* to get
its tokens.
Once it is so registered, such a client will have an ID and secret, which can be
passed into interfaces in the SDK.
The client credentials (ID and secret) are used to get tokens to power
interactions with Globus APIs, and SDK tools will automatically cache and reload
Comment thread
sirosen marked this conversation as resolved.
Outdated
these tokens appropriately.

.. note::

In order to be used as a Client Identity, a client must have an ID and secret.
However, not every client with an ID and secret supports this usage! Clients
may be registered with various different OAuth2 grant types enabled, and some
clients have an ID and secret but are used to authenticate user logins!

Put another way: having client credentials is *necessary but not sufficient*
for this kind of usage.

.. toctree::
:caption: Using Client Identities with the SDK
:maxdepth: 1

registering_a_client_identity
using_client_app/index
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
.. _userguide_register_client_identity:

Registering a Client Identity
=============================

In order to be used as a Client Identity or "service account", a client must
be registered in Globus Auth under the correct type.

This is similar to the
:ref:`getting started documentation on registering an app <tutorial_register_app>`,
but using some different settings.

Creating the Client Identity
----------------------------

The following steps will walk you through how to register a client for use as a
service account.
One topic not covered here is how to securely store and manage your secrets --
the guidance below will simply say "save", and it is the user's responsibility
to decide how to save and secure these credentials.

1. Navigate to the `Developer Site <https://app.globus.org/settings/developers>`_

2. Select "Register a service account or application credential for automation"

3. Create or Select a Project

* A project is a collection of apps with a shared list of administrators.
* If you don't own any projects, you will automatically be prompted to create one.
* If you do, you will be prompted to either select an existing or create a new one.

4. Creating or selecting a project will prompt you for another login, sign in with an
account that administers your project.

5. Give your App a name. This will appear as the identity's "name" where a
user's full name might appear.

6. Click "Register App". This will create your app and take you to a page
describing it.

7. Copy the "Client UUID" and save it -- this is your ``client_id`` in the
Python SDK's terms.

8. Click "Add Client Secret", fill in the label, and save the secret -- this is
your ``client_secret`` in the Python SDK's terms.


Saving and Retrieving Client IDs and Secrets
--------------------------------------------

The Globus SDK does not offer special capabilities for storage and retrieval of
client IDs and client secrets.

In examples in SDK documentation, you will see the client ID and secret written
as hardcoded constants, e.g.

.. code-block:: python

import globus_sdk

CLIENT_ID = "YOUR ID HERE"
CLIENT_SECRET = "YOUR SECRET HERE"

client = globus_sdk.ConfidentialAppAuthClient(CLIENT_ID, CLIENT_SECRET)

You can replace those variables with sources of your choice.
For example, you could make them environment variables:

.. code-block:: python

import os

CLIENT_ID = os.getenv("CLIENT_ID")
CLIENT_SECRET = os.getenv("CLIENT_SECRET")

if not (CLIENT_ID and CLIENT_SECRET):
raise RuntimeError("CLIENT_ID and CLIENT_SECRET must both be set.")

Selecting an appropriate storage and retrieval mechanism for client credentials
is considered a user responsibility by the SDK.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import globus_sdk

# your client credentials
CLIENT_ID = "YOUR ID HERE"
CLIENT_SECRET = "YOUR SECRET HERE"

# the ID of "tutorial collection 1"
TUTORIAL_COLLECTION = "6c54cade-bde5-45c1-bdea-f4bd71dba2cc"

# create a ClientApp named "app"
with globus_sdk.ClientApp(
"sample-app",
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
config=globus_sdk.GlobusAppConfig(token_storage="memory"),
) as app:
# create a TransferClient named "tc", bound to "app"
with globus_sdk.TransferClient(app=app) as tc:

# because the tutorial collection is of a type which uses a `data_access`
# scope for fine grained access control, the `data_access` requirement needs
# to be registered with the app
tc.add_app_data_access_scope(TUTORIAL_COLLECTION)

# iterate over the listing results, printing each filename
for entry in tc.operation_ls(TUTORIAL_COLLECTION, path="/home/share/godata"):
print(entry["name"])
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
.. _userguide_using_client_app:

Using a ClientApp with a Service Account
========================================

Once you have a client ID and secret from an app registration for a service
account, the SDK has a few tools which can use those credentials to acquire
tokens, to talk to various Globus Services.

The easiest tool for this job is a ``ClientApp``, a flavor of ``GlobusApp``
designed to work with service accounts.

Instantiating a ClientApp
-------------------------

Constructing an app takes three required parameters,

- the name of the app for use in the SDK (this does not have to match your registered client name)
Comment thread
sirosen marked this conversation as resolved.
Outdated
- the client ID
- the client secret

as in:

.. code-block:: python

import globus_sdk

CLIENT_ID = "YOUR ID HERE"
CLIENT_SECRET = "YOUR SECRET HERE"

app = globus_sdk.ClientApp(
"sample-app",
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
)

Using the App with a Globus Service
-----------------------------------

The resulting app can then be passed to any SDK client class to create an API
client object which uses the app for authentication requirements.
For example, to use the ``app`` object to run an ``ls`` on one of the tutorial
collections:

.. code-block:: python

TUTORIAL_COLLECTION = "6c54cade-bde5-45c1-bdea-f4bd71dba2cc"

with globus_sdk.TransferClient(app=app) as tc:
tc.add_app_data_access_scope(TUTORIAL_COLLECTION)
ls_result = tc.operation_ls(TUTORIAL_COLLECTION, path="/home/share/godata")

.. note::

Unfortunately, there are two different meanings of the word "client" in use
in this example!

A ``TransferClient`` is a "client" in the sense that it is a local object
which provides access to the Globus Transfer Service.
The ``CLIENT_ID``, ``CLIENT_SECRET``, and ``ClientApp`` are all using the
word "client" in reference to the OAuth2 standard's definition of a "client"
as a registered app, a different meaning for the same word.

Using Memory Storage
--------------------

Unlike user logins, client credentials can't be "logged out" vs "logged in" --
unless they are deleted via the Globus Auth service, they are always active.

As a result, unlike applications which provide user logins, ``ClientApp``\s will
very often prefer to store any tokens they are using in memory. The tokens will
be cached and reused over the lifetime of the process, but never persisted to
disk.

To configure an app in this way, simply add a ``config`` to the app
initialization to select the ``"memory"`` storage type:

.. code-block:: python

app = globus_sdk.ClientApp(
"sample-app",
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
config=globus_sdk.GlobusAppConfig(token_storage="memory"),
)

Complete Example
----------------

In addition to leveraging all of the elements described above, this example enhances the code sample to
use the ``ClientApp``'s context manager interface to close token storage.
We also add a loop of ``print()`` usages on the ``ls`` result to show some output:

.. literalinclude:: client_app_ls.py
:caption: ``client_app_ls.py`` [:download:`download <client_app_ls.py>`]
:language: python
1 change: 1 addition & 0 deletions docs/user_guide/usage_patterns/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ transfers.

data_transfer/index
sessions_and_consents/index
client_identities/index
Loading