I'm currently trying use the outlook mail service to obtain contacts/appointments and mails. However I've stumbled upon a problem.
I'm using OAuth2Swift as library to make all my OAuth calls since I'm integrating multiple services.
I created a URL schemelike described in their README
Then I created a Constants file which looks like this
struct Consumer {
let consumerKey: String
let consumerSecret: String
let authorizeURL: String
let accessTokenURL: String
let responseType: String?
let requestTokenURL: String?
}
let Outlook = Consumer(
consumerKey: "",
consumerSecret: "",
authorizeURL: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
accessTokenURL: "https://login.microsoftonline.com/common/oauth2/v2.0/token",
responseType: "code",
requestTokenURL: nil)
I created an application for outlook on https://apps.dev.microsoft.com
generated my key and secret and filled them in inside my application.
I added the mobile application platform to my app. Which tells me to use the redirect URI urn:ietf:wg:oauth:2.0:oob
So my code to authorise looks like this
#IBAction func btn_Outlook(_ sender: Any) {
let oauthOU = OAuth2Swift(
consumerKey: Outlook.consumerKey,
consumerSecret: Outlook.consumerSecret,
authorizeUrl: Outlook.authorizeURL,
accessTokenUrl: Outlook.accessTokenURL,
responseType: Outlook.responseType!)
oauthOU.authorizeURLHandler = SafariURLHandler(viewController: self, oauthSwift: oauthOU)
oauthOU.authorize(
withCallbackURL: "urn:ietf:wg:oauth:2.0:oob",
scope: "https://outlook.office.com/Mail.ReadWrite https://outlook.office.com/Mail.Send https://outlook.office.com/Calendars.ReadWrite https://outlook.office.com/Contacts.ReadWrite https://outlook.office.com/Tasks.ReadWrite",
state: state,
success: { credential, response, parameters in
print("logged in with \(credential), with response \(response) and parameters \(parameters)")},
failure: { error in
print("error occured \(error.localizedDescription)")
}
)
}
when I run the code I first get a screen to enter my mail/password. When I enter my mail it will redirect me to a different page/portal where I can enter my password. When I've entered my password it will show me the permissions screen.
as soon as I hit yes it will give me an error saying "Safari cannot open the page because the address is invalid." I'm pretty sure this has to do with the redirect URI but I'm not sure what to do to actually fix this.
I'm hoping someone is able to help me out with this!
I think you forgot to specify the identifier urn:ietf:wg:oauth:2.0:oob in your URL scheme settings (see first image: there is no identifier set)
I think you forgot to handle redirect URI in AppDelegate from OAuthSwift library! You've to handle the callback in AppDelegate as below.
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if (url.host == "oauth-callback") {
OAuthSwift.handle(url: url)
}
return true
}
Related
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(...)
}
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)
So I'm currently trying to get authorization for twitter working by making use of the OAuthSwift plugin I've tried to get it working with both OAuth1 and OAuth2 both unsuccessfully and with different errors/problems.
So for OAuth2 I get this response
Whoa there!
There is no request token for this page. That's the special key we need from applications asking to use your Twitter account. Please go back to the site or application that sent you here and try again; it was probably just a mistake.
I'm using the following piece of code for this
let oauthswift = OAuth2Swift(
consumerKey: Twitter.consumerKey,
consumerSecret: Twitter.consumerSecret,
authorizeUrl: Twitter.authorizeURL,
accessTokenUrl: Twitter.accessTokenURL,
responseType: Twitter.responseType!)
let state = generateState(withLength: 20)
oauthswift.authorize(
withCallbackURL: "https://oauthswift.herokuapp.com/callback/twitter",
scope: "",
state: state,
success: { credential, response, parameters in
print("logged in with \(credential), with response \(response) and parameters \(parameters)")
},
failure: { error in
print("error occured \(error.localizedDescription)")
}
)
Then I moved on to using OAuth1 which gives me the error
Desktop applications only support the auth_callback value 'oob' while I'm obviously trying to do this from an iOS application.
the code I used here is as follows
let oauthTwitter = OAuth1Swift(
consumerKey: "myKey",
consumerSecret: "mySecret",
requestTokenUrl: "https://api.twitter.com/oauth/request_token",
authorizeUrl: "https://api.twitter.com/oauth/authorize",
accessTokenUrl: "https://api.twitter.com/oauth/access_token")
oauthswift.authorize(
withCallbackURL: "https://oauthswift.herokuapp.com/callback/twitter",
scope: "",
state: state,
success: { credential, response, parameters in
print("logged in with \(credential), with response \(response) and parameters \(parameters)")
},
failure: { error in
print("error occured \(error.localizedDescription)")
}
)
I'm hoping someone is able to tell me what I'm doing wrong here because I can't seem to figure it out.
The problem ended up to be that I had setup the wrong url scheme. It contained a _ which isn't allowed.
In my case I didn't set a callback URL for the app on Twitter Dev site - https://developer.twitter.com/en/apps
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)
}
)
}
I am trying to authenticate a user getting read, write access permission to Trello API. I am using OAuth1Swift for authetication but cannot add paramaters to add a permission and app name.
How do we add these paramateers? This is my code below.
OAuthSwift Library
Trello API Docs
func doOAuthTrello() {
let oauthswift = OAuth1Swift(
consumerKey: "consumerKey",
consumerSecret: "consumerSecret",
requestTokenUrl: "https://trello.com/1/OAuthGetRequestToken",
authorizeUrl: "https://trello.com/1/OAuthAuthorizeToken",
accessTokenUrl: "https://trello.com/1/OAuthGetAccessToken"
)
self.oauthswift = oauthswift
oauthswift.authorizeURLHandler = getURLHandler()
let _ = oauthswift.authorize(
withCallbackURL: URL(string: "oauth-swift://oauth-callback/trello")!,
success: { credential, response, parameters in
self.showTokenAlert(name: serviceParameters["name"], credential: credential)
self.testTrello(oauthswift)
},
failure: { error in
print(error.localizedDescription, terminator: "")
}
)
}
After trying everything, this is the solution:
lazy var paramaters:[String: String] = {
return [
"consumerKey": "consumerKey",
"consumerSecret": "consumerSecret",
"requestTokenUrl": "https://trello.com/1/OAuthGetRequestToken?scope=read,write,account&expiration=never&name=AppName",
"authorizeUrl": "https://trello.com/1/OAuthAuthorizeToken?scope=read,write,account&expiration=never&name=AppName",
"accessTokenUrl": "https://trello.com/1/OAuthGetAccessToken?scope=read,write,account&expiration=never&name=AppName"
]
}()
The magic happens by adding ?scope=read,write,account&expiration=never&name=AppName to the url parameters