OAuth Twitter iOS Swift - ios

I am building an application with Swift-iOS and deployd as backend Deployd. I'm trying to figure out Twitter OAuth. Basically I would want to know how can I send my server a token and let dpd-passport save it in a user collection.
Twitter API is returning access token very fine. Here's my code:
TwitterClient.SharedInstance.requestSerializer.removeAccessToken()
//where TwitterClient is a BDBOAuth1SessionManager instance
TwitterClient.SharedInstance.fetchRequestTokenWithPath("oauth/request_token", method: "GET", callbackURL: NSURL(string: "cptwitter://oauth"), scope: nil, success: { (requestToken: BDBOAuth1Credential!) -> Void in
print(requestToken.token)
let authURL = NSURL(string: "https://api.twitter.com/oauth/authorize?oauth_token=\(requestToken.token)")
UIApplication.sharedApplication().openURL(authURL!)
}) { (error: NSError!) -> Void in
print("failed to get the token request")
}

Related

swift:receive AWS id_token after sending facebook current token to AWS Cognito?

I want to send the facebook access token to the AWS Cognito and then receive an authorization token which can further be sent as an Authorization header in HTTP Put request.
However, I always get "unauthorized" response from the AWS end point.
When I try to print :
credentialsProvider.credentials().continueOnSuccessWith(executor: AWSExecutor.default()) { (task) -> Any? in
print(task.error)
return true
}
I get the following output:
Optional(Error Domain=com.amazonaws.AWSJSONBuilderErrorDomain Code=4 "serialized object is neither a valid json Object nor NSData object: {
IdentityPoolId = "******";
Logins = {
"graph.facebook.com" = "<FBSDKAccessToken: *******>";
};
}" UserInfo={NSLocalizedDescription=serialized object is neither a valid json Object nor NSData object: {
IdentityPoolId = "*****+*";
Logins = {
"graph.facebook.com" = "<FBSDKAccessToken: ******>";
};
}})
This is my code:
import AWSCognito
class FacebookProvider: NSObject, AWSIdentityProviderManager {
func logins() -> AWSTask<NSDictionary> {
if let token = FBSDKAccessToken.current() {
return AWSTask(result: [AWSIdentityProviderFacebook:token])
}
return AWSTask(error:NSError(domain: "Facebook Login", code: -1 , userInfo: ["Facebook" : "No current Facebook access token"]))
}
}
class API {
..............
public func putOrder(when fbLogin: Bool, _ order: Order, onSuccess: #escaping(JSON) -> Void,
on Failure: #escaping(Error)-> Void) {
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .EUCentral1 ,
identityPoolId:"*****", identityProviderManager:FacebookProvider())
let configuration = AWSServiceConfiguration(region: AWSRegionType.EUCentral1, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let url = "\(serverURL)\(API.loginOrderPath)"
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(url: NSURL(string: url)! as URL)
urlRequest.httpMethod = API.apiMethodPut
urlRequest.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
urlRequest.setValue("\(credentialsProvider.credentials())", forHTTPHeaderField: "Authorization")
do {
var json: JSON
json = ["companyId": order.companyId, "drinks": order.drinksId, "payment": order.payment, "tip": order.tip]
urlRequest.httpBody = try json.rawData()
let task = URLSession.shared.dataTask(with: urlRequest as URLRequest, completionHandler: {data, response, error -> Void in
if error != nil {
Failure(error!)
} else {
if let response = try? JSON(data: data!) {
onSuccess(response)
} else {
}
}
})
task.resume()
} catch _ {
}
}
}
Expected Result: JSON response from the AWS Server
Actual Result : unauthorised
The reason why your are receiving an unauthorized response from API Gateway is double :
credentialsProvider.credentials() is not serialized to JSON and can not be "as is" for the authorization headers.
Looks like you are trying to manually call API Gateway, by managing your self the low level details of the URL Request. I don't see code to add a signature to the request. All authenticated API Gateway requests must be signed (see https://docs.aws.amazon.com/apigateway/api-reference/making-http-requests/) and the Authorization header must contain the credentials used to compute the signature.
Managing the low level details of AWS Signature is not trivial. You should not write code to do that but use the AWS iOS SDK instead. In particular, if you're trying to call API Gateway with Cognito User Pool authorisation, have a look at this example : https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-generate-sdk-ios-swift.html.
The API Gateway console will generate the client side code required to run this example (see https://docs.aws.amazon.com/apigateway/latest/developerguide/genearte-ios-sdk-of-an-api.html)
This should remove a lot of boiler plate from your code, making it easier to read and to maintain.
The flow posted in your comment above, the iOS SDK will take care of 2/ 3/ and 4/ steps for you - automatically.

LinkedIn login with custom token ( ERROR_INVALID_CUSTOM_TOKEN )

I am trying to login with LinkedIn using the native app and the LinkedIn SDK. So far I can login using the web if the LinkedIn app is not installed. I can also login with LinkedIn and get a token in return. But when I try to authenticate with Firebase I get this error:
Optional(Error Domain=FIRAuthErrorDomain Code=17000 "The custom token
format is incorrect. Please check the documentation." UserInfo=
{NSLocalizedDescription=The custom token format is incorrect. Please
check the documentation., error_name=ERROR_INVALID_CUSTOM_TOKEN})
This is my code:
// App installed
let permissions = [LISDK_BASIC_PROFILE_PERMISSION,LISDK_EMAILADDRESS_PERMISSION]
LISDKSessionManager.createSession(withAuth: permissions, state: nil, showGoToAppStoreDialog: true, successBlock: { (returnState) -> Void in
LISDKAPIHelper.sharedInstance().getRequest("https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,picture-url,public-profile-url,industry,positions,location)?format=json", success: { (response) -> Void in
if let data = response?.data.data(using: String.Encoding.utf8) {
if let dictResponse = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers){
let token = LISDKSessionManager.sharedInstance().session.accessToken.accessTokenValue
Auth.auth().signIn(withCustomToken: token! ) { (user, error) in
print(user!)
print(error!)
}
}
}
}, error: { (error) -> Void in
print("LINKEDIN error\(String(describing: error))")
})
}) { (error) -> Void in
print("error login linkedin")
}
The token I am sending to Firebase is a String, so that should be okay. I must be missing something. But what ?
The problem was my misunderstanding. I thought I could use the Linkedin token directly. It has to go to a webservice that uses the Firebase admin user to generate the token.

