Authenticating with playPORTAL
Introduction
In this article, we’re going to be using the playPORTAL Swift SDK to create a simple iOS app and integrate playPORTAL’s authentication flow. We will be demonstrating the ease in which you can authenticate playPORTAL users into your iOS app using playPORTAL’s single sign-on (SSO) and have access to playPORTAL’s COPPA compliant social network.
First, head over to playPORTAL and create your playPORTAL developer account, along with a new app. Once you’ve created an app, you’ll be able to get the client id and secret for that app, which are needed for your app to make requests to playPORTAL’s APIs.
You’ll also need to add the Authentication and Profile scopes for your app. Scopes dictate what information your app has access to; in this article we are only concerned with authenticating a user and requesting their profile. Now, let’s open up Xcode, create a new project and select ‘Single View App.’
First, we’ll need to add PPSDK-Swift as an external dependency, which we’ll do using Cocoapods. If you don’t already have it, install Cocoapods globally using
sudo gem install cocoapods
Then, in the root of your project, add Cocoapod support by running
pod init
pod update
This will create a .xcworkspace file in the directory that we will use from now on. Close your current Xcode session and open this file.
To add the SDK, open the Podfile under the Pods directory in the Project navigator and add
pod “PPSDK-Swift”, :git => “https://github.com/playportal-studio/PPSDK-Swift.git", :tag => “0.2.0”
under use_frameworks!
Finally, to install the SDK, go back to your project in the terminal and run
pod install
Configuration
Now that the project is created and we’ve added the PPSDK-Swift Pod, let’s configure it to use the app you created in playPORTAL studio. In your project, create a file called Config.swift. Go to your account and grab the client id and secret that was created and the redirect URI you associated with your app. We’ll add those values, along with the environment, to Config.swift. It should look something like this Config
Note: It’s important that you keep your configuration variables private and that they not be added to version control. If using git, you should create a .gitignore file in the root of your project (not in Xcode) and add Config.swift to it. This way, your configuration file is not added to your commit history and won’t be pushed to your remote repo.
You will also need to register your app’s redirect URI in Xcode. This way, after a user logs in through SSO, the SSO is able to redirect back to the app. Click on your root project folder in the Project navigator and go to the Info tab. The URL Types section at the bottom is where you will add your redirect URI.
Here is a URL Type example. Great! With the configuration out of the way, let’s write some code!
playPORTAL provides you with a social network out of the box so that you can focus on your app’s business logic and not worry about creating a user authentication system yourself. Users authenticate through the playPORTAL SSO flow which follows an OAuth2 model. With just a few lines of code, users will be able to sign in and use your app!
Head over to your AppDelegate.swift file in your project. You can delete all of the methods besides application(_:didFinishLaunchingWithOptions:) as you won’t need them. In this method, we are going to configure the SDK with our configuration variables. This allows the SDK to make requests on behalf of the app, as well as register its redirect URI.
PlayPortalAuth.shared.configure(forEnvironment: env, withClientId: clientId, andClientSecret: clientSecret, andRedirectURI: redirect)
(Don’t forget to add import PPSDK_Swift at the top of the file!).
Now, we are going to have the SDK check if there is a currently authenticated user. With our SDK, a user stays logged in unless they log themselves out. Therefore, if the user is already authenticated, you will immediately be able to go to your app’s initial view controller. Otherwise, you will have to open a login view controller so the user can login through SSO. Let’s add this under the configure method:
PlayPortalAuth.shared.isAuthenticated(loginDelegate: self) { error, userProfile in
}
Notice that this method takes an argument loginDelegate that is of type PlayPortalLoginDelegate. This is a protocol provided by the SDK that allows a conforming class to receive messages related to the authentication flow, such as a failed login or a successful logout. You can simply have your AppDelegate class conform to it without implementing any of the methods for now, as they are all optional.
isAuthenticated also takes a closure as an argument which takes two arguments: error and userProfile. userProfile is an instance of PlayPortalProfile and represents a user’s playPORTAL profile. completion will be invoked with userProfile for a successful authentication, or error if some issue occurred during the login flow. If both arguments are nil, the user is not authenticated and therefore needs to login. For now, let’s add some code to handle when the user is not authenticated:
if let error = error {
print(“An error occurred during authentication: \(error)”)
} else if userProfile == nil {
guard let login = UIStoryboard.init(name: “Main”, bundle: nil).instantiateViewController(withIdentifier: “login”) as? LoginViewController else {
return
}
self.window?.rootViewController = login
}
We will also need to implement one other method in `AppDelegate`:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
PlayPortalAuth.shared.open(url: url)
return true
}
This method will be called when the SSO flow finishes successfully and calls your app’s redirect URI. `PlayPortalAuth.shared.open(url: url)` is called with the `url` argument which will extract the authorization tokens created during the SSO process.
At this point, you should get an error. Why? Well, because LoginViewController doesn’t exist, of course! Let’s add a new LoginViewController.swift file and create a simple LoginViewController class. Then, in your Main.storyboard file, add a new view controller and associate it with the LoginViewController class you just created. Don’t forget to set the view controller’s Storyboard ID as login. We are also going to add a UIView to the login view controller in the storyboard that we will center horizontally and vertically in its containing view and with equal width and height as its containing view. Connect that view we just created to our LoginViewController class.
There is one other piece of code we will want to add to LoginViewController:
let loginButton = PlayPortalLoginButton(from: self)
loginButton.center = CGPoint(x: view.bounds.size.width / 2, y: view.bounds.size.height / 2)
loginView.addSubview(loginButton)
This snippet adds a PlayPortalLoginButton in the center of that UIView we connected to our LoginViewController. PlayPortalLoginButton is a subclass of UIButton and when tapped will kick off the playPORTAL SSO flow.
At this point, our Main.storyboard file and LoginViewController.swift file should look something like this: storyboard
Before we do anything else, let’s create a playPORTAL user to log in as.
It’s convenient during development to have test users that don’t have to be manually created. playPORTAL’s sandbox environment allows you to do just that. Head over to [https://studio.playportal.io/studio/sandbox](https://studio.playportal.io/studio/sandbox) in playPORTAL studio; here you can generate sandbox users that represent what actual playPORTAL users look like. Generate a new user that you will log in with.
Finally, let’s run the app!
When the app starts, it should open to our LoginViewController with the PlayPortalLoginButton centered in the middle.
If you tap on it, it will take you to the playPORTAL SSO screen where you can log in as the sandbox user you just created.
If all goes well, the user should have authenticated successfully.
If you click Continue you will be taken back to our login page. We now need to handle the case where the user is authenticated.
Let’s head over to AppDelegate.swift and refactor the completion passed to PlayPortalAuth.shared.isAuthenticated. When the user authenticates successfully, we will open a ProfileViewController and pass it the userProfile instance we received.
if let userProfile = userProfile {
guard let profile = UIStoryboard.init(name: “Main”, bundle: nil).instantiateViewController(withIdentifier: “profile”) as? ProfileViewController else {
return
}
profile.userProfile = userProfile
self.window?.rootViewController = profile
} else if let error = error {
print(“An error occurred during authentication: \(error)”)
} else if userProfile == nil {
guard let login = UIStoryboard.init(name: “Main”, bundle: nil).instantiateViewController(withIdentifier: “login”) as? LoginViewController else {
return
}
self.window?.rootViewController = login
}
Let’s add a new ProfileViewController.swift file with a ProfileViewController declared in it. We will also add a new view controller in our Main.storyboard and connect it to ProfileViewController with a Storyboard ID of profile. Let’s also add a label letting us know we’ve logged in successfully. Storyboard example here
If we go through the SSO flow again, we should be taken to our profile page.
Now, that profile isn’t really much of a profile, so why don’t we make use of a few of the properties we get back in the userProfile. You can create your own profile UI or check out the finished ProfileViewController in the repo (linked at the end).
Hey, look at that! It’s starting to look like a real profile page. Of course, I don’t expect you to create a UI that complex by yourself, but you get the idea. Let’s take a quick look at the code that was added in ProfileViewController to do this:
handleLabel.text = userProfile.handle
coverPhotoImageView.playPortalCoverPhoto(forImageId: userProfile.coverPhoto, nil)
profilePicImageView.playPortalProfilePic(forImageId: userProfile.profilePic, nil)
PPSDK-Swift adds some helper methods as extensions on UIImageView to add a user’s profile pic or cover photo as the image view’s underlying UIImage. It’s possible a user doesn’t have a profile pic or cover photo and therefore the profilePic and coverPhoto properties for PlayPortalProfile are both of type String?. The forImageId parameter in both methods takes an argument of String?; if nil is passed in, a default image will be supplied.
Let’s close the authentication loop by adding support for logout.
In our **Main.storyboard** file, we will embed our profile view controller in a **Navigation Controller**. We are going to add a **Bar Button Item** as the profile controller’s **Right Bar Button Item**. Set the title as ‘Logout’ and connect it to your `ProfileViewController` class as an `IBAction`. Our **Main.storyboard** file and **ProfileViewController.swift** file should look something like this: Logout tapped In the `logoutTapped(_:)` method, we are going to add
PlayPortalAuth.shared.logout()
We will also need to refactor the completion passed to isAuthenticated in our AppDelegate. When the user is authenticated, we want to set the rootViewController as the navigation controller we just created:
guard let navigation = UIStoryboard.init(name: “Main”, bundle: nil).instantiateViewController(withIdentifier: “navigation”) as? UINavigationController
, let profile = navigation.viewControllers[0] as? ProfileViewController
else {
return
}
profile.userProfile = userProfile
self.window?.rootViewController = navigation
Make sure to also give the navigation controller a Storyboard ID of navigation in the Main.storyboard file. Recall that we added PlayPortalLoginDelegate conformance to our AppDelegate. This protocol declares a few methods that are invoked during phases of the SSO flow, including logout. In your AppDelegate, add:
func didLogoutSuccessfully() {
}
This method will be invoked by the SDK after a successful logout. In most cases, you would likely just go back to your LoginViewController after a user logs out. Let’s refactor AppDelegate by putting the call to isAuthenticated in its own method.
func authenticate() {
PlayPortalAuth.shared.isAuthenticated(loginDelegate: self) { error, userProfile in
if let userProfile = userProfile {
guard let navigation = UIStoryboard.init(name: “Main”, bundle: nil).instantiateViewController(withIdentifier: “navigation”) as? UINavigationController
, let profile = navigation.viewControllers[0] as? ProfileViewController
else {
return
}
profile.userProfile = userProfile
self.window?.rootViewController = navigation
} else if let error = error {
print(“An error occurred during authentication: \(error)”)
} else if userProfile == nil {
guard let login = UIStoryboard.init(name: “Main”, bundle: nil).instantiateViewController(withIdentifier: “login”) as? LoginViewController else {
return
}
self.window?.rootViewController = login
}
}
}
Now we can call this method after PlayPortalAuth.shared.configure and call it in our didLogoutSuccessfully method.
When the user logs out, the didLogoutSuccessfully method will be invoked by the SDK, which will call our authenticate method. Because the user is no longer authenticated, they will be redirected back to the login page. Run the app and try it out!
In this article, we saw that with just a few lines of code, we were able to add playPORTAL authentication to an iOS app, giving us access to the entire playPORTAL social network. Using the playPORTAL sandbox environment, we were able to create a test user during development, obviating the need for us to manually create test users ourselves. In future articles, we will discuss how to add features such as playPORTAL’s Leaderboard and Lightning Database features. Stay tuned! You can find the finished project here.