Authenticating Ravelry API Using OAuthSwift
A quick example using OAuthSwift library to authenticate with the Ravelry API for use in a Swift iOS application.
First of all you might be wondering: What is Ravelry? I personally call it the wikipedia for knitters. It’s basically a database of yarns, knitting/crochet patterns and community forums, the social network for fiber crafters, site of which I’m a proud member of (find me as lanaquellama)
As a free resource, the site creators have made an API available and this tutorial will shed light on how to quickly setup OAuthSwift library and the OAuth2.0 credentials to get started using Ravelry API in an iOS application.
Setting up
After setting up a Ravelry Pro account, create a new app with OAuth 2.0 credentials.
Add an application name and because this is a mobile app we want the redirect URI to be handled internally using url-scheme. To do so we can type an URI that has the following format:
appname://oauth-callback/ravelry
Remember the appname you choose we will use it soon. For example purposes, mine will be called ‘ewe finder’.
Note: I will assume you are familiar with installing and using Cocoapods, so go ahead and add OAuthSwift to your project and comeback to this point.
For demo purposes, I’ve setup a new Swift project using Storyboards and will use the default ViewController
to add our code (this is not proper architecture so I suggest creating separate manager classes to handle this)
Step 1: Adding an URL Scheme
In Xcode, go to the Info tab for your app target and add (+) a new URL Type, type in the appname you setup in Ravelry (don’t type ://) in my case it’s ewefinder.
Step 2: Setup ViewController and IBAction
In your viewcontroller screen create an UIButton
and an @IBaction
for it called authenticateToRavelry()
.
Now inside your view controller class, import the the following libraries:
import OAuthSwift
import WebKit
Now, create an enum to handle two important pieces of information, the consumerKey and consumerSecret, these correspond to the ClientId and Secretkey of the Ravelry App you created before; this was where some of the confusion came in as you will see below because Ravelry uses the correct terms for OAuth1.0 but different naming for 2.0:
enum RavelryOAuth: String {
case consumerKey = "[consumerkey]"
case consumerSecret = "[consumersecret]"
}
Find those values here:
Now lets create an instance of Oauthswift inside the ViewController
class, notice we are using OAuth2Swift initializer, important thing here is to use the URLs for authorizeURL and accessTokenURL provided in the OAuth 2.0 documentation on Ravelry API Documentation.
class ViewController: UIViewController {
let oauthswift = OAuth2Swift(
consumerKey: RavelryOAuth.consumerKey.rawValue,
consumerSecret: RavelryOAuth.consumerSecret.rawValue,
authorizeUrl: "https://www.ravelry.com/oauth2/auth",
accessTokenUrl: "https://www.ravelry.com/oauth2/token",
responseType: "token"
)
}
Step 3: Add authorize code to IBAction method
Notice we again refer to that redirect URI we setup above as the withCallbackURL:
@IBAction func authenticateToRavelry() {
oauthswift.authorizeURLHandler = SafariURLHandler(viewController: self, oauthSwift: oauthswift)
let _ = oauthswift.authorize(
withCallbackURL: "ewefinder://oauth-callback/ravelry",
scope: "offline", state:"RAVELRYAUTH") { result in
switch result {
case .success(let (credential, response, parameters)):
print(credential.oauthToken)
// Do your request
case .failure(let error):
print(error.localizedDescription)
}
}
}
Other key items here was choosing the scope, in my case I chose offline, refer to the Ravelry API documentation for more scope permissions here. Also the state value I set to a custom string text ‘RAVELRYAUTH’ (there was no documentation on what to use here); I found out this can also be a random generated string but make sure it is bigger than 8 characters, if not you will get the following error message:
Step 4: Callback handling
Now that we’ve setup everything to make the call to authenticate, what happens next? We want Ravelry to redirect back to our app when it’s done authorizing, right.
On iOS 13 we must add the following method in SceneDelegate.swift
, the reason being that UIKit will notify UISceneDelegate
instead of UIApplicationDelegate
.
On iOS 13:
// MARK: Handle OAuth Callback
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
guard let url = URLContexts.first?.url else {
return
}
if (url.host == "oauth-callback") {
OAuthSwift.handle(url: url)
print(url)
}
}
iOS 12 or below
Add this in AppDelegate.swift
// MARK: Handle OAuth Callback
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
if url.host == “oauth-callback” {
print(“callback hit”)
OAuthSwift.handle(url: url)
}
return true
}
Step 5: Run your code and test login
Now you can run and test out the app, tap on the Login to Ravelry button, this should prompt a Safari page to open up the Ravelry login page, type in your credentials and you should be getting the “Allow ‘Your App’ to view and update your Ravelry notebook?” prompt. Tap authorize and that should bring you back to the app.
Now your ready to query and fetch data and use the Ravelry API for whatever you need. Happy coding!