I have a standard iOS app from QuickStart downloaded from my portal like so:
Its a very basic iOS app that communicates with the Azure backend where you can push and pull data.
log in, log out
If you are to turn on authentication in your portal, you will need to log in. You do so like this:
[client loginWithProvider:@"windowsazureactivedirectory"
controller:controller
animated:YES
completion:^(MSUser *user, NSError *error) {
// save data into your keychain
// invoke various custom APIs
// be able to pull and push data to your Easy Table
}];
Log out is also simple:
[client logoutWithCompletion:^(NSError * _Nullable error) {
if(!error) {
[self clearCredentials];
complete(nil);
} else {
DDLogError(@"%@", [error debugDescription]);
complete(error);
}
}];
Refreshing the Token
My problem is the token. I understand that when using Active Directory, the token they give you lasts for 1 hour only. If you were to get a Refresh token, you need to use it within 14 days. If you do use it within 14 days, it will be good up to 90 days after that.
Hence, I waited an hour, and when I try using the client to pull data or invoke an API, it would give me an 401 error:
Error Domain=com.Microsoft.MicrosoftAzureMobile.ErrorDomain Code=-1301 "The server returned an error." UserInfo={com.Microsoft.MicrosoftAzureMobile.ErrorResponseKey= { URL: https://xxxx-xxxxxx.azurewebsites.net/api/getUserProfileData } { status code: 401, headers { "Content-Length" = 0; Date = "Tue, 25 Oct 2016 09:18:57 GMT"; Server = "Microsoft-IIS/8.0"; "Set-Cookie" = "ARRAffinity=743d3a9e04f3c081f27c2f2c3af95d099f93dc60f14553bd4423b0abc62cfd33;Path=/;Domain=xxxx-xxxxxx.azurewebsites.net"; "Www-Authenticate" = "Bearer realm=\"xxxx-xxxxxx.azurewebsites.net\""; "X-Powered-By" = "ASP.NET"; } }, NSLocalizedDescription=The server returned an error., com.Microsoft.MicrosoftAzureMobile.ErrorRequestKey= { URL: https://xxxx-xxxxxx.azurewebsites.net/api/getUserProfileData }}
The log for my custom node script that the client hits, gives 401.71 unauthorized error:
2016-10-25T09:18:55 PID[35372] Warning JWT validation failed: IDX10223: Lifetime validation failed. The token is expired. ValidTo: '10/25/2016 09:12:31' Current time: '10/25/2016 09:18:55'.. 2016-10-25T09:18:55 PID[35372] Information Sending response: 401.71 Unauthorized
If I were to do a pull down on my table to grab data:
com.Microsoft.MicrosoftAzureMobile.ErrorRequestKey= { URL: https://xxx-xxxxx.azurewebsites.net/tables/TodoItem?$skip=0&$filter=(updatedAt%20ge%20datetimeoffset'2016-10-20T02%3A33%3A25.607Z')&$orderby=updatedAt%20asc&__includeDeleted=true&$top=50 }} code - -1301 domain - com.Microsoft.MicrosoftAzureMobile.ErrorDomain userInfo - { NSLocalizedDescription = "The server returned an error."; "com.Microsoft.MicrosoftAzureMobile.ErrorRequestKey" = " { URL: https://xxxx-xxxxxx.azurewebsites.net/tables/TodoItem?$skip=0&$filter=(updatedAt%20ge%20datetimeoffset'2016-10-20T02%3A33%3A25.607Z')&$orderby=updatedAt%20asc&__includeDeleted=true&$top=50 }";
Microsoft Azure has a small article on refreshing tokens here: https://azure.microsoft.com/en-us/blog/mobile-apps-easy-authentication-refresh-token-support/
I would use refreshUserWithCompletion: method, but it keeps giving me 403 error.
Hence, if anyone have successfully refreshed their token on an iOS app, please comment.
thank you!
UPDATE: REFRESH WORKS, TOKEN STILL EXPIRES IN 1 HOUR
After following the links, my refreshUserWithCompletion method works, and returns a valid MSUser object with token. However, the issue is that this token is still only good for 1 hour. I'm pasting my refresh token code below. Please suggest, thanks!
if(!client.currentUser) {
[client loginWithProvider:@"windowsazureactivedirectory"
controller:controller
animated:YES
completion:^(MSUser * user, NSError *error) {
DDLogInfo(@"INITIAL TOKEN, userId: %@, token: %@", user.userId, user.mobileServiceAuthenticationToken);
if(!error && user) {
[client refreshUserWithCompletion:^(MSUser * _Nullable user, NSError * _Nullable error) {
// user object now has new token for us to use.
// I'm assuming this is the refresh token.
[self saveUserIntoKeyChain: user];
// I can just load the userId and token from the keychain for future uses, and they all work.
// The only problem is that this token is only good for 1 hour.
}];
}
}];
}