I am using following code to handle twitter integration in my Application.
- (IBAction)signInWithTwitter:(id)sender {
NSURL *requestURL = [NSURL URLWithString:#"https://api.twitter.com/oauth/request_token"];
NSURL *accessURL = [NSURL URLWithString:#"https://api.twitter.com/oauth/access_token"];
NSURL *authorizeURL = [NSURL URLWithString:#"https://api.twitter.com/oauth/authorize"];
NSString *scope = #"http://api.twitter.com/";
GTMOAuthAuthentication *auth = [self authForTwitter];
[auth setCallback:#"http://www.noop.com/OAuthCallback"];
GTMOAuthViewControllerTouch *viewController;
viewController = [[GTMOAuthViewControllerTouch alloc] initWithScope:scope
language:nil
requestTokenURL:requestURL
authorizeTokenURL:authorizeURL
accessTokenURL:accessURL
authentication:auth
appServiceName:#"CK12: Twitter"
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
}
- (GTMOAuthAuthentication *)authForTwitter {
GTMOAuthAuthentication *auth = [[GTMOAuthAuthentication alloc] initWithSignatureMethod:kGTMOAuthSignatureMethodHMAC_SHA1
consumerKey:TWITTER_CONSUMER_KEY
privateKey:TWITTER_CONSUMER_SECRET];
[auth setServiceProvider:#"Twitter"];
return auth;
}
My problem is, if I am changing device time i.e making it 1 hour late, then I am getting following error:
Error Domain=com.google.HTTPStatus Code=401 and error message is : failed to validate oauth signature and token .
So can anybody please suggest how to solve this. if system time is wrong then also I want to make it work .
Finally I got solution for this . . . .
One of the reason we get this error "Failed to validate OAuth signature and token"
when system time is wrong . Because OAuth request carry system timestamp parameters with it , so when device time is not within the 5 minutes of twitter server time .we get "Failed to validate OAuth signature and token" .
There are two ways to make it work , if the device time is even wrong .
1.make HTTP HEAD request to an endpoint on api.twitter.com -- you'll get a Date HTTP header in the response that indicates the current time understood by Twitter. You would then convert this to epoch time and adjust your oauth_timestamp values by a determined offset.
2.There's a small iOS library named ios-ntp link: http://code.google.com/p/ios-ntp . use this to get the current Accurate time .
After that i just set the timestamp of OAuth object in the following method
- (GTMOAuthAuthentication *)authForTwitter
{
GTMOAuthAuthentication *auth = [[GTMOAuthAuthentication alloc]
initWithSignatureMethod:kGTMOAuthSignatureMethodHMAC_SHA1
consumerKey:TWITTER_CONSUMER_KEY
privateKey:TWITTER_CONSUMER_SECRET];
[auth setServiceProvider:#"Twitter"];
NSDate * currentdate = //GET ACCURATE DATE HERE ;
[auth setTimestamp:[NSString stringWithFormat:#"%f",[currentdate timeIntervalSince1970]]];
return auth;
}
that's it . . .Happy Coding :)
Related
I use the following function to get the optimal route.
https://wse.ls.hereapi.com/2/findsequence.json?start=25.082621,121.583021&destination1=25.097258,121.517384&destination2=25.041825,121.514988&destination3=25.026060,121.527532&destination4=25.034607,121.488616&destination5=25.063467,121.539141&destination6=25.070833,121.531389&destination7=25.023056,121.505278&destination8=25.093102,121.532366&destination9=25.094807,121.529036&destination10=25.075230,121.560761&destination11=25.093102,121.532366&destination12=25.118899,121.470798&mode=fastest;car&&apiKey=...
And try to use this (HERE SDK FOR IOS (PREMIUM EDITION) V3.17) :
NMARoutingMode *routingMode = [[NMARoutingMode alloc] initWithRoutingType:NMARoutingTypeFastest transportMode:NMATransportModeScooter routingOptions:NMARoutingOptionAvoidHighway];
NMACoreRouter *coreRouter = [[NMACoreRouter alloc] init];
coreRouter.connectivity = NMACoreRouterConnectivityOnline;
[coreRouter calculateRouteWithStops:stops routingMode:routingMode completionBlock:^(NMARouteResult * _Nullable routeResult, NMARoutingError error) {
}];
to bring out NMARouteResult, but it only respond NMARoutingErrorInvalidOperation
How do I solve the problem?
The error indicates that another request is already being processed. Please make sure you are not calling the route calculation until the result of the previous request is returned.
I am using QuickBlox iOS SDK (version 2.9.2) and got a failure with error code 422 when calling
[QBRequest createObject:qbcoCustomObject successBlock:^(QBResponse *response, QBCOCustomObject *object) {
} errorBlock:^(QBResponse *response) {
}];
It happens OCCASIONALLY and does not resume until I logout and login QuickBlox again.
The error message is as follows:
2017-04-24 06:18:45.855557 App[8720:4958563] [QBCore] Response error: Error Domain=com.alamofire.error.serialization.response Code=-1011 "Request failed: client error (422)" UserInfo={com.alamofire.serialization.response.error.response=<NSHTTPURLResponse: 0x17422ed40> { URL: https://api.quickblox.com/data/MyCircleComments.json } { status code: 422, headers {
"Access-Control-Allow-Origin" = "*";
"Cache-Control" = "no-cache";
Connection = "keep-alive";
"Content-Length" = 45;
"Content-Type" = "application/json; charset=utf-8";
Date = "Mon, 24 Apr 2017 12:18:45 GMT";
"QB-Token-ExpirationDate" = "2017-04-24 14:09:35 +0000";
"QuickBlox-REST-API-Version" = "0.1.1";
Server = "openresty/1.9.15.1";
Status = "422 Unprocessable Entity";
"X-Rack-Cache" = "invalidate, pass";
"X-Request-Id" = 89f509abd6fd7f61d02e34ae9e83ce70;
"X-Runtime" = "0.009477";
"X-UA-Compatible" = "IE=Edge,chrome=1";
} }, NSErrorFailingURLKey=https://api.quickblox.com/data/MyCircleComments.json, com.alamofire.serialization.response.error.data=<7b226572 726f7273 223a7b22 62617365 223a5b22 466f7262 69646465 6e2e204e 65656420 75736572 2e225d7d 7d>, NSLocalizedDescription=Request failed: client error (422)}
2017-04-24 06:18:45.856659 App[8720:4958563] [QBCore] Response error reasons: {
errors = {
base = (
"Forbidden. Need user."
);
};
}
Due to the fact that it resumes only after I logout and login again, I was thinking that it may be related to session expiry. I added login method at the app's didFinishLaunching and didBecomeActive so that the app will automatically re-login to make sure the login session be valid. The login method I use is
[QBRequest logInWithUserLogin:sUsername password:sPassword successBlock:^(QBResponse *response, QBUUser *user) {
} errorBlock:^(QBResponse *response) {
}];
and by setting breakpoints I am sure each time the auto relogin did succeed.
However, app's auto-relogin does not work. The failure still happens occasionally and the only way out is logout and login manually.
I googled this issue and found a bunch of topic but none seems to meet my problem. (One post suggests that the time of device may not be synchronized but actually my iPhone is using the network time.)
Can anyone give me a hint why it fails and a solution is highly appreciated. Thanks in advance.
One of the best answer for above issue:-
**"Bad timestamp means that you send invalid timestamp value on session creation, which is based on your phone time. Your device time shouldn't differ from server more than 2 hours.
We suggest you synchronize time on your devices with NTP service or just set tick 2 checkboxes in Settings in your device: Automatic date & time and Automatic time zone.
Hope this help"**
Ref :- https://github.com/QuickBlox/quickblox-ios-sdk/issues/452
From setting of the device set timezone automatic on.
Hope this will help you.
Try to get Quickblox session token
[[[QBSession currentSession] sessionDetails] token];
And check session type via REST API
//QuickBlox Documentation
curl -X GET \
-H "QuickBlox-REST-API-Version: 0.1.0" \
-H "QB-Token: 8b75a6c7191285499d890a81df4ee7fe49bc732a" \
https://api.quickblox.com/session.json
If field "user_id" of your token will be equal to 0 this mean that you have "application-token" type, and you cannot create or update items on QBlox, after login with session token "upgrades" to "user-token"
I have similar issue, and i made extra check, if token-type is application, then you need login with same user again (recursively call login method if you can), i know that its a workaround, but we cant dig deeper because all locked in Quickblox.framework
I use Restkit in my iOS app to call an API.
When the app first launched, a client token is retrieved from the API in order to call the service to post a new user.
After this user has successfully being created, a new access token is sent back by the API. This time is it is a user token.
All the other requests to the API made by the app will now have to use this user token.
I am using a singleton class that inherits from RKObjectManager. I then built one class per ressource to access (example : Users, Images, ...) all inheriting from that main class called AKObjectManager.
In AKObjectManager I have the following method :
+ (instancetype)sharedManager
{
NSURL *url = [NSURL URLWithString:LLY_API_BASE_URL];
AKObjectManager *sharedManager = [self managerWithBaseURL:url];
sharedManager.requestSerializationMIMEType = RKMIMETypeJSON;
...
// Access Token
NSUserDefaults* userData = [NSUserDefaults standardUserDefaults];
if ([userData objectForKey:#"accessToken"]) {
// Not too sure if this is being taken into account for the other class that inherits
[ sharedManager.HTTPClient setDefaultHeader:#"Authorization" value:[userData objectForKey:#"accessToken"]];
}
return sharedManager;
}
I thought that by checking for every access the accessToken in NSUserDefaults and setting it in the Authorization field in the header would work but no. I can see through NSLog that the new access token is set when changing it for for some reasons using Charles the header of the request still points to the old one.
I then used
[[AKObjectManager sharedManager].HTTPClient setDefaultHeader:#"Authorization" value:accessToken.accessToken];
As soon as I got the new token but faced the same issue.
Finally I went for that road (UserManager inherits from AKObjectManager)
// Force the newly refresh token to be set in the Authorization header
[[UserManager sharedManager].HTTPClient setDefaultHeader:#"Authorization" value:[[NSUserDefaults standardUserDefaults] objectForKey:#"accessToken"]];
[[UserManager sharedManager] show:nil // userId equals nil meaning it will be replaced by 'self'
success:^(User* user){
self.user = user;
...
And it worked but I am not too happy about the implementation.
Could you point me to where I got it wrong and advise on how to do it ?
I am currently working on an IOS app and I want to use OAuth to authenticate this app with a Grails system we have in place. The grails system has a OAuth2 provider setup using the plugin at the link below:
https://github.com/adaptivecomputing/grails-spring-security-oauth2-provider
The OAuth provider is setup and it does work as I have tested the URL's shown below and I do get an authorisation code as expected once the access has been granted:
http://localhost:8080/app/oauth/authorize?response_type=code&client_id=clientId&redirect_uri=http://localhost:8080/app/
The issue I am having is that when I use the GTM OAuth plugin for IOS from google I have set it up as follows:
static NSString *const kMyClientID = #"1";
static NSString *const kMyClientSecret = #"secret";
static NSString *const kKeychainItemName = #"systemKeychain";
- (GTMOAuth2Authentication *)systemAuth
{
// Set the token URL to the system token endpoint.
NSURL *tokenURL = [NSURL URLWithString:#"http://www.systemurl.co.uk/oauth/token"];
// Set a bogus redirect URI. It won't actually be used as the redirect will
// be intercepted by the OAuth library and handled in the app.
NSString *redirectURI = #"http://www.systemurl.co.uk/";
GTMOAuth2Authentication *auth;
auth = [GTMOAuth2Authentication authenticationWithServiceProvider:#"SYSTEM API"
tokenURL:tokenURL
redirectURI:redirectURI
clientID:kMyClientID
clientSecret:kMyClientSecret];
return auth;
}
- (void)authorize:(NSString *)service
{
GTMOAuth2Authentication *auth = [self systemAuth];
// Prepare the Authorization URL. We will pass in the name of the service
// that we wish to authorize with.
NSURL *authURL = [NSURL URLWithString:[NSString stringWithFormat:#"http://www.systemurl.co.uk/oauth/authorize"]];
// Display the authentication view
GTMOAuth2ViewControllerTouch *viewController;
viewController = [ [GTMOAuth2ViewControllerTouch alloc] initWithAuthentication:auth
authorizationURL:authURL
keychainItemName:kKeychainItemName
delegate:self
finishedSelector:#selector(viewController:finishedWithAuth:error:)];
[viewController setBrowserCookiesURL:[NSURL URLWithString:#"http://www.systemurl.co.uk/"]];
// Push the authentication view to our navigation controller instance
[ [self navigationController] pushViewController:viewController animated:YES];
}
- (void)viewController:(GTMOAuth2ViewControllerTouch *)viewController
finishedWithAuth:(GTMOAuth2Authentication *)auth
error:(NSError *)error
{
if (error != nil)
{
// Authentication failed
UIAlertView *alertView = [ [UIAlertView alloc] initWithTitle:#"Authorization Failed"
message:[error localizedDescription]
delegate:self
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[alertView show];
}
else
{
// Authentication succeeded
// Assign the access token to the instance property for later use
self.accessToken = auth.accessToken;
// Display the access token to the user
UIAlertView *alertView = [ [UIAlertView alloc] initWithTitle:#"Authorization Succeeded"
message:[NSString stringWithFormat:#"Access Token: %#", auth.accessToken]
delegate:self
cancelButtonTitle:#"Dismiss"
otherButtonTitles:nil];
[alertView show];
}
}
The issue is when I run the code above it redirects me to the system fine and I log in, then the page comes up for me to grant access to this app and I click "Authorize" and the app shows me an alert view with an error 500 in it.
So I went back to the Grails system and looked at the logs to see what happened and I noticed the url being passed in by the app was:
"GET /oauth/authorize?client_id=1&redirect_uri=http%3A%2F%2Fwww.systemurl.co.uk%2F&response_type=code HTTP/1.1" 302 -
"GET /oauth/authorize?client_id=1&redirect_uri=http%3A%2F%2Fwww.systemurl.co.uk%2F&response_type=code HTTP/1.1" 200 6923
"POST /oauth/authorize?client_id=1&redirect_uri=http%3A%2F%2Fwww.systemurl.co.uk%2F&response_type=code HTTP/1.1" 302 -
and the error 500 message is shown below from the system:
2014-03-24 08:25:53,081 [http-8080-2] ERROR errors.GrailsExceptionResolver - NoSuchClientException occurred when processing request: [POST] /oauth/token - parameters:
client_secret: secret
grant_type: authorization_code
redirect_uri: http://www.systemurl.co.uk/
code: 4bf5Se
client_id: 1
No client with requested id: testing. Stacktrace follows:
org.springframework.security.oauth2.provider.NoSuchClientException: No client with requested id: testing
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:179)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at grails.plugin.springsecurity.web.filter.GrailsAnonymousAuthenticationFilter.doFilter(GrailsAnonymousAuthenticationFilter.java:53)
at grails.plugin.springsecurity.web.authentication.RequestHolderAuthenticationFilter.doFilter(RequestHolderAuthenticationFilter.java:49)
at grails.plugin.springsecurity.web.authentication.logout.MutableLogoutFilter.doFilter(MutableLogoutFilter.java:82)
at java.lang.Thread.run(Thread.java:722)
Now the error above would suggest to me that for some reason the username is being used as a client id somehow and I don't know why, as the username and password are "testing" on the grails system.
Can anyone please offer any advise on why this might be happening?
Thanks in advance
***EDIT*****
I have debugged the HTTP requests being sent and the below is the RAW request being sent to get the token:
POST /oauth/token HTTP/1.1
Host: www.systemurl.co.uk
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Accept-Language: en-us
Cookie: JSESSIONID=70EB045C21084E166A34EDA88FE155C8.28151
Accept: */*
Content-Length: 130
Connection: keep-alive
User-Agent: gtm-oauth2 com.test.OAuthGTM/1.0
client_id=1&client_secret=secret&code=VaYn8M&grant_type=authorization_code&redirect_uri=http%3A%2F%2Fwww.systemurl.co.uk%2F
The short answer is: "client_id=public", then it works
The long answer:
If you debug through the code, you'll find out that the exception is thrown in InMemoryClientDetailsService.
In Grails Version 2.2.4 the code looks something like this
private Map<String, ? extends ClientDetails> clientDetailsStore = new HashMap<String, ClientDetails>();
public ClientDetails loadClientByClientId(String clientId) throws OAuth2Exception {
ClientDetails details = clientDetailsStore.get(clientId);
if (details == null) {
throw new InvalidClientException("Client not found: " + clientId);
}
return details;
}
In the Map clientDetailsStore is only one value which is "public"
Can anyone help me , I want to Download the connection of LinkedIn and Add into iPhone Address Book.
I googled it but not getting any help.
I am using following Api :
NSURL *url = [NSURL URLWithString:#"http://api.linkedin.com/v1/people/~/connections"];
and I am getting the response like:
profile {
errorCode = 0;
message = "Access to connections denied";
requestId = GVG2FXA2N0;
status = 403;
timestamp = 1366641414499;
}
There is AddressBook framework for that:
http://developer.apple.com/library/ios/#documentation/ContactData/Conceptual/AddressBookProgrammingGuideforiPhone/
a wrapper library:
http://maniacdev.com/2012/02/open-source-ios-address-book-wrapper-library-providing-automatic-hashing-and-permission-alerts/
Simple tutorial:
http://programming4.us/mobile/9260.aspx
You must be missing r_network scope.Even I was getting same error. But when I added r_network scope the problem resolved