Basecamp3 login issue with Oauth2 in Swift - ios

My app needs to get a basecamp3 login. Hence I used the OAuth2Swift library. But unfortunately, I am unable to receive the token from basecamp even the user has authorized the app.
Below is the screenshot
I have used the following code
func createAuthRequest(){
// create an instance and retain it
let oauthswift = OAuth2Swift(
consumerKey: clientID,
consumerSecret: clientSecret,
authorizeUrl: authURL,
responseType: "token"
)
//oauthswift.authorizeURLHandler = self
oauthswift.authorizeURLHandler = SafariURLHandler(viewController: self, oauthSwift: oauthswift)
let handle = oauthswift.authorize(
withCallbackURL: URL(string: redirectURL)!,
scope: "profile", state:"") { result in //This block of code never executed
switch result {
case .success(let (credential, response, parameters)):
print(credential.oauthToken)
// Do your request
case .failure(let error):
print(error.localizedDescription)
}
}
}
The code inside withCallbackURL never executed even the user has authorized the app.
Any help regarding this is appreciated.

I found the solution the problem was I was using wrong authentication & token URL.
Following URL need to be used. I missed to add web_server in auth/token url and unfortunately Basecamp haven't mentioned the same in their documets.
let authURL = "https://launchpad.37signals.com/authorization/new?type=web_server"
let tokenURL = "https://launchpad.37signals.com/authorization/token?type=web_server"
and redirectURL = com.abc.abc:/oauth2Callback (The same redircturl need to be updated for app under basecamp developer console where com.abc.abc is bundle id of the app)

Related

Swift OAuth2.0 with redirectURI

I'm using a service that provides an OAuth2.0 authentication. This are the steps i need:
Open a URL with user Id as params
User approves my app (which is correctyle registered).
The user is redirected to a RedirectUri, with access token in the hash.
The third point is my main problem.
I've implemented the OAuth with microsoft libraries and everything works fine. But I cant use them here so I'm trying https://github.com/OAuthSwift/OAuthSwift this one.
This is my code:
private func authenticationService() {
// create an instance and retain it
let oauthswift = OAuth2Swift(
consumerKey: "xx",
consumerSecret: "xxx",
authorizeUrl: "//myurl + userId",
responseType: "token"
)
oauthswift.authorizeURLHandler = OAuthSwiftOpenURLExternally.sharedInstance
let handle = oauthswift.authorize(
withCallbackURL: "???",
scope: "", state:"") { result in
switch result {
case .success(let (credential, response, parameters)):
print(credential.oauthToken)
// Do your request
case .failure(let error):
print(error.localizedDescription)
}
}
}
This open correctly my Safari but then I'm redirected to the URI with access token in the hash and nothing happened.
The main problem here is that I've a redirect uri so I guess the callback URL is not called? And this is not opening a sheet but it is redirecting to Safari. And I dont like this approach.
How can I perform OAuth2.0 in swift with the steps above? How can I get the access token from an url? What is the best library and how can I get the most of it?
Update:
This is my code for stackExchange:
let request: OAuth2Request = .init(authUrl: "https://stackexchange.com/oauth/dialog?client_id=<MYCLIENTID>&scope=private_info&redirect_uri=https://stackexchange.com/oauth/login_success",
tokenUrl: "https://stackoverflow.com/oauth/access_token/json",
clientId: "<MYCLIENTID>",
redirectUri: "https://stackexchange.com/oauth/login_success",
clientSecret: "",
scopes: [])
The OAuth domain in stack apps is => stackexchange.com
So i've added in my URL Types the following: redirect-uri://<stackexchange.com> (even without <>)
But everytimes I approve my app i'm stacked in the "Authorizing application" which contains my token and i'm not redirected.
If you are targeting iOS 13 you can use the new AuthenticationServices library provided by Apple.
It will work on both macOS and iOS.
Maybe this would help other developers, I create a simple and small swift package to handle OAuth2 in Swift, you can check the demo project it works very well 👍
https://github.com/hadiidbouk/SimpleOAuth2
Edit:
You are passing the wrong URLs, they should be like this
let request: OAuth2Request = .init(authUrl: "https://stackoverflow.com/oauth",
tokenUrl: "https://stackoverflow.com/oauth/access_token/json",
clientId: "<<your client id>>",
redirectUri: "redirect-uri://stackexchange.com",
clientSecret: "<<your client secret>>",
scopes: ["private_info"])
In the below code:
private func authenticationService() {
// create an instance and retain it
let oauthswift = OAuth2Swift(...)
you don't retain oauthswift (nor handle). They will be deallocated as soon as you finish executing the authenticationService function.
You need to store references to oauthswift and handle outside the function (at the class level).
let oauthswift: OAuth2Swift
let handle: ...
init() {
oauthswift = OAuth2Swift(
consumerKey: "xx",
consumerSecret: "xxx",
authorizeUrl: "//myurl + userId",
responseType: "token"
)
...
}
private func authenticationService() {
handle = oauthswift.authorize(...)
}

Athentication problems on iOS when using AppAuth and Okta

I have a simple iOS Swift app loosely based on the AppAuth-iOS example (https://github.com/openid/AppAuth-iOS) as well as Okta OAuth sample (https://github.com/oktadeveloper/okta-openidconnect-appauth-ios). I am not using Service Discovery nor authomatic token aquisition (i.e. not using authStateByPresentingAuthorizationRequest).
My sample works against Azure AD but does not work against Okta. I am able to log in and am authenticated and redirected back to my mobile app (AppDelegate.application()) but then the flow does not return to my OIDAuthorizationService.present() completion block.
Here is some code:
#IBAction func signInButton(_ sender: Any) {
// select idp
switch selectedIdentityProvider! {
case "Azure AD":
selectedAuthConfig = AzureAdAuthConfig()
case "Okta":
selectedAuthConfig = OktaAuthConfig();
default:
return
}
appAuthAuthorize(authConfig: selectedAuthConfig!)
}
func appAuthAuthorize(authConfig: AuthConfig) {
let serviceConfiguration = OIDServiceConfiguration(
authorizationEndpoint: NSURL(string: authConfig.authEndPoint)! as URL,
tokenEndpoint: NSURL(string: authConfig.tokenEndPoint)! as URL)
let request = OIDAuthorizationRequest(configuration: serviceConfiguration, clientId: authConfig.clientId, scopes: authConfig.scope, redirectURL: NSURL(string: authConfig.redirectUri)! as URL, responseType: OIDResponseTypeCode, additionalParameters: nil)
doAppAuthAuthorization(authRequest: request)
}
func doAppAuthAuthorization(authRequest: OIDAuthorizationRequest) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.currentAuthorizationFlow = OIDAuthorizationService.present(authRequest, presenting: self, callback: {
(authorizationResponse, error) in
if (authorizationResponse != nil) {
self.authState = OIDAuthState(authorizationResponse: authorizationResponse!)
self.logMessage(message: "Got authorization tokens. Access token: \(String(describing: self.authState?.lastAuthorizationResponse.authorizationCode))")
self.doTokenRequest()
} else {
self.authState = nil
self.logMessage(message: "Authorization error: \(String(describing: error?.localizedDescription))")
}
})
}
I could rewrite the code to use authStateByPresentingAuthorizationRequest() to see if it works but am a bit leery as this code works against Azure AD. Any suggestions?
Update 1
I forgot to mention that I have a working Android/Java example going against the same Okta definitions and working like a charm.
Update 2
I did rewrite the code to use authStateByPresentingAuthorizationRequest() against Okta and am getting the same result (i.e. getting stuck after redirect back to my app). I tested this against Azure AD and it works Ok.
Resolved. I guess the problem was that the redirect URL defined in Okta was mixed case. Android AppAuth implementation does not mind but iOS AppAuth implementation does. Changed redirect URL in Okta to lower case only, changed redirect Uri paramter passed in to lower case only and bing, all works great. Thanks #jmelberg for pointing me in this direction - by debugging resumeAuthorizationFlow(with: url) I was able to see the exact behaviour and why the call returned a False.

