I have a single page Javascript application (SPA). I have a middle-tier Azure Function service that uses TypeScript/NodeJS. The SPA allows users to login and, on demand, contact the middle tier service to retrieve calendar data from the MS Graph. The middle tier then needs to be able to periodically retrieve that calendar data again, on behalf of the user, without another explicit request from the client.
I need to support both Azure AD accounts and personal MSA accounts. I have one AAD app registration for the SPA and one for the middle-tier service. For Azure AD accounts, this all "just works" because the the middle tier receives an access token from the client, exchanges it for an access token + refresh token from AAD, then retrieves data from the MS Graph API using the access token which it periodically refreshes by using the refresh token it got as part of the OBO flow.
I know that making this work with personal MSA accounts is more challenging because of the lack of combined consent. The only suggestion I could find about how to make this work with MSA was on this page under the "Use of a single application" section. However, I cannot seem to make this work.
If I change my SPA to request all the same scopes that my middle tier needs (https://graph.microsoft.com/Calendars.Read openid profile email offline_access) when calling acquireTokenSilent (on the MSAL library), the correct consent dialog shows but the access token I get back is not a JWT. I understand that this can be expected (because of the "Important" note at the top of this page), however that causes problems when I try to do the OBO flow with my middle tier. If I take that non-JWT access token, send it to my middle tier service (which now identifies itself using the same AAD app registration as the SPA), then try to call the AAD endpoint for the OBO flow, I get this error:
AADSTS50027: JWT token is invalid or malformed.
Trace ID: a3647c0e-e7f5-4919-a457-1bd1e951f501
Correlation ID: a44f9292-1ba0-43b7-aafe-0a77e5adbc35
Timestamp: 2019-12-04 18:52:58Z
...so it's clearly expecting a JWT.
Is there a way to make this OBO flow work with personal MSAs? Or is this OBO flow not the correct thing to do when using personal MSA's with a middle tier that needs a refresh token (so it can periodically re-call the MS Graph API on behalf of the user)? If it's not the right thing to do, how can my middle tier get a working refresh token so it can periodically retrieve a new access token?
Note: I have read this SO post but it does not appear to address the issue I'm having -- I understand that a common OBO pattern cannot be used for both AAD and personal MSA accounts (frustratingly) but I am having trouble getting any personal MSA OBO flow working, ignoring for a moment how much code, if any, I might be able to share between the Azure AD and personal MSA OBO flows.
Thanks!