telenordigital / connect-ios-sdk

Docs 📒👉
https://telenordigital.github.io/id-docs.telenordigital.com/integrate-ios-sdk.html
Apache License 2.0
9 stars 8 forks source link

Refreshing Token still didn't work #19

Closed thihaaung6245 closed 8 years ago

thihaaung6245 commented 8 years ago

Since I have updated the latest update which handle refresh token error,it worked for a moment.But,I am still experiencing those error logs at console

iPhone 4, iOS : 8

RefreshToken not found
Refresh error=Optional(Error Domain=TDConnectIosSdk.OAuth2Error Code=0 "The operation couldn’t be completed. (TDConnectIosSdk.OAuth2Error error 0.)")

iPhone 6, iOS : 9.2.1

RefreshToken not found
Refresh error=Optional(Error Domain=TDConnectIosSdk.OAuth2Error Code=0 "(null)")

Every 1 hr,the access token is expire and it request new access token with refresh token.So,there might be something wrong with refresh token on SDK or the Connect Server Side which I still didn't figure it out for sure.Or may be the Refresh Token ExpireDate.I am collecting my own log time that I refresh token.I will post that log tomorrow.I mean which time I refresh token per day.

All my telenor services are working with Connect Access Token,So,If I don't have Access token,I can't do anything or can't request any services.As well as refreshing token,log in,revoke token from Connect.

Would you please take a look at this problem?

With Regards, Telenor Self-Care App iOS Developer.

jorunfa commented 8 years ago

Thanks for letting me know. I'll look into it as soon as I can.

jorunfa commented 8 years ago

I'm still looking into the issue, but the access_token does expire after 1 hour, so if you need to access user resources then you must have a non-expired access_token, if I'm not mistaking.

thihaaung6245 commented 8 years ago

Report to the issue.Here is the log that i tested on my iPhone 6 : iOS 9.3.1

June 2 2016 10:34 AM : INSTALL 11:34 AM : Refresh(Success,return new accesstoken) 12:41 PM : Refresh(Success,return new accesstoken) 1:45 PM : Refresh(Success,return new accesstoken) 2:45 PM : Refresh(Success,return new accesstoken) 4:00 PM : Refresh(Success,return new accesstoken) 5:00 PM : Refresh(Success,return new accesstoken)

