iOS – OAuth integration with Goodreads
In this tutorial we’ll use the OAuth library for Swift: OAuthSwift, to authenticate users through the Goodreads identity provider. The library is very easy to use. So it’s going to be an easy but rich tutorial as we’ll parse the returned xml response with the SWXMLHash library to get the id of the authenticated user. Which will take us to the following tutorial on working with the Goodreads API in Swift and managing its xml and json responses.
For now, let’s just start with a demo of what we’ll have by the end of the tutorial.
What we’ll build
Setting up OAuthSwift
After creating a new iOS project and building your custom uis, you’ll need to add a Pod file as we’ll be using the CocoaPods dependecy manager to install the two libraries we need : OAuthSwift and SWXMLHash . So you’ll have to add the following to your Pod file :
use_frameworks! target 'GoodreadsOauth' do platform :ios, '10.11' use_frameworks! pod 'OAuthSwift', '~> 1.2.0' pod 'SWXMLHash', '~> 4.0.0' end
Working with OAuth in iOS needs few more configurations than installig OAuthSwift library :
- you need to set URL Schemes in the info tab of your target as follows :
replace “OAuthSample” with your application name.
- and make few updates to your AppDelegate to handle oauth callback urls as follows :
import OAuthSwift import UIKit @UIApplicationMain class AppDelegate: UIResponder { var window: UIWindow? } // MARK: handle callback url extension AppDelegate { func applicationHandle(url: URL) { if (url.host == "oauth-callback") { OAuthSwift.handle(url: url) } else { // Google provider is the only one wuth your.bundle.id url schema. OAuthSwift.handle(url: url) } } } // MARK: ApplicationDelegate extension AppDelegate: UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool { return true } func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool { applicationHandle(url: url) return true } @available(iOS 9.0, *) func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool { applicationHandle(url: url) return true } }
Authorizing with OAuth1.0
In order to work with the Goodreads API you need to register your app for a developer key on goodreads.com/api/keys :
Once you register your app you will get a secret and key codes which you’ll use in creating an instance of OAuth1 with Goodreads as an identity provider as follows (step 1):
func doOAuthGoodreads() { /** 1 . create an instance of OAuth1 **/ let oauthswift = OAuth1Swift( consumerKey: "Your_Api_Key_Here", consumerSecret: "You_Api_Secret_Here", requestTokenUrl: "https://www.goodreads.com/oauth/request_token", authorizeUrl: "https://www.goodreads.com/oauth/authorize?mobile=1", accessTokenUrl: "https://www.goodreads.com/oauth/access_token" ) self.oauthswift=oauthswift oauthswift.allowMissingOAuthVerifier = true oauthswift.authorizeURLHandler = getURLHandler() /** 2 . authorize with a redirect url **/ let _ = oauthswift.authorize( withCallbackURL: URL(string: "OAuthSample://oauth-callback/goodreads")!, success: { credential, response, parameters in self.showTokenAlert(name: "Oauth Credentials", credential: credential) self.testOauthGoodreads(oauthswift) }, failure: { error in print( "ERROR ERROR: \(error.localizedDescription)", terminator: "") } ) }
In step 2 we called the authorize() method of our OAuth instance with a callback url parameter and success and failure handlers.
Callback or redirect URLs are a critical part of the OAuth flow. It is so critical that OAuth service (or better said potential hackers) doesn’t redirect the user to arbitrary locations after authorization. Which requires developers to register one or more redirect URLs when they create the application.
In our case ,using Goodreads with OAuth1Swift, callback urls are defined as follows:
“appName://oauth-callback/goodreads”
you have to setup this url when registering your app :
Post-authorization: getting Goodreads user_id
After authorizing the user, on the success handler of authorize() method, first information you’ll need to retrieve is the authorized user’s id , so that you can perform other API calls using that id.
In our case, it takes this call to retrieve the user id:
oauthswift.client.get( “https://www.goodreads.com/api/auth_user”, success, failure)
func testOauthGoodreads(_ oauthswift: OAuth1Swift) { let _ = oauthswift.client.get( "https://www.goodreads.com/api/auth_user", success: { response in /** parse the returned xml to read user id **/ let dataString = response.string! let xml = SWXMLHash.parse(dataString) let userID = (xml["GoodreadsResponse"]["user"].element?.attribute(by: "id")?.text)! print("---- RAW:\(dataString)") print("---- XML:\(xml)") print("---- USER ID:\(userID)") self.showAlertView(title: "ID of authorised user", message: "user_id:\(userID). You can now use it for Goodreads API rest calls..") /** save the userID to .. **/ // ... }, failure: { error in print(error) } ) }
For the helper methods we used ( showTokenAlert(name,credential) and showAlertView(title,message) ) you can check out this git repo for the source code of the demo app.
Working on OAuth in Swift with Goodreads I found the OAuthSwift official demo quit explanatory and useful, but I couldn’t find a plain tutorial explaining the steps and saving me the little time I spent preparing this demo. Which made write this tutorial and share it with you!
In the hope you find this useful, I would welcome any of your questions or requests in comments below.
Recent Comments