arup-group / arc-components

Arup Reusable Components
https://arc.arup.com
MIT License
10 stars 0 forks source link

ARC SSO Access Token Availability #109

Closed cerimorse closed 1 year ago

cerimorse commented 2 years ago

Currently the ARC SSO component handles authentication which works really well. Internally when the component retrieves the avatar photo, it uses a private function _getAccessToken to retrieve the access token required to call the Microsoft Graph API endpoint.

If an application that utilises the ARC SSO component needs to call another Microsoft Graph API endpoint, there is currently no way to retrieve the access token (other than potentially through local storage). It would be great if we could make the access token available to applications.

I propose we do this in one of two ways:

  1. Add the token to the account object:
{
    "homeAccountId": "3f9c8a2f-1da4-44e4-b3a6-be593c658052.4ae48b41-0137-4599-8661-fc641fe77bea",
    "environment": "login.windows.net",
    "tenantId": "4ae48b41-0137-4599-8661-fc641fe77bea",
    "username": "Ceri.Morse@arup.com",
    "localAccountId": "3f9c8a2f-1da4-44e4-b3a6-be593c658052",
    "name": "Ceri Morse",
    "idTokenClaims": {
        "aud": "3e001f04-f064-4e5c-a8a0-b7c0162ef9d2",
        "iss": "https://login.microsoftonline.com/4ae48b41-0137-4599-8661-fc641fe77bea/v2.0",
        "iat": 1660576774,
        "nbf": 1660576774,
        "exp": 1660580674,
        "name": "Ceri Morse",
        "nonce": "2bc9058c-023d-44fb-b704-7bc17c0802c1",
        "oid": "3f9c8a2f-1da4-44e4-b3a6-be593c658052",
        "preferred_username": "Ceri.Morse@arup.com",
        "rh": "0.AQUAQYvkSjcBmUWGYfxkH-d76gQfAD5k8FxOqKC3wBYu-dIFAL4.",
        "sub": "DFyAtBj1Oac8TMdtPyx4zbxisU_BYWrIRup_4XUgNIM",
        "tid": "4ae48b41-0137-4599-8661-fc641fe77bea",
        "uti": "mYnRoix0P0uNdvceZ-0YAA",
        "ver": "2.0"
    },
    "accessToken": "TOKEN STRING GOES HERE"
}
  1. Make the internal _getAccessToken function publicly available
thomasmarr commented 2 years ago

Sometimes we need to access multiple different APIs, and they each need their own token with the correct audience and scopes. In addition to, (or instead of) the <arc-sso> component directly exposing the graph access token, I'd like to see it expose a method that allows the user to request a token, specifying the scopes (and whatever other options are permitted by the acquireToken method provided by MSAL).

dominicegginton commented 2 years ago

I say lets not reinvent what's already out there and provided by Microsoft. I believe we should be providing guidance on how to use ARC alongside other common libraries such as @microsoft/mgt that provides a really nice SSO componennt that can easily be placed within the user slot of the ArcHeader component. The @microsoft/mgt library also includes providers to enable your application to authenticate with Microsoft Identity and access Microsoft Graph in only few lines of code, this includes a provider for MSAL2 and a custom provider in case you want to use your own authentication logic.

The providers can also be used seperatly from the Microsoft components so I think we might be able to use the MSAL2 provider under the hood to handle auth for the ArcSSO component, but this still needs some investigation. What are people's thoughts on this?

jasperwieringa commented 2 years ago

@thomasmarr The arc-sso component already allows users to provide a scopes array. Requesting an access token, uses these scopes. ARC has a default scopes array of ['openid', 'profile', 'User.Read']. Exposing just the getAccessToken, should in most cases be sufficient correct?

thomasmarr commented 2 years ago

@jasperwieringa the challenge is when we need (after authenticating) to request access tokens for other APIs, i.e. with different scopes from those used in the login request.

If getAccessToken on arc-sso allows for the user to pass the options permitted by the MSAL acquireToken method that should work. If it just re-uses the scopes array passed to the component for logging in, then not really.

From what I can tell, the arc-sso component is really trying to create an abstraction on top of MSAL, to make it quick and easy to add SSO with sensible default behaviour. I think this GitHub issue is really stemming from a need for sufficient escape hatches to be provided to give us access to the underlying MSAL objects / methods when we need them.

jasperwieringa commented 2 years ago

The abstraction level is indeed an important factor of any ARC component. If there is usecase for retrieving an accessToken from the underlying MSAL object by providing different scopes, then that might be a thing to add. I am not sure whether exposing the underlying MSAL object itself is something we want to do, but I leave that into your capable/experienced hands. Sometimes advanced features of underlying 3rd party software is necessary and therefore ARC could potentially expose said libraries. The question only remains: how much.

thomasmarr commented 2 years ago

My personal view is that on something like this, ARC should just give as much access as possible to the underlying MSAL stuff.

With the design oriented components, deciding what constraints to apply in order to 'enforce' alignment with the design system is totally valid. But for something like auth I struggle to see a good reason not to give the user as full control over it as possible (but with sensible defaults to make the most common use case as easy as possible). I don't think it's really the design system's job to restrict how people handle implementation of auth.

jasperwieringa commented 2 years ago

I definitely agree. The only 'problem' or point to consider is, web-components are accessible by users of your application. If a user were to query the arc-sso component, they would be able to update properties or get access to elements you (as a developer) might not want to expose.

Example: document.querySelector('arc-sso').msalInstance = anythingElse;

Although this might not necessarily cause any real problems, it is still something to consider/be aware of.

JoshWoodArup commented 2 years ago

Would allowing the PublicClientApplication to be injected into the component work as a solution? That would also make it easier to work with libraries such as react-masl