Replacing the OAuth service

The OAuth handler was written 9 years ago, using the common Python 2.7 and is hosted on Google App Engine. Many things have changed since then, notably the deprecation of Python 2.x, which is now enforced on GAE.

There has been requests for a more closely guarded “in-house” hosting option, so instead of simply upgrading the Python solution, I have written a replacement service:

The new service is written in C# to cater better to the expertise of the development community around Duplicati and is built to be deployed in a Docker setup, with environment configuration.

I am currently hosting a functioning deployment for evaluation:

  • https://oauth-service.duplicati.com

The idea is that this service will eventually replace the GAE version, but it may not be as smooth a transition as I have hoped.

Known issues

Below is a list of know issues with the transition.

Missing providers

I have removed the providers that are no longer active, I do not expect this to cause any problems.

Windows Live & Microsoft Graph

Since 2020 there has been a requirement that the company is approved before it can offer the login functionality currently available from the GAE service. Duplicati has been allowed to operate but since I need to change the server, I cannot re-use the current tokens without interrupting service from the existing users.

I think the right solution is to register for a verified Microsoft Partner account and then discontinue the GAE version. This is something that takes some time and it also means that any MS based users will need to re-create their token.

Until I get the verified account, I have disabled the MS OAuth options on the hosted service.

Google Drive

Google attempts to prevent unwanted exposure of sensitive files on Google Drive, with a limited access scope. Unfortunately, this method is designed for web-based applications that needs to store files for a particular app. This means that the app can only access the files it creates itself. Unfortunately, any access to the files from within Google Drive will render them unaccessible for the application, with no meaningful way to let the application re-own them.

For users changing the OAuth method, Google treats it as a new application, meaning there will no longer be access to files uploaded with the previous OAuth server, and no meaningful way to change ownership.

This leaves the full access method which Google is severely restricting and may not be permitting for Duplicati going forward. I have applied for access, and the initial review appears to be pending.

Summary

Despite the hassles this is a needed upgrade, caused by my choice of GAE many years ago.

If you have any input to the transition, ideas, hints, suggestions, questions, then please post them here.

At some point, when the transition path is clear, I think we can add a warning to all backups that are using the GAE OAuth server and then shut down the GAE service after a grace period.

1 Like

In the existing GAE system, there is an export function, guarded by an Api key (it’s for internal worker processes). Could it be possible to have an export function restricted to the key owner, allowing for users of an OAuth server to get back the native OAuth token on their own computer (something like the V2 system), and reexport it to another OAuth server ? It would allow users to manage their access without being tied to a specific server.
I am yet to validate this wild idea (not sure it is allowed by the OAuth spec…)

My test with a personal account recognized it as the same application, maybe wanting more access.
No problem actually doing backup, recreate, etc. I just flip the AuthID and oauth-url back and forth…

I’m not sure if there’s a detailed history, but I’m assuming it just noted new server for my account, as:

Testing on 2.0.7.100 Canary, but I know there are some fixes coming to OAuth server moving, so I’m being conservative in my testing because I don’t recall offhand what’s expected to break with Canary.

EDIT: In case it’s not clear from Google’s “Duplicati can” list, this was their “limited” drive.file login.

I can confirm that an “old” backup with limited access still works when the new oauth server is used, after generating a new auth ID. As in the screenshot, it looks like it adds another domain to the same application access.

There was a warning that Duplicati already has an existing access, but it worked fine.

So google drive should have no problems to migrate.

I take it that the oauth keys have been migrated from the current server then.
The existing PR deals with the case of using an alternate OAuth server to create a new authorization.
So I think that if you create a new authorization, as it will be created on the current standard Duplicati OAuth server, you will not be able to use it with this new server.

that’s the default for Duplicati now, you can’t use the full access without some ugly hacking I believe.

If you mean the data that identify the OAuth server as representing Duplicati, then it would appear so, however if you mean my own tokens, I doubt that but I did first try my old differently-formatted AuthID.

