Facing login issue with loginWithAccesstoken for docusign - ios

Update: problem Resolved: Check below comments
Using Docusign as a framework, during login it is giving below error.
Error Domain=user.additional.data.fetch.error Code=-1016 "Unable to fetch additional data for user - Request failed: unacceptable content-type: text/html" UserInfo={NSLocalizedDescription=Unable to fetch additional data for user - Request failed: unacceptable content-type: text/html, NSLocalizedFailureReason=USER_ADDITIONAL_DATA_FETC
Below is data used for login
NSString * userName = #"D*****y";
NSString * accessToken = #"eyJ0eXAiOiJNVCIsImFsZyI6IlJTMjU2Iiwia2lkIjoiNjgxODVmZjEtNGU1MS00Y2U5LWFmMWMtNjg5ODEyMjAzMzE3In0.AQoAAAABAAUABwAAEozC_7LZSAgAAFKv0EKz2UgCADH-vovuycJOtx8b-0T42BgVAAEAAAAYAAEAAAAFAAAADQAkAAAAMDFmZmFjMmQtMWU2Zi00OTk2LTlmMTgtM2E0MWMzNmVkZmMwIgAkAAAAMDFmZmFjMmQtMWU2Zi00OTk2LTlmMTgtM2E0MWMzNmVkZmMwMACAkGNv-rLZSDcAct05PIuJOEitb0Mnkb4e_A.UdjyVjBFNUL6Lq7H5ulDAOe_NhpygYGQHKUyAJYdEthfo8EXIX6DEE5aLZLdKxnB-CjrTFz9NWjGkIVUFpXuDPukWgWkuWDRNI0s57fe09rws4JAsIovlh0regrd1eh-wGUwAhLLqzivtmz-fR23PVryCeUll-JsS-y_PCfrfZDQJj4JQ3D44olnSDvvYQ-tyDBChwLatPiwWBnD9ef4UHWZzp2dYbnURhkhVM7SgXXnhkz5FF1J-bUmSVPURDAkGIx8TA5VpXPA2gxt5ydo01IDk5pe1OWJCBC9Tue89SSLysum1NoFbzvhpGPRB2IMDmKg7J8QYoSy1-*******";
NSString * userId = #"8bbefe31-****-4ec2-****-1bfb44f8d818";
NSString * accountId = #"1******6";
NSString * email = #"kdines*****#gmail.com";
NSString * demoHostApi = #"https://account-d.docusign.com/";
NSString * integratorKey = #"01ffac2d-****-4996-****-3a41c36edfc0";
Below function is used for login
[DSMManager loginWithAccessToken:accessToken accountId:accountId userId:userId userName:userName email:email host:[NSURL URLWithString:hostApiUrl] integratorKey:integratorKey completion:^(DSMAccountInfo *accountInfo, NSError *error) {
}];

First, off, it appears you have a hardcoded access token. That may work for a while, but these tokens expire after 8 hours and it's not a long term solution to copy/paste them into your code.
As Paul pointed out the URL to make API calls in DocuSign (for the eSignature API) are : https://demo.docusign.net/restapi in the developer account and https://www.docusign.net/restapi in production (although you may have a different one for your account)
Best practice is to call the getUserInfo which provides the list of one or more accounts for the logged in user. The account information includes the baseURI which can be used to make API calls.

Related

Do I need to refresh the access token when using Microsoft Graph and How to do it?

I'm using Microsoft Graph SDK for my iOS Application.
Do I need to manually refresh the access token when it expired?
The access token I'm talking about is:
NXOAuth2AccountStore.sharedStore().accounts[0].accessToken
I have tested that I can still query even the accessToken expired. At the time I first logged in, the expired time is 3600 secs. So, I waited 2 hours, test to get user info, events again and still can get it.
I have dump "accessToken.hasExpired" and "accessToken.expiresAt" to make sure access token is expired
Thanks
* More Details *
I follow the sample here:
https://github.com/microsoftgraph/ios-swift-connect-sample
I cannot find any documents about refresh access token on Microsoft Graph:
https://graph.microsoft.io/en-us/code-samples-and-sdks
Yes, you need to refresh tokens periodically when using Graph in your application. More detailed documentation is available through Azure AD's site: https://learn.microsoft.com/en-us/azure/active-directory/active-directory-authentication-scenarios
The suggested auth library you are using contains a method for refreshing this token:
#implementation NXOAuth2AuthenticatorRefreshCallback
If I haven't answered your question, could you be more specific about what you are trying to accomplish? Are you able to use an expired token or are you unable to refresh your old one?
Use this code whenever you need to refresh the access token.
This will act as a patch to predefined code provided in graph sdk and you can extract the token from the method :
+(id)tokenWithResponseBody:(NSString *)theResponseBody tokenType:(NSString *)tokenType;
[MSGraphClient setAuthenticationProvider:AppDel.authentication.authProvider];
_graphClient = [MSGraphClient client];
NSMutableURLRequest * sampleReq = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:#"https://graph.microsoft.com/v1.0/me"]];
[_graphClient.authenticationProvider appendAuthenticationHeaders:sampleReq completion:^(NSMutableURLRequest *request, NSError *error){
if(error == nil)
{
}
else
{
[self showToast:#"" message:#"Failure in refresh 0365 token"];
}
}];

Developer Authenticated Identities with Amazon

I'm not familar very well with Amazon so have few questions:
I want to perform login for users on amazon with Cognito using my own custom backEnd solution. Found this like possible solution. This backEnd return after registering and logging for me
{
identityId = "eu-xxxx-x:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx";
login = 1;
token = "eyJraWQiOiJldS13ZXN0LTExIiwidHlwIjoiSldTIiwiYWxnIjoiUlM1MTIifQ.eyJzdWIiOiJldS13ZXN0LTE6NGFmNDdmMWItZDNmOC00NmZkLWI2MzEtZGE2OGU3ZmRmYzE1IiwiYXVkIjoiZXUtd2VzdC0xOjIwNjBiZDc3LWEwNDAtNGI4OC05MDU4LTczMGY3Y2RmNGQyZSIsImFtciI6WyJhdXRoZW50aWNhdGVkIiwibG9naW4ud3A0Lm15YXBwIiwibG9naW4ud3A0Lm15YXBwOmV1LXdlc3QtMToyMDYwYmQ3Ny1hMDQwLTRiODgtOTA1OC03MzBmN2NkZjRkMmU6a2lyaWxsLmdlQGdtYWlsLmNvbSJdLCJpc3MiOiJodHRwczovL2NvZ25pdG8taWRlbnRpdHkuYW1hem9uYXdzLmNvbSIsImV4cCI6MTQ1NTI5MDA5OSwiaWF0IjoxNDU1Mjg5MTk5fQ.FGnBUEQZ3wDENFNa_g29l2UhlIAklBnLdqpMomSE3_ayesNV1dqGyzAMQCvwyr4XdJpB3lI0KF-k3wc4t8BKPYg5QKrZ-q-aNkjwp34tHFMIr8vGw4vbZiKB6XnGMRghYSbPtuwwFG80ibZMAAXik4nld8sGxoQSrCjTubPKU4I9Mzi6lJQsDGAZxmm56E2lVSeBw2nZbE1iwRDhJf6hHJsKOLceDDtWoknRX3NHeNuoueNLS1JrbphD8wVqejxhEjrK-qucoUL_uj81GxYUkyONQtu-3B79epsXIsxvU_zW1MwVufFg5p5ID83F1Cic77QkzF2FJnEJIadEG6R_yw";
}
I want follow this guide. But according to this i should provide IdentityProviderName and token and set it like after any social's login :
credentialsProvider.logins = #{
#(AWSCognitoLoginProviderKeyFacebook): token
};
As IdentityProviderName i used name that was setted in config.json
"DEVELOPER_PROVIDER_NAME": "<ProviderName>"
But i got exception that i havent any provider
AWSCognitoCredentialsProvider
getCredentialsWithCognito:authenticated:]_block_invoke |
GetCredentialsForIdentity failed. Error is [Error
Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=8 "(null)"
UserInfo={__type=InvalidParameterException, message=Please provide a
valid public provider}]
When i go to IAM Console to create providerID it ask me to choose type of provider (OpenID or SAML)
So i'm really dont understand what exactly should i put there? what type to select.
For server i used Lambda service with DynamoDB service, for web pages used S3.
According to this flow:
I already complete first 4 steps and i'm stack on 5 step, So i need only to send this data to Cognito (no needs to prepare my custom dev provider, because i already have idendityID and token, thats looks like incorrect).
As result
developer Auth - only for login method from lambda but when i try to use DynamoDB user are not auth.
All roles are added - currently i add temp role for Unath users
{
"Sid": "DynamoDBPolicy",
"Effect": "Allow",
"Action": [
"dynamodb:*"
],
"Resource": [
"*"
]
}
All works (huh) but it's not really good
Question - how to make Cognito DevAuth with received token from my backEnd solution placed on Lambda? Does i miss something?
UPDATE
thanks to #Rachit Dhall
AWSCognitoIdentity *cognitoIdentity = [AWSCognitoIdentity defaultCognitoIdentity];
AWSCognitoIdentityGetCredentialsForIdentityInput *input = [[AWSCognitoIdentityGetCredentialsForIdentityInput alloc] init];
input.identityId = [task.result valueForKey:#"identityId"];
input.logins = #{
#"cognito-identity.amazonaws.com" : [task.result valueForKey:#"token"]
};
[cognitoIdentity getCredentialsForIdentity:input completionHandler:^(AWSCognitoIdentityGetCredentialsForIdentityResponse * _Nullable response, NSError * _Nullable error) {
//how to update my configuration for AWS with
//AWSCognitoIdentityCredentials object?
}];
but not sure what to do with AWSCognitoIdentityCredentials received in response - how to update my configuration?
Also found next:
Does it mean that there is no another way for this? Or something missed?
The error which says present a valid public provider issue, is because you are calling GetCredentialsForIdentity with your login provider. But instead the flow is that you call GetOpenIdTokenForDeveloperIdentity from your backend, you get a token as response. Then to get credentials you call GetCredentialsForIdentity with key cognito-identity.amazonaws.com in the logins parameter and value as the token received from previous call.
Update:
To make sure Amazon DynamoDB uses credentials vended by Amazon Cognito you can create a default AWSServiceConfiguration with your credentials provider and use this to initialize the client.
// create a configuration that uses the provider
AWSServiceConfiguration *configuration = [AWSServiceConfiguration configurationWithRegion:AWSRegionUSEast1 provider:credentialsProvider];
// get a client with the default service configuration
AWSDynamoDB *dynamoDB = [AWSDynamoDB defaultDynamoDB];

