.. _userguide_coalesce_gares: Coalescing Requirements Errors ============================== A common pattern for applications which want to provide the best possible user experience is to defer raising errors until all discoverable issues are identified. Instead of immediately, eagerly raising an error, the application can provide a superior interface by collecting all of the errors at once and presenting them to the user to resolve. In the context of Globus Auth applications, this can manifest as multiple interactions -- direct or indirect -- which produce Globus Auth Requirements Errors (represented in the SDK as the :class:`globus_sdk.gare.GARE` class). Each :class:`globus_sdk.gare.GARE` can be resolved by a separate login flow, but for an application which collects 3 ``GARE``\s, this would mean asking the user to login 3 times in a row! Applications which collect multiple such errors want to present the user with the fewest possible login flows. Unfortunately, ``GARE``\s are capable of expressing constraints which cannot be safely merged into a single login flow -- requirements may be mutually exclusive, or they may overlap in ill-defined ways. Merging or "coalescing" ``GARE``\s is difficult to define in the general case, but if you have more knowledge of your applications' requirements, you may be able to do more than is generally safe. In this doc, we'll share some theoretical cases of ``GARE``\s which - definitely can be merged together safely - definitely cannot be merged together safely - possibly can be merged together For readers who prefer to start with complete working examples, jump ahead to the :ref:`example script ` which shows a simple and safe merge procedure -- although it might not simplify all possible combinations. GAREs Which Can Safely Merge ---------------------------- Two of the fields in a ``GARE`` are arrays of values which are always combined with "and" semantics. As a result, they can always be safely combined with array concatenation. These fields are: - ``required_scopes`` - ``session_required_policies`` Additionally, the ``code`` field is defined as a non-semantic hint, and is therefore safe to rewrite. Although services may use other values in practice, there are only two well-defined values for the ``code`` string: - ``ConsentRequired``: indicates that the user must consent to additional scopes in order to authorize the resource server(s) to complete the requested action. - ``AuthorizationRequired``: indicates that this is a Globus Auth Requirements Error that is not more specifically described by any other code. Because ``AuthorizationRequired`` is generic, it can always be safely used for a ``GARE`` produced from other requirements. Safe Merge Example ^^^^^^^^^^^^^^^^^^ For example, .. code-block:: json { "code": "ConsentRequired", "authorization_parameters": { "required_scopes": ["foo"] } } and .. code-block:: json { "code": "AuthorizationRequired", "authorization_parameters": { "required_scopes": ["bar"], "session_required_policies": [ "f2047039-2f07-4f13-b21b-b2edf7f9d329", "2fc6d9a3-9322-48a1-ad39-5dcf63a593a7" ] } } can safely merge into .. code-block:: json { "code": "AuthorizationRequired", "authorization_parameters": { "required_scopes": ["foo", "bar"], "session_required_policies": [ "f2047039-2f07-4f13-b21b-b2edf7f9d329", "2fc6d9a3-9322-48a1-ad39-5dcf63a593a7" ] } } GAREs Which Cannot Safely Merge ------------------------------- There are no strictly defined merge semantics for any of the fields in ``GARE``\s, but in particular we can see problems when trying to merge together ``session_required_single_domain``. This field expresses the idea that a user must have an identity from *one of* the listed domains, meaning it uses "or" semantics. However, two separate ``GARE``\s naturally communicate "and" semantics, so merging two such lists together produces an incorrect result. Unsafe Merge Example ^^^^^^^^^^^^^^^^^^^^ For example, .. code-block:: json { "code": "AuthorizationRequired", "authorization_parameters": { "session_required_single_domain": ["umich.edu"] } } and .. code-block:: json { "code": "AuthorizationRequired", "authorization_parameters": { "session_required_single_domain": ["stanford.edu"] } } cannot merge together! As a pair, these documents express "the user must have an in-session ``umich.edu`` identity" **and** "the user must have an in-session ``stanford.edu`` identity". If we combine them into .. code-block:: json { "code": "AuthorizationRequired", "authorization_parameters": { "session_required_single_domain": ["umich.edu", "stanford.edu"] } } we accidentally express the idea that "the user must have an in-session ``umich.edu`` identity" **or** "the user must have an in-session ``stanford.edu`` identity". We have accidentally transformed the "and" into an "or"! GAREs Which Can Safely Merge *Sometimes* ---------------------------------------- Some fields in ``GARE``\s cannot be merged without some decision being made. For example, ``session_message`` is a string message to display to the user. When combining two ``GARE``\s with distinct messages, how should the result be formulated? Should the messages be joined with some separator? Should a new message be composed? There is no strictly correct answer. However! An application which is, itself, replacing the ``session_message`` can safely ignore this conflict because it was planning to change the message anyway. Maybe Safe Merge Example ^^^^^^^^^^^^^^^^^^^^^^^^ For example, .. code-block:: json { "code": "ConsentRequired", "authorization_parameters": { "session_message": "You need authorization for Service Foo!", "required_scopes": ["foo"] } } and .. code-block:: json { "code": "ConsentRequired", "authorization_parameters": { "session_message": "You need authorization for Service Bar!", "required_scopes": ["bar"] } } Could be combined into .. code-block:: json { "code": "ConsentRequired", "authorization_parameters": { "session_message": "You need to authorize use of Services Foo and Bar.", "required_scopes": ["foo", "bar"] } } This is safe because ``session_message`` is known to be non-semantic for the purpose of authorizing the user. .. _userguide_coalesce_gares_example: Summary: Complete Example ------------------------- Even knowing that ``GARE``\s cannot be safely combined in many cases, as established in the introduction above, doing so is highly desirable for some applications. This example merges together these documents, represented as :class:`globus_sdk.gare.GARE` objects, only in cases which are defined to be safe. If ``session_message`` or ``prompt`` values are supplied, they will override any values for these fields present in the GAREs, allowing the ``GARE``\s to merge more aggressively. .. literalinclude:: coalesce_gares.py :caption: ``coalesce_gares.py`` [:download:`download `] :language: python .. note:: This example discards extra fields, which a ``GARE`` may store, but which are not part of the format specification.