As it turned out, it seemed like my old AuthID had been expired by some party, so I wound up doing the exact sequence above, getting back into operation on old server, trying AuthID in new. It didn’t work, but even if tokens were migrated (can version change be done?), my tokens were probably way too recent.

It was a button before, and I assumed it still is, as the new server still has it:

EDIT:

To clarify further, even after I changed the oauth-url, I noticed that the AuthID link sent me to old server, so I wound up going directly to new server URL and using the button on the left there to manually copy.

EDIT 2:

After reading the docker hub info, I’m thinking new server gave me a V1 AuthID, but longer passphrase.

Yes that’s the whole point of this PR, in current Duplicati the existing OAuth server is hard coded.

I will have to check that as I don’t understand how it can work :slight_smile:

Wouldn’t it be just another independent refresh and access token set? An app can have multiple sets.
Deleting a backup should revoke the oauth token #5092 spoke of a workflow (not mine) that kept lots.

This how usual installed apps (but not Duplicati) do it. There are potential security hazards either way. One hazard of a centralized store is that if an attacker can insert themselves, they can do wide harm.

OAuth 2.0 for Native Apps is somewhat old, but is at least an RFC. There are new Internet Drafts out.
Google has taken an official dislike to at least one practice which is to talk on local loopback interface.
Loopback IP Address flow Migration Guide discusses, but at least desktop use seems permitted, now.

OAuth has a lot of variations to it, and sometimes a service provider gets to set rules as they do there.

If you ever watch packets, watch your loopback interace while rclone is setting up its access by OAuth.
If that’s too much, I think even a netstat at the right time can spot it doing work using a loopback port.

The encryption on the new service is different than the old, so currently AuthIDs cannot be used across the servers. I was hoping to do some kind of migration, but the MS issues are forcing me to look towards not supporting this.

Yes, that was apparently never properly tested, but the intention was that the server should be changeable.

The AuthID is essentially an id:password. This is used to decrypt the refresh token stored on the OAuth server. The decrypted refresh token is used to issue a short-lived access token. When you access the Google API, you only provide the access token, and Google can then know your internal Google User Id, and the fact that Duplicati was the issuer.

You can do that, but the problem is that the step to get from refresh token to access token requires a client secret. If that secret is present with the client, any abuse will cause all users of the same secret to be cut off. It is possible to let the user go through the hoops and obtaining a refresh token, but this is not something I think regular users can be expected to do.

That is excellent news! That means that I can scratch that concern and focus only on getting the MS OAuth flow set up.

Rclone OAuth Implemented Incorrectly. Exposes Client Secrets? explains why they went the other way. Either way has issues, and I’m not sure which is worse. Secrets in source got rclone banned from ACD, however that’s just an illustration of the who-holds-the-secrets issue, because they’re discontinued now.

However corporate IT departments might prefer to set up their private C# server, just the way they like.

As a side note, there can reportedly be performance advantages to cutting loose from the large crowd.
Making your own client_id talks about how things like rate limiting can be tied to specific client ID used.

Detailed directions there are interesting. Seemingly Google doesn’t mind taking a program’s app name repeatedly, but if someone abuses them, I wonder if it’s their client ID or our app that gets into trouble?

sounds like a vote for not sharing our secret, but I don’t know if our app gets dragged in by association.

EDIT:

Actually, the end user could also get dragged in. Is there any reliable data on who/what gets a ban first?

I don’t know if this will come up, but Duplicati arguably abuses OneDrive by ignoring Retry-After.
There’s a forum discussion, and a possibly not-yet-ideal pull request to try to get more compliant…

I think that’s what I missed. I assumed that you created a new application, but instead you just added the new OAuth server to the Google application.

Registration of Native App Clients recognizes that installed apps are public clients, meaning they have a tough time keeping credentials secret. I suspect our OAuth servers are confidential clients, but I’m not sure how different providers treat different styles of OAuth in terms of registration data, banning, etc.

