Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
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
service_accounts/index
17 changes: 17 additions & 0 deletions docs/user_guide/usage_patterns/service_accounts/index.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.. _userguide_service_accounts:

Service Accounts
================

"Service Accounts" or "Client Identities" (the terms are synonymous) are
automated users which authenticate with Globus via client credentials.
Using this type of credential allows for automated usage of Globus services
which does not rely on user interaction or login flows.

.. toctree::
:caption: Using Service Accounts with the SDK
:maxdepth: 1

understanding_service_accounts
registering_a_service_account
using_client_app/index
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
.. _userguide_register_service_account:

Registering a Service Account
=============================

In order to be used as a Service Account or "Client Identity", 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
-------------------

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,67 @@
.. _userguide_understanding_service_accounts:

Understanding Service Accounts
==============================

Some clients registered in Globus may operate as independent "service accounts",
distinct actors with their own identities.
These are also referred to as "client identities" because the actor in question
is the client itself.
Service accounts useful for a wide range of automation tasks, in which users
want to leverage Globus APIs, but without handling login flows and user
credentials.

Service Accounts are Clients
----------------------------

To create a service account, users must register a new Globus Auth client 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's :class:`globus_sdk.GlobusApp` and
:class:`globus_sdk.ClientCredentialsAuthorizer` will automatically cache and
reload these tokens appropriately.

.. note::

In order to be used as a Service Account, 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.


Disambiguation: "Clients" vs "Client Identities" vs "Service Accounts"
----------------------------------------------------------------------

There are two different meanings for the word "client", from different domains.

Conventionally, a library's adapter for a web API is a "client".
In the SDK, we primarily use the word "client" to refer to these API connectors,
as in ``TransferClient``, ``GroupsClient``, etc.

OAuth2 calls an application registered with the service a "client".
A "Client Identity" is a Globus Auth concept which uses this meaning of
"client".

As a result of this ambiguity, this documentation will prefer to refer to
"Client Identities" as "Service Accounts", which is the term which is used in
other Globus documentation and the web interface.


Service Account Permissions
---------------------------

Service Accounts have their own assigned identities, group memberships, and
permissions within Globus.
They are not implicitly linked in any way to the user who created them, or the
administrators who manage them.
Their permissions are isolated.

Users of Service Accounts need to separately assign permissions to these
identities, depending on what resources the client is meant to access.
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,97 @@
.. _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,

- a human readable name to identify your app in HTTP requests and token caching (e.g., "My Cool Weathervane").
- this does not need match the name you supplied during client registration.
- 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