OAuth Error General Code 4 Swift - AppAuth for iOS

Im trying to implement AppAuth in iOS. basic implementation has been done. seems to be everything working fine. but im not recieving the token as expected. im getting Error Error Domain=org.openid.appauth.general Code=-4
let authorizationEndpoint : NSURL = NSURL(string: "https://accounts.google.com/o/oauth2/v2/auth")!
let tokenEndpoint : NSURL = NSURL(string: "https://www.googleapis.com/oauth2/v4/token")!
let configuration = OIDServiceConfiguration(authorizationEndpoint: authorizationEndpoint as URL, tokenEndpoint: tokenEndpoint as URL)
let request = OIDAuthorizationRequest.init(configuration: configuration, clientId: "<MyTOKEN>", scopes: [OIDScopeOpenID], redirectURL: URL(string: "http://127.0.0.1:9004")!, responseType: OIDResponseTypeCode, additionalParameters: nil)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
// appDelegate.currentAuthorizationFlow
appDelegate.currentAuthorizationFlow = OIDAuthState.authState(byPresenting: request, presenting: self, callback: { (authState, error) in
if((authState) != nil){
print("Got authorization tokens. Access token: \(authState?.lastTokenResponse?.accessToken)")
}else{
print("Authorization error \(error?.localizedDescription)")
}
})
After dealing with errors and changes i figured out the problem after dealing with redirectUri and Token.
redirectUri - once you authorized with google it will generate the token and after that you should open the app. redirectUri will help with that.
This is how you can setup redirectUri
The value for iOS URL scheme wil be the scheme of your redirect URI. This is the Client ID in reverse domain name notation, e.g. com.googleusercontent.apps.IDENTIFIER. To construct the redirect URI, add your own path component. E.g. com.googleusercontent.apps.IDENTIFIER:/oauth2redirect/google. Note that there is only a single slash (/) after the scheme.

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.

Resources