How to get Instagram access_token using OAuth2Swift

I tried every possible option, but the redirect URI does not return the access_token. I added a call back URI, I am able to ask from the user to login and give access permission, but I get this error on the call back.
I registered this URI on the Dev portal, and it seems to work fine:
http://oauthswift.herokuapp.com/callback/instagram
When I try to authenticate on a web browser using:
https://api.instagram.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=http://oauthswift.herokuapp.com/callback/instagram&response_type=token
I do get the access token:
When I try using OAuthSwift, I get this error and the redirect URI does not include the access_token, dispite what the Docs says:
This is the error:
serverError[No access_token, no code and no error provided by server]
This is my code below:
// MARK: Instagram
func doOAuthInstagram(_ serviceParameters: [String:String]){
let oauthswift = OAuth2Swift(
consumerKey: serviceParameters["consumerKey"]!,
consumerSecret: serviceParameters["consumerSecret"]!,
authorizeUrl: "https://api.instagram.com/oauth/authorize",
responseType: "token"
)
let state = generateState(withLength: 20)
self.oauthswift = oauthswift
oauthswift.authorizeURLHandler = getURLHandler()
let _ = oauthswift.authorize(
withCallbackURL: URL(string: "http://oauthswift.herokuapp.com/callback/instagram")!, scope: "likes+comments", state:state,
success: { credential, response, parameters in
self.showTokenAlert(name: serviceParameters["name"], credential: credential)
self.testInstagram(oauthswift)
},
failure: { error in
print(error.description)
}
)
}

Intercept oauth2 callback

