1. Introduction

The purpose of Sessions in Globus Auth is to allow services to provide higher levels of access restrictions by determining which of the identities in a user’s identity set have been used to authenticate and when, which the service can use to make access control decisions based on that information.

The use of Sessions allows services to guarantee that a user has authenticated with a specific identity within some period of time, and can prevent an attacker from gaining access to higher-assurance resources by compromising a linked identity.

1.1. Sessions at a Glance

When a service receives a request using an access token, the service can retrieve information about the token (introspection) to determine which specific identities the user has authenticated with in the current session.

If the service determines that the user has not authenticated with an identity that permits the operation, but that another of the user’s linked identities would permit operation, the service can return an error to the app that made the request.

The app can then use the error response from the service to construct an authorization URL for Globus Auth and redirects the user to it. Globus Auth will the prompt the user to authenticate using the identity that will allow access.

The user is then redirected back to the app with an authorization code which the app can exchange for new access tokens, just like a normal authorization flow. The app repeats the request with a new token, and when the service introspects this new token it determines that the user has authenticated with the necessary identity and processes the request.

1.2. Definition of a Globus Auth Session

A Session in Globus Auth has a set of tokens and authentications, and is identified by a session context. The session context is typically a particular app (end-user OAuth client) and a particular browser. For example, these are all separate sessions for the same user:

  1. User logs into App A on Firefox on their laptop.

  2. User logs into App A on Chrome on their laptop.

  3. User logs into App B on Chrome on their laptop.

An authentication only belongs to a Session if it’s made within the full session context. For example:

User logs into App A in their browser. They are not yet logged in to Globus Auth, so they authenticate with their GlobusID identity. The tokens returned to App A will be tied to a Session that reflects the GlobusID authentication. User logs into App B in the same browser. The user is already logged into Globus Auth, and therefore does not need to authenticate with an Identity Provider again. The tokens returned to App B will be tied to a empty session, reflecting no authentications, since no additional authentication was necessary.

Further, only authentications for 3-legged OAuth flows are added to sessions. Tokens derived from a 2-legged flow (Client Credentials or Username/Password grant) will always have an empty session. Direct logins (e.g., for the Consents page in Globus Auth) are also not added to client Sessions.

All derived tokens (i.e., from Refresh Token or Dependent Token Grants) belong to the same session as the "parent" token. Therefore sessions can be used to trace the origin of any token belonging to a Session. For instance, a dependent token which is derived from another dependent token could be traced back to a particular (set of) authentication(s).

1.2.1. Session Lifecycle

First some terminology:

A Session is open whenever it is possible to add new authentications to it. A Session is closed whenever it is no longer possible to add new authentications to it.

A new session is implicitly opened whenever a user logs into an app and there is no currently open session. It becomes closed whenever:

  • The user quits their browser. Note that this means that Globus Auth can not reliably tell whether a Session is currently open or closed, in the sense used here.

  • The user logs out of Globus Auth.

  • The user logs into a different account (identity set) in the same browser.

There is no time-out of Sessions. Potentially a user can keep their browser open and stay logged into the same account forever. Further, refresh tokens allows clients to keep getting access tokens belonging to the same Session indefinitely.

Authentications for a given identity are never removed from a Session, except when the user unlinks that identity.

2. Sessions For Service Developers

When a service receives a request using an access token it has not previously seen, it should use token introspection to determine the session information (and other information) associated with the token. The session information associated with a given access token is immutable, and unlinking an identity will cause any token which contains the identity as part of its session information to be revoked.

The service can then determine, based on the introspection result and its own access policies, whether to grant access. If the authentication information in the session of the current token is not sufficient to grant access, but that the user could gain access if they (re-)authenticate with a particular linked identity. Then the service should construct an error that allows the calling client to redirect the user to Globus Auth with the necessary information.

The client can then initiate a new authorization flow, at the end of which the calling client will be given a new access token with which to repeat the denied request. The session information associated with this new access token will reflect new authentications done during the authorization flow.

If the service has access control rules for long running jobs that requires the user to have authenticated with some particular identity within a given amount of time for the entire duration of the job, the service may also need to periodically use Globus Auth to prompt the user to refresh their session.

Services should be aware that users can have multiple sessions at the same time, even for the same app. As such, each previously unseen access token should be evaluated independently.

2.1. Getting Session Information via Token Introspection

Services wishing to find out session information about a token can call the introspect endpoint with the POST include parameter session_info. The response will then include session information using the following format:

"session_info" : {
    "session_id" : <uuid>,
    "authentications" : {
        <identity_id1> : {
            "auth_time" : <seconds-since-epoch>,
            "idp": <idp-id>,
        }, <identity_id2> : {...}
    }
}

Only the most recent authentication for a particular identity is included. The session information associated with a token is immutable; existing tokens will not be updated to reflect new authentications. Tokens issued through either the implicit, authorization code, refresh token, or dependent token grant will reflect the sessions information at time of issuance.

Session ID is included for logging/debugging purposes, and may be used for other purposes such as tracking a session across multiple API calls. However, clients/services don’t need to care about it.

2.2. Unlinking

The only situation in which an identity/authentication is ever removed from an open session is if the user unlinks an identity.

If an identity is unlinked, any currently active access tokens belonging to a session in which the identity has authenticated (such that services may have made access control decisions based upon it) are revoked. Any subsequently issued access tokens belonging to that session will not reflect any authentications made by the unlinked identity.

3. Sessions For App Developers

If an app knows that in order for a user to access a particular resource they first need to authenticate with a particular identity, it can construct an authorization URL that will make Globus Auth prompt the user for that particular authentication. At the end of the authorization flow, the app will receive a new set of access tokens with updated session information.

