OneDrive / onedrive-sdk-dotnet-msa-auth-adapter

Other
26 stars 22 forks source link

Can't seem to get CredentialCache / silent token refresh working with MSA. #20

Closed Forceh91 closed 7 years ago

Forceh91 commented 7 years ago

I've connected the OneDrive account and given permission etc, and get access tokens / refresh tokens back fine. However when I go to retrieve files the access token has already expired, and I can't seem to get it to work.

When I connect OneDrive to the app, I call the following function, to quadruple check that everything is fine. However that doesn't seem to be helping. This function is also called when the app starts.

        public static async void loadOneDriveConnection()
        {
            // attempt a connection using the refresh token
            await msaAuthenticationProvider.RestoreMostRecentFromCacheOrAuthenticateUserAsync();
            onedriveConnection = new OneDriveClient(msaAuthenticationProvider);

            // check we got deets
            if (msaAuthenticationProvider.CurrentAccountSession == null)
                return;

            // store the new deets
            storeOneDriveAccount(msaAuthenticationProvider.CurrentAccountSession.AccessToken);
            storeOneDriveAccountRefresh(msaAuthenticationProvider.CurrentAccountSession.RefreshToken);
        }
cdmayer commented 7 years ago

Why are you storing the AccessToken and RefreshToken? The Auth Adapter should automatically getting the access token, storing it, and refreshing it if needed. Can you show the code where you create msaAuthenticationProvider and where you use onedriveConnection?

As an aside, you can use MsaAuthenticationProvider.IsAuthenticated to see if a user is authenticated. You should not really need to look directly at the CurrentAccountSession unless you plan on replacing it.

Forceh91 commented 7 years ago

Hi, the storage of AccessToken and RefreshToken is left over from the old SDK version.

    public static class TVTOneDrive
    {
        public static OneDriveClient onedriveConnection = null;
        public static string[] accessScopes = {
            "onedrive.readwrite",
            "onedrive.appfolder",
            "offline_access"
        };

        public static MsaAuthenticationProvider msaAuthenticationProvider = new MsaAuthenticationProvider("clientid", "returnurl", accessScopes, null, null);

        public static async Task<bool> loadOneDriveConnection(bool isFreshAccount = false)
        {
            // either get from the cache or do a fresh authentication
            if (isFreshAccount == false) 
                await msaAuthenticationProvider.RestoreMostRecentFromCacheOrAuthenticateUserAsync();
            else
                await msaAuthenticationProvider.AuthenticateUserAsync();

            // now create our connection
            onedriveConnection = new OneDriveClient(msaAuthenticationProvider);

            // check we got deets
            if (msaAuthenticationProvider.CurrentAccountSession == null)
                return false;

            // and that we authenticated
            if (msaAuthenticationProvider.IsAuthenticated == false)
                return false;

            // all good
            return true;
        }

Then this is where I use the onedriveConnection that I created.

        public static async Task<ObservableCollection<TVTBackup>> fetchTVTBackups()
        {
            ObservableCollection<TVTBackup> backups = new ObservableCollection<TVTBackup>();

            // make sure we're connected to onedrive before we actually try doing anything
            if (onedriveConnection == null)
                return backups;

            // make sure we're authenticated
            if (msaAuthenticationProvider.IsAuthenticated == false)
                return backups;

            // this is where the access token error occurs, saying that it's not valid
            IItemChildrenCollectionPage childrenCollection = await onedriveConnection.Drive.Special.AppRoot.Children.Request().GetAsync();

            foreach (Item backup in childrenCollection.CurrentPage)
            {
                // create a backup object
                TVTBackup tvtBackup = new TVTBackup()
                {
                    dateCreated = backup.CreatedDateTime,
                    fileID = backup.Id,
                    fileName = backup.Name,
                    fileSize = backup.Size
                };

                // and add it to the list
                backups.Add(tvtBackup);
            }

            // return the list of items
            return backups;
        }
cdmayer commented 7 years ago

I don't see anything glaringly obvious. One thing that sticks out to me: are you using a version of the SDK prior to v2.0? It's not a priority to support that version of the SDK. You should be able to upgrade in place with very minor changes. (You may want to wait just a couple days until I publish v2.0.3, which adds support for Drive.Special)

What is the message on the exception? Even better, can you try printing the access token you have (TVTOneDrive.MsaAuthenticationProvider.CurrentAccountSession.AccessToken) to the console, then doing a direct request using an HTTP Client like Fiddler or Postman? I need to know more about why your authentication is failing.

Forceh91 commented 7 years ago

I'm using v2.0.2 of the SDK according to NuGet packages.

This is the response I get when I send a request via hurl.it.


{"error": {"code": "InvalidAuthenticationToken","message": "CompactToken parsing failed with error code: -2147184105","innerError": {"request-id": "368851d4-38a3-421e-a501-e97374d18e20","date": "2016-10-17T22:58:43"}}}

Oh, and the "ExpiresUTC" is basically as soon as the token is received as well.

cdmayer commented 7 years ago

It looks like you might be developing a Universal Windows app. Have you associated your app with the store?

Forceh91 commented 7 years ago

Yep, the app previously worked before I updated the NuGet packages, and had an update a few days prior with the OneDrive stuff working :)

cdmayer commented 7 years ago

OK. Maybe we can narrow down the scope of the problem a bit. Can you try:

Keep trying until you get a combination of the SDK + this package that does work (use the NEWEST packages that don't exhibit the bug), then report back. We should be able to narrow down the offending changes using that matrix.

Forceh91 commented 7 years ago

I can't seem to get any combination working currently. I've tried down to v1.03 (doesn't seem to go lower) for this package. As for the SDK the lowest I can go before this SDK no longer works alongside it is 2.0.0, and I get the same errors again.

I'm pretty sure I'm getting the same access token everytime as well.

Forceh91 commented 7 years ago

So I've changed onedriveConnection to the following and it's working :/

onedriveConnection = new OneDriveClient("https://api.onedrive.com/v1.0", msaAuthenticationProvider);
cdmayer commented 7 years ago

Ah, of course. I am sorry that I didn't catch that earlier; the issue was that you were making requests against the Graph API (as opposed to OneDrive; the resources are the same but the naming is different). Glad you found the problem and I'll keep an eye out for this in the future.