Modular Sign in with Apple in iOS

Over the years, authentication has been a creep for most of the mobile apps. At first, it was required for users to signup to start using any app. Then Apple and UX developers wondered Why users are required to signup for a thing they have not seen or used.

Thus, you should let them taste the application. Then, if they like it enough and would like to access more features, they are required to sign up. This, in turn, leads to having many paths to get your user to the signup process and many entry points.

Want to read this story later? Save it in Journal.

On the other hand, signing up is a process users always hate because it is a time-consuming process. That’s why developers invented a single sign-in button, starting with Facebook, moving on to Google, and Apple, which lately, decided to have its button.

So, How to deal with that in your codebase?

Will you just add it to the login controller, easy? Ok, what if you’ve multiple login entry points to your app? you’ll copy the code? it’s just a few SDK imports and login lines, right?

But that doesn’t scale well, at all.

Every iOS app is now required to include the new sign in with Apple. Be it a new app, or a current one in the AppStore. For the current apps, Apple extended the deadline to June 30, 2020.

The key idea here is that using this pattern drives me to the fact of how adhering to design patterns impacted my code, making it very robust, composable, and easy to test.

What’s the “Strategy” design pattern?

Strategy Design Pattern: is a type of behavioral design pattern that encapsulates a “family” of algorithms and selects one from the pool for use during runtime. The algorithms are interchangeable, meaning that they are substitutable for each other. The key idea is to create objects which represent various strategies(source)

What’re we trying to achieve?

An authentication module that can easily be extended with new services, tested, debugged, monitored, and easily reused.

How can that be assembled in swift?

First, let’s utilize Swift powerful enums to include all services we’re going to use to authenticate a user:

enum PreferredAuthMethod{  case phone(number: String)  case email(email: String, password: String)  case google  case facebook  case apple
}

Notice this will be our source of truth when we need to add new service types. Say you want to add Github, you’ll just add it to the cases above, and extend the service protocol, coming shortly.

What’s an authentication service?

It’s a service we’re using so can tell it simply: Authenticate this user, and let us know if you could, or not!

So the service is a simple protocol with just two functions:

protocol AuthService {
var authType: PreferredAuthMethod { get }
func authenticate() func deAuthenticate()}

No matter what the service is or which algorithm it is using, it should be able to authenticate the user then reply to the caller with results, in swift using a protocol or a closure, depending on how you would prefer building your API.

I prefer delegates, which feels much cleaner to me.

Here’s the delegate I’ve created:

This is the delegate I’m using to tell the service caller that if the user is authorized or not, and the controller to pass it to some of those SDKs that need it, like Facebook and Apple. They’re using it to present their controllers above yours, it can be ignored in facebook case, but not in the Apple one as far as I’ve researched.

Ok, but now how would the previous enum generate those services?

let’s extend the enum adding a getServicefunction:

I’m just implementing the Apple one here, leaving other services for you to practice, but it’d be the same.

Observe how both the source controller and the delegate are being sent separately to the service initializer, yet they can be combined as we will see next.

Where am I going to use this?

You will need an authenticator object to tell it your authentication strategy and your two commands that we have built so far.

This object will have a simple interface, just like the service.

You will also wait for this object to respond with results. The caller will be able to switch between strategies using autocompletion, which is very effortless, provided by the enum that we created to contain all the strategies aka services.

Now let’s deep dive into this snippet. Notice the type alias? It’s just the swift way to combine two types into one, notice that I’m combining the two

UIViewController & AuthServiceDelegate

into another one: AuthenticationViewSource, simple! right?

Just because I’m using MVC method to explain it here, but it can be separated as we’ve seen it in the enum factory above.

For the functions, we’ve almost identical ones to our protocol, but here we’re passing the strategy we’d be using, generating service and passing the call to it, making userAuthinticator acting as a mediator.

Some have asked me about why passing UIViewController?
It’s not a good practice. And I agree, but If you’ve worked with those SDKs. Some of them need your presented UIViewController, to present their own on top of it.

Who’s responsible for creating the service?

You’ve seen it in the code above, the enum acts as a factory for the service.

Authentication as a service

When you’re using your API to create and authenticate a user from backend, you’re calling the Authentication service that you or your backend has built, which was extended later to other 3rd party services such as Google, or Apple. It’s a huge business, maybe you have you heard of Okta as well.

My point is, it’s a simple service, you ask it to verify a user, and it replies with a simple answer too! Authenticated or not!

so let’s build the sign in with Apple service:

Notice the two main protocol functions, and since Apple doesn’t provide a way to remove user authentication I left it empty, Facebook and Google for example provide functions for that.

Whether you’re using your own backend or using Firebase for example. You’ll need to verify apple results, I’ve added that to the service via the ServiceAuthorizer protocol to get the results from the delegate and handle it on its own.

The only missing part in this class is the confirmation to the delegate and data source:

You can see that it’s pretty easy with a straightforward implementation.

Notice the function presentationAnchor and it’s required window. That’s why I passed the controller to the service, in case of Facebook: they ask for the controller.

Handle the errors, pass credentials to Firebase, or your backend object to send user information to it and get back the response through the delegate!

Now we’re done with the Apple sign-in module, and you can easily use it anywhere! just add it, conform to the delegate protocol, and you’re done!

Notice the pattern here, we simply tell the class which method user did pick, and we authenticate based on his choice, the caller doesn’t need to know anything about the details, which is very SOLID!

Voila! it works!

This has been a nice journey so far, hope you’ve enjoyed it. I also used the same pattern to build something to handle different cell types in a Table/CollectionView! I found it mentioned in one of the articles and it was just great!

If you like this and my other articles, I discuss those topics and more in lintschool, check out our advanced iOS course.

Sharing and clapping are very appreciated. Thanks in advance.

📝 Save this story in Journal.

👩‍💻 Wake up every Sunday morning to the week’s most noteworthy stories in Tech waiting in your inbox. Read the Noteworthy in Tech newsletter.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Abdoelrhman Mohamed

Abdoelrhman Mohamed

461 Followers

Mobile software engineer @Adevinta, working with swift and iOS mainly, and community founder @SwiftCairo @LintSchool