AzureAD / microsoft-authentication-library-for-js

Microsoft Authentication Library (MSAL) for JS
http://aka.ms/aadv2
MIT License
3.64k stars 2.65k forks source link

OneDrive personal account unable to aquire offline_access scope #3109

Closed arsnyder16 closed 3 years ago

arsnyder16 commented 3 years ago

I am trying to acquire an offline access/refresh token pair on my web api server using the on behalf of flow https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow

I am acquiring the id token for the assertion on the client side and sending to the server. My flow works correctly for OneDrive for business account, but for personal OneDrive I get an error trying to get an access token.

const endpoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/token';
{
  client_id            : config.msgraph.clientId,
  client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
  scope                : ['Files.Read.All', 'Files.ReadWrite.All', 'User.Read', 'offline_access'].join(' '),
  grant_type         : 'urn:ietf:params:oauth:grant-type:jwt-bearer',
  requested_token_use: 'on_behalf_of',
  client_assertion: CreateJWT()
};
{
  "error": "invalid_grant",
  "error_description": "AADSTS70000: The request was denied because one or more scopes requested are unauthorized or expired. The user must first sign in and grant the client application access to the requested scope.\\r\\nTrace ID: 38a5157b-23ee-4112-8833-18036d524a00\\r\\nCorrelation ID: 85e47fe8-8c8a-45ae-83c6-94d785af1ff8\\r\\nTimestamp: 2021-02-28 23:29:51Z",
  "error_codes": [70000],
  "timestamp": "2021-02-28 23:29:51Z",
  "trace_id": "38a5157b-23ee-4112-8833-18036d524a00",
  "correlation_id": "85e47fe8-8c8a-45ae-83c6-94d785af1ff8",
  "error_uri": "https://login.microsoftonline.com/error?code=70000",
  "suberror": "consent_required"
}

Is offline_access supported for OneDrive Personal? I haven't found anything documented to suggest otherwise.

Library

Framework

Description

Error Message

MSAL Configuration

// Provide configuration values here.
// For Azure B2C issues, please include your policies.

Reproduction steps

// Provide relevant code snippets here.
// For Azure B2C issues, please include your policies.

Expected behavior

Identity Provider

Browsers/Environment

Regression

Security

Source

pkanher617 commented 3 years ago

@arsnyder16 This looks like it is an expected error, it needs to be handled with an interactive call with the same set of scopes to allow the user to consent.

It looks like you are using msal 1.x to acquire tokens, I don't think you need to send offline_access for this? I will double check to make sure.

arsnyder16 commented 3 years ago

@pkanher617 Just so i am clear. This is expected behavior for personal accounts but not for business accounts? My flow is working fine for non personal accounts.

I have tried requesting offline_access on the client, and i had no change in behavior. I am trying to establish on_behalf_of on my web server. Currently to do that i am just sending the users idToken retrieved from msal to the server and from there I can establish an access token/refresh token pair for the server to use

pkanher617 commented 3 years ago

There are some differences in how the MSA (personal) auth service and AAD (business) auth service handles scopes, so it is probably expected, but I will double check with the service team.

I think I misunderstood the scenario, so disregard the comment about offline_access above.

hpsin commented 3 years ago

Does the server have consent for files.read.all? This usually occurs when e.g. your front-end requests just ID tokens (openid, profile scopes) and then attempt to request a token for additional scopes which are not consented. Do you see OneDrive in the consent screen for MSA users when you sign in?

arsnyder16 commented 3 years ago

@hpsin The server is sending exactly what i at the top scope: ['Files.Read.All', 'Files.ReadWrite.All', 'User.Read', 'offline_access']

I tried @pkanher617 suggestion and it worked. So i revoked my permissions to the app and then the launched the login so that consent would show up and i made sure the client sent offline_access and that made the extra consent be granted. I don't see to need to do this for business accounts. The other issue that is hanging me up is it a lot of cases the initial login for these accounts and the consent is usually a result of the onedrive file picker being shown. I tried passing offline_access to the scopes advanced: {scopes: ['Files.Read', 'Files.ReadWrite', 'offline_access']} but the picker does not work properly in that case.

I am going to restructure a few things within the application to see if i can get the user logged in/consenting before showing the picker.

arsnyder16 commented 3 years ago

Because the file picker does not work correctly with 'offline_access' i have to either prompt before or after the picker. Whichever popups happens second is always getting blocked by the browser since its not coming from user input which isn't verify desirable from the user perspective

arsnyder16 commented 3 years ago

I tracked down the issue within the onedrive picker there is code that is prepending https://graph.microsoft.com/ to any scope passed, but https://graph.microsoft.com/offline_access is an invalid scope.

I notice that the picker automatically passes profile, openid. I would be nice if this were to also pass offline_access or not prepend graph.microsoft.com

case c.default.AADv2: t = (i = "profile openid https://graph.microsoft.com/User.Read " + (r = e).scopes.map(function(e) { return "https://graph.microsoft.com/" + e }).join(" "),

hpsin commented 3 years ago

Could you share a link to that code? We'll track it down internally.

arsnyder16 commented 3 years ago

@hpsin I have not been able to find an repo that hosts this code but maybe you can find based on this information

https://docs.microsoft.com/en-us/onedrive/developer/controls/file-pickers/js-v72/save-file?view=odsp-graph-online

hosted here: https://js.live.net/v7.2/OneDrive.js

I have also logged: https://github.com/OneDrive/onedrive-api-docs/issues/1445

@KevinTCoughlin @VesaJuvonen @JeremyKelley @chackman can any of you assist?

arsnyder16 commented 3 years ago

just some more information related.

I manually modified the OneDrive.js file and added offline_access beside profile openid and everything worked as expected.

One other odd behavior i notice with this library is i can't just use my scopes that i use for msal

['profile', 'openid', 'offline_access', 'Files.Read.All', 'Files.ReadWrite.All', 'People.Read', 'Contacts.Read', 'User.ReadBasic.All']

The library is expecting to append All to Files.Read and Files.ReadWrite so i have to actually pass `'Files.Read', Files.ReadWrite' instead

scopes: msal.scopes.map(scope => scope === 'Files.Read.All' || scope === 'Files.ReadWrite.All' ? scope.replace('.All', '') : scope)

r-a-y commented 3 years ago

This is useful information about the offline_access scope, @arsnyder16. Thanks for posting your workaround!

github-actions[bot] commented 3 years ago

This issue has not seen activity in 14 days. If your issue has not been resolved please leave a comment to keep this open. It will be closed in 7 days if it remains stale.

github-actions[bot] commented 3 years ago

This issue has been closed due to inactivity. If this has not been resolved please open a new issue. Thanks!