Evernote iOS SDK - How do I authenticate with a token?

I am using Evernote SDK for iOS and I am saving the authentication token when the user has authorized access.
Once the user installs my application on a different device, I want to use that token to reauthenticate automatically, but it looks like SDK doesn't support that. Is there a way to do that?
I had the same issue last week, and their SDK indeed doesn't support it out-of-the-box, but after some research I found a solution that works perfectly. This solution mimics a valid authentication flow.
A little background:
When the ENSession class initializes, it retrieves the credentials that are saved on the keychain (unless [[ENSession sharedSession] unauthenticate] was called earlier). The problem is that the keychain is empty when using a different device, so our goal is to add a valid ENCredentials instance to the ENCredentialStore.
Solution:
Add the following imports to your code: ENCredentials.h and ENCredentialStore.h. We will need them later.
Initialize the ENSession like you already do, using setSharedSessionConsumerKey:(NSString *)key consumerSecret:(NSString *)secret optionalHost:(NSString *)host.
In order to create a valid ENCredentials object, we need to provide the following objects:
NSString * host
NSString * edamUserId
NSString * noteStoreUrl
NSString * webApiUrlPrefix
NSString * authenticationToken
NSDate * expirationDate
The host is always www.evernote.com (as defined in ENSession under ENSessionBootstrapServerBaseURLStringUS).
edamUserId is the user id you received when you got the original token. Same for the expirationDate. If you are not sure how to get them then you should use [[ENSession sharedSession].userStore getUserWithSuccess:^(EDAMUser *user) once authenticated.
So the only objects that are actually missing are noteStoreUrl and webApiUrlPrefix. Their format is always:
noteStoreUrl: https://www.evernote.com/shard/edam_shard/notestore
webApiUrlPrefix: https://www.evernote.com/shard/edam_shard/
Luckily, your token already contains edam_shared (value of S=, see this):
#"S=s161:U=5ce3f20:E=1561182201b:C=24eb9d000f8:P=285:A=app:V=2:H=e8ebf56eac26aaacdef2f3caed0bc309"
If you extract s161 and put it in the URLs above it will work (I am sure you know how to extract that, but let me know if you're having problems).
Now we are ready to authenticate using the token. First, expose the necessary functions from ENSession using a category:
#interface ENSession(Authentication)
- (void)startup;
- (void)addCredentials:(ENCredentials *)credentials;
#end
And authenticate using the token:
ENCredentials *credentials = [[ENCredentials alloc] initWithHost:ENSessionBootstrapServerBaseURLStringUS edamUserId:userId noteStoreUrl:noteStoreUrl webApiUrlPrefix:webApiUrlPrefix authenticationToken:token expirationDate:expirationDate];
[[ENSession sharedSession] addCredentials:credentials];
[[ENSession sharedSession] startup];
The last line is important in order to refresh the ENSession and retrieve the new stored credentials.
Now you are authenticated and ready to query the SDK. Good luck.

Apigee user authentication, access_token, and cache login session in iOS

I'm new to Apigee and can't seem to wrap my head around it. I am familiar with implementing an iOS app that talks to a database via a webservice call. The call would involve passing back and forth JSON or variables though POST, GET, etc.
The user flow I envision is a lot like Facebook long term token storage. Here are the steps:
Type username and password to login.
The app will remember the access_token in the keychain.
The access_token will be used with any future requests such as updating profile. This way the user doesn't have re-login every time he/she is using the app.
Log out will clear all the token.
If the token is invalid or expired, the app will take the user back to login.
I've taken multiple routes and ended up getting stuck on all of them when it comes to Apigee.
ROUTE 1
I made a call to logInUser and receive access_token in return.
[self.apigeeDataClient logInUser:username password:password];
All this is good until I want to update user's email address using the code below.
NSMutableDictionary *requestDict = [NSMutableDictionary dictionary];
[requestDict setObject:email forKey:kDataEmail];
NSString *url = [NSString stringWithFormat:#"%#/%#/%#/users/%#?access_token=%#", BASE_URL, UG_ORG_NAME, APP_NAME, [userData objectForKey:kDataUUID], self.accessToken];
NSString *op = #"PUT";
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[NSDictionary dictionaryWithDictionary:requestDict]
options:0
error:&error];
[self.apigeeDataClient apiRequest:url operation:op data:[NSString stringWithUTF8String:[jsonData bytes]]];
It seems that every other time it's giving me "No content to map to Object due to end of input" error. I checked out this thread but have no luck. I made sure the JSON object is not null. I tried changing the operation from PUT to POST and GET. None of which update the email address in the database.
ROUTE 2
Instead of using apiRequest, I switched to updateEntity.
NSMutableDictionary *requestDict = [NSMutableDictionary dictionary];
[requestDict setObject:email forKey:kDataEmail];
[requestDict setObject:kDataUsers forKey:kDataType];
[requestDict setObject:self.accessToken forKey:kDataAccessToken];
NSString *entityID = [userData objectForKey:kDataUUID];
[self.apigeeDataClient updateEntity:entityID entity:requestDict];
It looks promising except I started getting "Subject does not have permission" like the issue described in this thread. I tried calling assignPermissions like mentioned in Apigee document but that didn't solve the problem. I even provide access_token with the call, even though I shouldn't have to.
In the attempt to avoid calling login also tried calling storeOAuth2TokensInKeychain and retrieveStoredOAuth2TokensFromKeychain mentioned here. That didn't work either.
The only thing way to resolve this error is by calling logInUser before making a call to updateEntity. This means the user will have to login every time he/she wants to use the app. I know I can store username/password in the keychain. But before I do that I'm wondering if there's better solution out there.
I know it's a long post. So thank you for reading this far. Any pointers are greatly appreciated.

Twitter oauth/access_token 401 Error

I've been working on an all that uses the full OAuth app flow, and I have been running into an issue where I only get back a 401 = "Invalid or expired token" error. I've checked my request with the documentation, and everything looks correct, and I'm stumped. Below is the details of my request.
URL
https://api.twitter.com/1.1/oauth/access_token
HTTP Method
POST
Headers
Content-Type: application/x-www-form-urlencoded
Authorization: OAuth oauth_consumer_key="CONSUMER_API_KEY", oauth_nonce="B4D43B0C-A348-4EB6-9C0B-8B0F4FE8", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1397724299", oauth_version="1.0", oauth_token="TOKEN_FROM_REQUEST_TOKEN_API", oauth_signature="ulYIzTacwC%2FeGUdoCPYsrFEqg4A%3D"
HTTP Body
oauth_verifier=OAUTH_VERIFIER_FROM_REQUEST_TOKEN_API
I have no issues getting the oauth/request_token API to work, and I have appropriately set the permissions in Twitter's app settings. Does anyone have any idea what's going on with this?
Thanks for any help you all may be able to offer.
-- UPDATE --
Another thing to note is that I'm using the STTwitter library to make the requests. It did not have a built-in method to handle the oauth/authorize or oath/authenticate API methods so I'm using the code below.
// get request token, and present login screen
STTwitterAPI *twitter = [STTwitterAPI twitterAPIWithOAuthConsumerKey:twitterApiKey consumerSecret:twitterApiSecret];
[twitter postTokenRequest:^(NSURL *url, NSString *oauthToken)
{
authWebViewController = [[TWAuthWebViewController alloc] init];
authWebViewController.url = [NSURL URLWithString:[NSString stringWithFormat:#"https://api.twitter.com/oauth/authorize?oauth_token=%#", oauthToken]];
authWebViewController.completion = ^(TWAuthWebViewController *authViewController, NSURL *oauthCallbackURL)
{
// get the request token and verifier from the URL
NSString *oauthToken = [TWLoginBusiness getOAuthTokenFromURL:oauthCallbackURL];
NSString *oauthVerifier = [TWLoginBusiness getOAuthVerifierFromURL:oauthCallbackURL];
// get user data with the oauth token
[twitter postResource:#"oauth/access_token"
baseURLString:#"https://api.twitter.com/1.1"
parameters:#{#"oauth_verifier" : oauthVerifier}
uploadProgressBlock:nil
downloadProgressBlock:nil
successBlock:^(NSDictionary *rateLimits, id response)
{
NSLog(#"Reponse: %#", response);
completion(nil, nil);
} errorBlock:^(NSError *error)
{
NSLog(#"Error: %#", error);
completion(nil, error);
}];
};
presentAuthController(authWebViewController);
} oauthCallback:twitterApiCallback errorBlock:^(NSError *error)
{
completion(nil, error);
}];
One last note. The part that actually displays the web view controller is not listed here. I wanted to keep the code snippet here focused on the actual API methods, and not the UI logic. Just be assured that the line right after authWebViewController.url.... displays the web view, and then the completion block is called after the user completes the authentication on the Twitter web page. Also the two methods getOauthTokenFromURL and getOauthVerifierFromUrl do in fact return the correct token and verifier. The STTwitter library actually saves out the token it's self, so that is why it's not manually passed into the logic below. The logic generates the request above.
Thanks
The full OAuth flow is already implemented in STTwitter library.
Check out iOS demo for a working example of web-based authentication through Safari.
What you are trying to do here is a web-based authentication inside the application.
Although it is totally feasible, I did not include this workflow in the demo project because it is considered a bad practice.
Indeed, the point of OAuth is that the user does not want to enter her Twitter credentials in your own application, but asks Twitter to send your app dedicated OAuth tokens instead.
Let me know if you need more help with STTwitter.

Resources