I'm trying to connect an iOS Swift app to an API, and I've experimented with oauthswift, aerogear, and heimdallr.
The flow is working fine, but the API itself doesn't have user-owned resources. All users have access to all resources. The API does, however, require OAuth2 to authenticate.
Is there a way to prevent a swift app from bouncing to Safari (or Safariwebview) and either avoiding the user login part or handling it with a workaround? I know this is sort of antithetical to oauth2, but there's no need (and actually it would be an impediment) for a single user to be logged in to this api.
Basically, I want the app to login on the backend for access to every user. I know this api has sdk's in Ruby, Python, and Node that do just that. So, how can I do this in Swift?
Here's my oauthswift code that successfully gets me in:
let yourEndpoint = ("https://www.awebsite.com/search/shows/a_show")
let oauthswift = OAuth2Swift(
consumerKey: "my key",
consumerSecret: "my secret",
authorizeUrl: "https://www.awebsite.com/oauth/authorize",
accessTokenUrl: "https://www.awebsite.com/oauth/token",
responseType: "token")
let name = "sample_api_proj"
oauthswift.authorizeWithCallbackURL( NSURL(string: "xxx:xxxx:xx:oauth:2.0:xxx")!, scope: "", state: "", success: {
credential, response, parameters in
self.showTokenAlert(name, credential: credential)
let parameters = Dictionary<String, AnyObject>()
oauthswift.client.get("https://www.awebsite.com/api/search/shows/ashow", parameters: parameters,
success: {
data, response in
let jsonDict: AnyObject! = try? NSJSONSerialization.JSONObjectWithData(data, options: [])
print(jsonDict)
}, failure: { error in
print(error)
})
}, failure: { error in
print(error.localizedDescription)
})
I'm returning to this to provide the answer that I ultimately found. I didn't realize there were different types of oauth2, and the type used to authorize an entire app is called 'client credentials.' Not all libraries/pods are designed for this type of oauth. The working solution I found was with p2.OAuth2.

How to create STRIPE customer using STRIPE API in IOS?

I have STRIPE integration in my ios application.
I am able to generate token using cards details entered by users.
I send this TOKEN to server for payment process.
That's all fine !
Problem , is I want to create a STRIPE Customer using its API.
How to do this , does SDK provide anything for this ?
OR passing 'Authorization_KEY' and 'STRIPE_TEST_PUBLIC_KEY' in header is the way ?
OR I need to implement whole 'OAuth 2.0' for this ?
Please help !
Thank you !
I don't think you can create a Stripe Customer with the Public Key. I'm quite sure Secret key is required for this request and so it should probably be handled on the server instead of the client app.
Yes, nabeel is correct, the customer should be created by the server instead of the client app. Although, if you want to risk it, you can do it like this...
class StripeUtils {
//Feed in the STPCardParams to create a Stripe token.
func generateToken(with params: STPCardParams, completion: #escaping (Error?, STPToken?) -> ()) {
STPAPIClient.shared().createToken(withCard: params) { (token, error) in
completion(error, token)
}
}
//Pass the token and user email address to get the STPCustomer
func createUserWith(email: String, token: STPToken?, completion: #escaping (Error?, STPCustomer?) -> ()) {
guard let token = token else {
print("Token can not be nil")
completion(*error*, nil)
return
}
let headers = ["Authorization": "Bearer \(Constants.STRIPE_SECRET_KEY)"] //The secret key
let body = ["email": email, "source": token.tokenId] as [String : Any]
var paramString = String()
body.forEach({ (key, value) in
paramString = "\(paramString)\(key)=\(value)&"
})
let params = paramString.data(using: .utf8)
//URLStrings.stripe_createUser is "https://api.stripe.com/v1/customers"
//The APIManager is a class that takes urlString, params(HTTP body) and headers(HTTP headers) to get initialized.
//(You can use Alamofire or whatever you use to handle APIs)
//Instance of APIManager has a method called 'perform' with the URLSession's completion block (Data?, URLResponse?, Error?) -> ()
let manager = APIManager(urlString: URLStrings.stripe_createUser.description, params: params, headers: headers)
manager.perform { (data, response, error) in
//Use STPCustomerDeserializer intead of standard JSONSerialization to let Stripe hanlde the API response.
let object = STPCustomerDeserializer.init(data: data, urlResponse: response, error: error)
completion(object.error, object.customer)
//That's it, you'll have a STPCustomer instance with stripeId if there were no errors.
}
}
}

Resources