googleapis / google-api-dotnet-client

Google APIs Client Library for .NET
https://developers.google.com/api-client-library/dotnet
Apache License 2.0
1.36k stars 528 forks source link

Unauthorized client issue #2802

Closed ajram23 closed 4 months ago

ajram23 commented 4 months ago

I have a Mac app with a simple container that runs sync api's with google contacts. The user logins into google to authorize the app and everything works and access/refresh token are passed to the server running in the container. When the refresh occurs in a hour I am getting an unauthorized client issue. This is probably rudimentary I have setup two oauth client IDs (one for the iOS/Mac) and the other for the container (Mac). When the token is expired, I try to refresh it with the client ID along with the secret from the Mac OAuth client and I get a Failed to refresh token: ('unauthorized_client: Unauthorized', {'error': 'unauthorized_client', 'error_description': 'Unauthorized'}) The Mac app sends the refresh token to the container every 55 minutes as well.

Feels like I am messing up something up rudimentary. Any suggestions would be greatly appreciated.

jskeet commented 4 months ago

It's unclear to me where iOS comes in, and you haven't provided any code so it's hard to know exactly what you're doing. I wouldn't expect you to need to do any refresh explicitly yourself - that should be able to happen automatically with an appropriate UserCredential. But it might be better to do the refresh from the same system that originally performed the authentication - and it seems odd to have two different client IDs.

If you could explain the system more clearly in terms of what the server is in this case, we're more likely to be able to help you.

I'll assign this to @amanda-tarafa who is out today, but has more experience with the auth library than I do.

ajram23 commented 4 months ago

My apologies.

Mac app performs the authentication: And sends the code to the localhost (which is running inside the container). Here is the code that sends the tokens GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in if let error = error { print("[syncData] Failed to restore previous sign-in: (error)") completion(false, "Failed to restore previous sign-in") return }

        guard let user = user else {
            print("[syncData] No user signed in")
            completion(false, "No user signed in")
            return
        }

        user.refreshTokensIfNeeded { user, error in
            if let error = error {
                print("[syncData] Failed to refresh tokens: \(error)")
                completion(false, "Failed to refresh tokens")
                return
            }

            guard let user = user else {
                print("[syncData] No user after refreshing tokens")
                completion(false, "No user after refreshing tokens")
                return
            }

            Task {
                do {
                    let scopesString = user.grantedScopes?.joined(separator: ",") ?? ""
                    try await self.sendTokenToServer(accessToken: user.accessToken.tokenString, refreshToken: user.refreshToken.tokenString, scopesString: scopesString)

This is the same code that is triggered every 55 minutes. The reason the sync code is in the container is that it does a lot of processing after getting the data in python. Not something I want to do in Swift. Its essentially a local docker running a couple of python scripts that process the contacts once its gets them. LLMs are also involved. So my client is a Mac tray app that signs into google and sends the tokens to this container to do the heavy lifting. Hope this helps, happy to answer more specific questions. Thank you for getting back right away.

jskeet commented 4 months ago

Do you understand you've filed a bug in the .NET repo? If your code is all in Python and Swift, this is the wrong place for your issue...

ajram23 commented 4 months ago

Oops my bad, I messed up. Sincere apologies. Will post on there.