However, oftentimes the app cannot know ahead of time which authentications will be necessary for a particular request. Requirements may differ between different sub-resources (dependent services) as well as over time. Therefore apps also need to be able to process certain error responses from services, that can be used to construct the aforementioned authorization URLs.

Developers of native apps will also need to bootstrap an app instance, which after that works exactly as any other app with respect to sessions.

4. Required Error Format from Services

When a service returns a permission error related to the session, the error must include the parameters that the calling client will need to construct an appropriate authorization URL, as described below.

This is required for interoperability, so that apps can process session-related errors from different services in the same way.

For services returning JSON responses over HTTP the status code must be 403, and the error body must contain the key "authorization_parameters", which points to an object containing parameters that the top level client can use to construct an authorization URL. For example:

{
    "authorization_parameters" : {
            "session_message": <message-for-end-user>,
            "session_required_identities": <list-of-identity-ids>
}

Services may also include whatever additional parameters they wish.

In the case of nested (dependent) services (e.g., an app calls Service A which calls Service B, which returns a session-related error) the authorization_parameters part of the error should be returned unchanged all the way to the top level app.

5. Client-initiated Authentications

Clients that need the user to add some authentication to their session to gain access to a protected resource can do so by initiating an OAuth2 authorization flow and including some special query parameters to the authorization endpoint, in addition to the normally used authorization parameters (scopes, redirect URLs, etc). These query parameters are:

  • session_message=<text-message>

    • Globus Auth will display the message to the user.

    • E.g., "To gain access you need to authenticate with your UChicago identity".

  • session_required_identities=<list-of-identity-ids>

    • Globus Auth will prompt the user to authenticate with all of the listed identities before sending them back to the client.

      • If the user has already authenticated with all listed identities in the current session, the call behaves as any other other authorization call (i.e., either directly sending the user back to the redirect_uri or prompting for consent).

    • All listed identities must be a part of the same identity set/account. Requesting identities from different sets is an error.

    • If the client requests identities from an account other than the one the user is currently logged in to Auth as (for example if the user uses different accounts for different apps), the user will be automatically logged out before authenticating to any of the required identities.

  • prompt=login

    • The user will be prompted to re-authenticate even if they have already authenticated with a particular identity in the current session, so that services can enforce their own "freshness" requirements on the session.

Because this flow is stateless (in the REST sense of the word) clients should leverage the state query parameter, which will be returned unchanged to the client, to remember what the user was trying to do before getting sent off.

If successful, the user is returned to the app with freshly minted tokens, just like a normal authorization call, but with updated session authentication information.

Developers should be aware that these are helpers only. They are meant to guide the user to do the right thing, but there is no hard enforcement that the client always gets back what it expects; the user could theoretically manipulate the authorization URL, for example. As such, it is always up to services to inspect what is sent to them.

6. Sessions for Native Apps

A native app is any application which is not accessed via a browser. Examples includes CLI clients, such as the Globus CLI, and mobile apps.

6.1. Bootstrapping a Native App Instance

Developers can register a Native App Template in Globus Auth. They can specify all the same parameters as any other client. More on this later. The display name chosen for the Native App Template will be displayed to the user in addition to the name the user chooses for their own app instance.

After registering, they will receive a template_id which should be bundled with the installation package distributed to users. As part of the native app installation process, the app should perform a POST request to Globus Auth at /v2/api/clients with the following parameters in a JSON body:

  • template_id

    • The template ID bundled with the installation package.

  • name

    • A display name for the app instance which will show up on the consents page, in addition to the name of the app template.

    • The native app should prompt for this at installation time, so that users multiple instances can distinguish between them.

This call will return a client ID and secret for the app instance. This is for the most part a normal OAuth2 client, which can perform authorization code grants, but with some important distinctions:

  • This is an instance client, and should only be used for this one instance of the native app. The app instance should not be used by multiple users, although the same user can use multiple accounts.

  • It may be deleted by Globus Auth after some time if it goes unused.

  • It can not be modified using the Clients API, except changing its own display name and generating/invalidating client secrets for key rotation. All properties except display name are inherited from the template that the developer registered. If these are changed on the template (for example, changing the privacy policy) the corresponding property will get updated on all instance clients derived from the template.

Also note that if a native app template is deleted, so are all of the instance clients derived from it. This is similar to how deleting a parent client in the Clients API will also delete all child clients.

7. Example Flow

  1. An app calls a service to access resource X with an access token valid for the service.

  2. Resource X can only be accessed if identity eadbeece-7fbe-484c-b002-d0a01fdc4f0d has authenticated in the current session. The service introspects the token, and determines that this identity is part of the user’s account, but they have not authenticated with it in the current session.

  3. The service returns a 403 Forbidden response which contains, along with any other error information the service wishes, the following:

{
"authorization_parameters" : {
    "session_message": "Must authenticate to view resource X",
    "session_required_identities": [eadbeece-7fbe-484c-b002-d0a01fdc4f0d]
}
  1. The app constructs an authorization URL using the provided parameters, and redirects the user to them.

  2. Globus Auth display the session_message to the user, and tells them the username of the identity they need to authenticate as.

  3. If the user clicks "Continue", they are redirected out to the Identity Provider implied by the identity id.

  4. Assuming the user authenticates with the right identity, they are sent back to the app with an authorization code that the app can exchange for new tokens reflecting the recent authentication.

  5. The app repeats the request with the new access token, the service introspects it and finds that it fulfills the session requirements, and processes the request.


© 2010- The University of Chicago Legal