June 3 2016 11:10 AM : Refresh(Success,return new accesstoken) 12:32 PM : Refresh(Success,return new accesstoken) 2:37 PM : Refresh(Success,return new accesstoken) 4:45 PM : Log Out (show me "AccessToken Not Found") So,Can’t Log Out (didn’t return any error,I think its stucking at the SDK somewhere else and didn't return me any error from Error response or completion handler.So,I am stucking at the middle)

6:00 PM : I did clear the app from memory and open again,it do refresh and show me this on console RefreshToken not found Refresh error=Optional(Error Domain=TDConnectIosSdk.OAuth2Error Code=0 "(null)")

Looks like the access token did clear itself at some condition or the refresh token.I think may be you need to check AccessTokenExpireDate or RefreshTokenExpireDate.I am trying my best to help you out solve this case.Hope this help.

thihaaung6245 commented 8 years ago

That issue also happen when user didn't refresh the app for long time...

jorunfa commented 8 years ago

Are you getting this when you sign out?

Signing out… response=Optional() error=nil AccessToken not found

Is the AccessToken not found at the end here the problem?

Currently the flow works like this when you sign out:

  1. You press Sign out
  2. The oauth2Module in SignedInViewController revokes the access of the tokens.
  3. When revoking the tokens are also set to nil.
  4. After that method completes it calls self.dismissViewControllerAnimated
  5. The SignedInViewController is then dismissed and the SignInViewController starts appearing.
  6. The viewDidAppear method is called in SignInViewController.
  7. This calls if oauth2Module!.isAuthorized()
  8. oauth2Module.isAuthorized() is -> return self.oauth2Session.accessToken != nil && self.oauth2Session.tokenIsNotExpired()
  9. When calling self.oauth2Session.accessToken here the console will print AccessToken not found if the accessToken is nil.

So every time isAuthorized() is called when the accessToken is nil the console will print AccessToken not found. See line 144 and line 166 in TrustedPersistantOAuth2Session.swift.

I understand if it looks like very much like an error. It's a bit misleading. Is that the problem?

thihaaung6245 commented 8 years ago

This log appear when I log out after I getting refresh error

RefreshToken not found
Refresh error=Optional(Error Domain=TDConnectIosSdk.OAuth2Error Code=0 "(null)")
Signing Out
AccessToken not found

I can manage the log out process.But, we have to do something with refreshing token error.

Here is my working flow :

We have middle-ware server that was working with every telenor services which also include Connect Integration.

1.Login > went to connect login web view > get access token> save the token in my keychain (because i don't know how to get the access token from the Connect SDK offline.)

2.When the token i save in keychain expire in 1 hr or every time I request to that middle-ware server with expire access token,it return Error Code which was "Access Token was Expired"

3.Then I refresh token using you code,

let config = TelenorConnectConfig(clientId: "tnmm-mytelenorapp-ios",
                                      redirectUrl: "tnmm-mytelenorapp-ios://connect/oauth2callback",
                                      useStaging: connect_server_states,
                                      scopes: ["profile", "openid", "email","phone"],
                                      accountId: "tnmm-mytelenorapp-ios")

oauth2Module = AccountManager.getAccountByConfig(config) ?? AccountManager.addAccount(self.config, moduleClass: TelenorConnectOAuth2Module.self)

self.oauth2Module?.refreshAccessToken({(accessToken:AnyObject?, error : NSError?)->Void in
            dispatch_async(dispatch_get_main_queue(), {
                      self.dismissViewControllerAnimated(true){
                            guard let accessToken = accessToken else {
                                     print("Refresh error=\(error)")
                                     self.showNotifyAlert("Refresh", message: (error?.localizedDescription)!)
                                     return
                             }
                             // update the updated token in my keychain
                             self.configurationUtil.save("Token", value: String(accessToken))
                             // then call remain web service when getting access token back.
                      }
             })
 })

Because my middle-ware server return result code when access token expire.I didn't check this code every time i refresh token.

guard let oauth2Module = self.oauth2Module else {
            return
        }

if oauth2Module.isAuthorized(){
}

Then after using server hours and do several refresh

RefreshToken not found
Refresh error=Optional(Error Domain=TDConnectIosSdk.OAuth2Error Code=0 "The operation couldn’t be completed. (TDConnectIosSdk.OAuth2Error error 0.)")
RefreshToken not found
Refresh error=Optional(Error Domain=TDConnectIosSdk.OAuth2Error Code=0 "(null)")

These above error happened which is I can't refresh token after getting such error.Log Out operation also failed too after getting such error.

thihaaung6245 commented 8 years ago

I think you need to check this code.

screenshot 2016-06-07 10 49 26

Looks like you clear refresh token automatically on the client.So,if the refresh token not found return me the above error I posted.I think you need to check something about refreshTokenExpireDate.

Hope this help.

jorunfa commented 8 years ago

Ok. First thing. You don't have to manually save any tokens when refreshing or requsting tokens. When you're using a TrustedPersistantOAuth2Session the tokens will be saved in KeyChain for you. See the highlighted line: image

This will call self.keychain.save(... -> image

Regarding the highlighted lines here: image You must have a refreshToken to be able to refresh the accessToken. That is why there is a guard there. If there is no refreshToken an error has occurred. Are you using TrustedPersistantOAuth2Session or UntrustedMemoryOAuth2Session?

We have middle-ware server that was working with every telenor services which also include Connect Integration.

I haven't heard of this middle-ware server before. What does it do? I will ask around if anyone else knows anything about the setup you have, but any more information you can give me would be helpful.

thihaaung6245 commented 8 years ago

I got 2 questions to ask :

  1. How do I get access token that is store on client side the one you posted? [Which is not included at HelloWorldExample]
  2. How to check that If I am using TrustedPersistantOAuth2Session or UntrustedMemoryOAuth2Session? because I just call oauth2Module.refreshAccessToken when I need to refresh token.

This is how we do about middle-ware server Client <-> Middle-ware Server (TopUp,Check Connect Access Token,Other services) <-> Telenor Server

Before we do anything else with the Telenor server it reach to Middle-ware sever first.So,lets talk about

Check Connect Access Token

When time that we need to refresh?Here is my working flow of middle ware server and me.

1.Client <-> Request Some Service -> Middle Ware (Check Token [The Access Token which got from Connect] with Telenor Connet Server ) <-> Connect (Check if expire or not)

2.Assume it was expire.

3.Connect <-> Return token was expire <-> Middle-ware (got the response from Connect which was expire token)

4.Middle-ware <-> Send Session Expire [Result Code] <-> Client

Then client read the result code and refresh the app using your oauth2Module.refreshAccessToken()

jorunfa commented 8 years ago

Getting accessToken

Calling requestAccess() will always give you a valid accessToken. image

You should never need to manually call refreshAccessToken. Just call requestAccess() when you want the accessToken.

oauth2Module!.requestAccess { (accessToken: AnyObject?, error: NSError?) in
    print("accessToken is -> \(accessToken)")
}

produces accessToken is -> Optional(rk9p2jpjgp37llCTn1jyRHehOht)

TrustedPersistantOAuth2Session

If you do not specify a OAuth2Session to the init function of OAuth2Module it will use TrustedPersistantOAuth2Session. image

thihaaung6245 commented 8 years ago

So,looks like i have to use requestAccess instead of refreshAccessToken when i try to refresh token.So,I need to know that state :

If I happen that,will it reach to ConnectWebView or will it automatically sign in without reaching ConnectWebView and give me access token i need?

jorunfa commented 8 years ago

If no user is signed in it will have to open a web view to authenticate and authorize the user. Specifically it will call requestAuthorizationCode(…, and on the last line here it will present a web view controller ->

image

thihaaung6245 commented 8 years ago

Hmmm,I see.Now,let me try with requestAccess() starting for now.If it didn't work out and happen error like this :

RefreshToken not found
Refresh error=Optional(Error Domain=TDConnectIosSdk.OAuth2Error Code=0 "(null)")

I will let you know.Thanks for the support.

jorunfa commented 8 years ago

Ok. Let me know what happens 👍

thihaaung6245 commented 8 years ago

Calling requestAccess() will always give you a valid accessToken.

  • If it is not expired, you will get the one saved in keychain.
  • If it is expired, but you have a refresh token, it will refresh the accessToken for you and give you that.
  • If you don't have an accessToken or a refreshToken (if a user is not signed in) then it will sign in the user and then give you the accessToken.

I am having strange situation with third condition.I am sign in to connect of course.But,looks like my accessToken and refreshToken expired after I haven't used the app for a period of time,like 2 days.

So,it reached the third condition that you mentioned but I am sign in user who didn't use the app for 2 days.But,strange behavior is,I have to login again for two times.

When the third condition reach,it bring me connect login page. After i clicked allow all permission,It dismissed web view controller(SFSafariViewController) and appeared again.So,I have to login two times.Then I got the access token,Can you check it whats wrong?

jorunfa commented 8 years ago

Yes, I will look into it.

thihaaung6245 commented 8 years ago

If u need some log,I will post here when I have it.

jorunfa commented 8 years ago

But,strange behavior is,I have to login again for two times.

I made a new release: 0.6.7. I think your problem will go away by using this latest version. Consider making the same changes as I made in the SignInViewController.

So,it reached the third condition that you mentioned but I am sign in user who didn't use the app for 2 days.

It is very strange that you don't have a valid Refresh Token after only 2 days. Refresh Tokens have an expiration date in the order of months. Are you refreshing directly or is the middleware server doing this?

thihaaung6245 commented 8 years ago

No,I am refreshing directly.Middle-ware only check accesstoken and see if valid or not. If it is not valid,it return response string "Token Expire" to my app and I do refreshing directly with Telenor Connect using your sdk method "requestAccess"

jorunfa commented 8 years ago

Did the latest version help with either of the two issues?

thihaaung6245 commented 8 years ago

Still not having that issue again....Besides its rare.I will let you know when that happen again.