If it’s correct that public clients abound among installed apps, banning apps for failing impossible task of keeping the client secret secret against all manner of attacks seems kind of unfair to the app developers. Duplicati’s method lets an installed app potentially claim to be a confidential client. Does that help things?

I picked on rclone earlier because data is easy to get, but installed apps could certainly be studied more.

EDIT 1:

Rather than test first, I used Google. Here’s a recently fixed Thunderbird issue where they originally had themselves classified the wrong way. I won’t claim to follow it all, but it also gives insight on one provider.

Office365 OAuth2 Implementation uses Confidential Client instead of Public Client access

Proof Key for Code Exchange by OAuth Public Clients also gets a mention. Maybe that can help secure, but tracing this through the standards is tough, and then after that comes whatever provider wants to do.

EDIT 2:

OAuth2 for Go appears quite popular, but at first glance it looks like it can be employed in several ways. Persistence in rclone is config file, but Duplicacy Cannot refresh oauth token in China due to GFW uses helper on the web site, so maybe that’s how access token refresh was handled. I didn’t try a deep study.

I think you suspect well. The ‘secret’ is kept in the application configuration (that’s in the config.py file for the current Duplicati server, a file that is not being exported to github), so it’s not known to the app users. This Thunderbird issue you linked to is making clearer the difference in the MS configuration between ‘web’ and ‘mobile and desktop’ settings (I had wondered about that). BTW, you can setup an OAuth configuration for any old Outlook.com user (no need for a special account or anything), as long as it’s a ‘private’ setup (limited) you can use it as you wish. That’s only for a wide distribution that Ms begins to be annoying.

In principle, Duplicati should be a ‘mobile and desktop’ app if it was really a ‘trust no one’ setup. Unfortunately I think it would need to reconnect manually from time to time to the provider for that to work (as is the case for Thunderbird for example). The case of a backup application is not taken in account by OAuth (I guess).
All is not yet fully clear in this…

Huh? I don’t have to do it. BTW, I added a second edit to my previous post. Writing it when you posted. Access token gets refreshed with the refresh token, but if provider also kills refresh, then it’s a problem, however it might also be a problem with confidential client, as it might need manual setup from scratch.

It’s not happening every day, but I had to reconnect to Gmail a few weeks ago.

Interesting. I use Gmail with whatever Thunderbird they offer to Windows, and haven’t had that … yet. Sometimes providers just like reauthentication. I think Microsoft just forced a password change on me. Google got me on a TOTP authenticator app, which may or may not explain your different experience.

Yes that’s it. To be sure I deleted everything in Google configuration, recreated a new service, set it up with 2 servers, and reproduced the exact same behaviour, the second time Google auth screen warned that it was adding a second access, just as it happens with your new server and the Gae server. So there is no problem specific to Google - however users will indeed have to recreate new Oauth keys.
This step could possibly be avoided by migrating the Gae server instead of creating a C# one.

We should fix that anyway, but I think the partner verification is just to make sure there is a liable entity in case the account is used for malware.

Yes, but I did add it as its own client, so it could go both ways :slight_smile:

The OAuth protocol was very much designed with webservices in mind, not a lot of work went in to supporting desktop applications. There are newer extensions that allow a flow that is better for desktop clients, but not all providers support it.

From that, it looks like they register a domain that just redirects to 127.0.0.1 and then use that redirect. A quick Google search indicates that each user needs to register a client, and then the domain is used to sendt the requests to the local webserver. With the C# version we can support this as well, but it requires quite a lot for the user to set up.

Yes, the problem is that Duplicati runs in the background, so there is no good way to show a “please log in” dialog and it would break automated backups. I think OAuth has poor support for a “service account”, but really it should be possible to generate an API key instead of requiring OAuth for applications like this.

Yes, that is a path forward. Maybe we need to do both. The problem is that since I have been so late in upgrading, GAE now prevents uploading Python 2.x so I cannot roll back the upgrade in case it has flaws. Breaking this will cause massive problems for users. If I get a working Python 3 application, I can add an upgrade path, here the current refresh token can be migrated transparently to the C# server.