daneden / Twift

🐦 An async Swift library for the Twitter v2 API 🚧 WIP

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Refresh token/access possible issue

emin-grbo opened this issue Β· comments

commented

I have an issue where I am not sure If I am doing anything wrong or if there is an issue with 2.0 token.

When I initiate the app and login by authorizing the user like so:

let oauthUser = try await Twift.Authentication().authenticateUser(
     clientId: Constants.clientID,
     redirectUri: URL(string: Constants.urlScheme)!,
     scope: Set(OAuth2Scope.allCases),
     presentationContextProvider: nil)
client = Twift(.oauth2UserAuth(oauthUser))
UserDefaults.encodeUser(user: oauthUser)
self.oauthUser = oauthUser
completion(true)

Everything works fine (UserDefaults storing is temporary)

But after launching the app for example...few hours later, same build in xcode, I use the path:

if let oauthUser = UserDefaults.decodeUser() {
                client = Twift(.oauth2UserAuth(oauthUser))
                completion(true)

However, the call I make after this, using the said client, fails to get a response other than Unauthorised

When I follow the call, refresh is not used as authToken is valid, and by checking expiresIn myself, I saw that is true.

So, seems that the client is not initiated/authorized then?
The only difference in two flows is that first one uses authenticateUser and second one does not, but I am storing that user properly (I read it before and after storing and it seems πŸ‘Œ)

Here is the call that gets invalid response"
https://api.twitter.com/2/users/me?user.fields=description,profile_image_url
with token:
Bearer akNhMEZxTklrSU1ZV19TVS1qM2FSenRmdmdlWm9OZ0x6dTd6WktzUWlzZmE0OjE2NTQxMTE1MDg1NTE6MTowOmF0OjE

Update:
If I perform the force refresh, everything is fine πŸ€·β€β™‚οΈ.
client?.refreshOAuth2AccessToken()
So maybe the Twift(.oauth2UserAuth(oauthUser)) just needs to be async?

Hope I am not talking out my ass here, just typing this as I debug πŸ˜‚

commented

I also think I keep hitting this now, even with force refresh πŸ˜…

guard let refreshToken = oauthUser.refreshToken,
          let clientId = oauthUser.clientId else {
      throw TwiftError.UnknownError("Couldn't find refresh token or client ID")
    }
commented

@daneden So, I think I found the issue, but not sure If I am doing anything wrong in the setup myself or if this needs to be modified.

On initial app launch login works fine, oauthUser is stored, and all is well :)

During the next launch, when I initiate Twift, I use the stored user. If token has expired, It will refresh, but here's the kicker. Once it refreshes, my stored user has invalid tokens. So if it refreshed already in previous session or at any time really, I can not longer initiate Twift with the authorized user, It was lost in the refresh.

Basically, there should be a way to re-store the user if refreshed, or access it and store it on appClose?

You can easily repro this if you force the refresh when the app is launched like so:

client = await Twift(.oauth2UserAuth(oauthUser))
try? await client?.refreshOAuth2AccessToken(onlyIfExpired: false)

Again, maybe it is me who is missing something obvious here πŸ˜…

commented

Also, in the initial oauthUser I get back clientID seems to be nil πŸ€·β€β™‚οΈ
And this error might come up as well, with message is a tad unclear since it needs BOTH clientID and the refresh token, not or ?

    guard let refreshToken = oauthUser.refreshToken,
          let clientId = oauthUser.clientId else {
      throw TwiftError.UnknownError("Couldn't find refresh token or client ID")
    }

Hey @roblack, sorry for the radio silence on this one! Looks like you found the main cause of this issue: the refreshed credentials aren't accessible. I'd probably make a public property on the Twift class to access the current auth credentials, and perhaps add an optional callback method that can be invoked when the credentials are refreshed when initialising an instance (for example, saving the new credentials to the Keychain).

I can't remember how important it was to retrieve the client ID, so it may be that we don't need the guard let to unwrap the client ID (just the refreshed token).

I can probably work on this in the coming week. Thanks for flagging again!

commented

No worries about the delay, hope dealing with the little one is going ok πŸ‘ Got one here too πŸ˜…

I thought about whether to try to do this myself as well, just wanted to make sure I am not missing something about this refresh route.
I will make a PR tonight as I have made some efforts locally already, but if you feel that is not clean/straightforward enough, feel free to run over it :)

Closed by #31!