GET all the yarny things

Authenticating Ravelry API Using OAuthSwift

Natalia Sibaja
The Startup

--

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.

Create a new App on Ravelry Pro

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
Add a Redirect URI

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.

Adding a URL Scheme

Step 2: Setup ViewController and IBAction

In your viewcontroller screen create an UIButton and an @IBaction for it called authenticateToRavelry() .

Create a UIButton and corresponding IBAction to trigger auth sequence

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:

App Client ID and Secret (hit show to reveal)

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:

Error when state variable is smaller than 8 characters

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!

--

--

Natalia Sibaja
The Startup

Swift Sweetheart | iOS Developer | Yarn Coder | Soft Circuits