Add Authentication to Your iOS Apps With Centralized Login, Part 3
We wrap up our series on adding a centralized login functionality to your iOS application by checking out an authentication SDK.
Join the DZone community and get the full member experience.
Join For FreeWelcome back! If you missed them, you can find Part 1 and Part 2 here.
A Simpler Approach: Using the Auth0 SDK for iOS
Although the steps shown before are somewhat simple, there is an even easier way to do them! Auth0 provides a Swift library that can be used to interact with these endpoints in a simpler way. Let's take a look.
We will start from the same basic clean template as before: a single page iOS application with a label and a button that reads Login
. When this button is pressed, the following code is executed:
@IBAction func buttonClicked(_ sender: Any) {
if profile != nil {
profile = nil
updateUI()
} else {
Auth0
.webAuth(clientId: clientId, domain: domain)
.scope("openid token profile")
.start { result in
switch result {
case .success(let credentials):
Auth0
.authentication(clientId: clientId, domain: domain)
.userInfo(withAccessToken: credentials.accessToken!)
.start { result in
switch result {
case .success(let profile):
self.profile = profile
case .failure(let error):
print("Failed with \(error)")
self.profile = nil
}
self.updateUI()
}
case .failure(let error):
self.profile = nil
print("Failed with \(error)")
}
self.updateUI()
}
}
}
To use this library simply call Auth0.webAuth
and pass the right clientId
and domain
parameters. You can then proceed to set the right scope or other settings by chaining calls. Finally, call start
to start the authorization process. This will display the authorization URL in Safari. Once this is completed, the callback passed to start
will be called with the access token and other credentials. That's right! All the PKCE stuff and the call to /oauth/token
is handled automagically by the library, no need to do that manually anymore!
Once the credentials are in your possession you can get the user's information by calling:
Auth0.authentication(clientId: clientId, domain: domain)
.userInfo(withAccessToken: credentials.accessToken!)
.start { result in //(...) }
The access token passed to this call is the one returned by the webAuth
operation from before. Piece of cake!
The Auth0.swift library internally uses the same method to communicate between Safari and the application: URL schemes. This means that the right callback URL must be set in the client settings for your app in the Auth0 dashboard. The format of this URL, however, is much more specific:
{YOUR_BUNDLE_IDENTIFIER}://${YOUR_AUTH0_DOMAIN}/ios/{YOUR_BUNDLE_IDENTIFIER}/callback
In our example this looks like:
Auth0.Centralized-Login-Test-2://speyrott.auth0.com/ios/Auth0.Centralized-Login-Test-2/callback
On iOS versions older than 11, the Auth0.swift library still requires the URL scheme to be configured manually as we did for our "manual endpoints" example in the Info.plist
file:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>None</string>
<key>CFBundleURLName</key>
<string>auth0</string>
<key>CFBundleURLSchemes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
</array>
The right handler in the AppDelegate
must also be set:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
return Auth0.resumeAuth(url, options: options)
}
In any case, this is still much easier than hitting the endpoints manually.
A Note About Credentials
The credentials returned by the call to /oauth/token
or Auth0.webAuth
(i.e. the access token and the refresh token) must be stored safely. In other words, do not put these elements in insecure storage like NSUserDefaults
. iOS provides a keychain that can be used for these purposes. The safety of your app depends on the safety of the access and refresh tokens! Consider these as sensitive as user passwords.
Customization of the Centralized Login Page
As we said before, a big part of the user experience is the login view of our mobile app. This is, usually, one of the first things the users see. Therefore, we must make sure it fits with the rest of the application. The centralized login feature allows this too!
We've seen in our example that using Safari to open the URL for the /authorize
endpoint results in a login page that gets displayed. This login page is hosted by the authorization server. In contrast, in legacy native mobile applications, the login page or view would be an internal part of the application and completely managed by it.
The Auth0 authorization server allows you to modify the login page served by it to your taste. To do this, open the dashboard and navigate to the Hosted Pages
section. If you enable the Customize Login Page
switch you will be presented by a text editor right below. This is the HTML page that is served when the authorization server needs a user to authenticate themselves.
By default, Auth0 uses the Auth0 Lock library. The Auth0 Lock library is a convenience library for displaying login pages and popups. This library supports all of the different login features that Auth0 provides, including social logins, username/password signup, and log in, etc. Of course, you are free to use your own, completely custom, login page. In general, Auth0 Lock is a great choice and can be customized to your taste.
For our example, we will simply change the logo and the default color scheme to a different one for our Centralized Login Test 1
application. The Centralized Login Test 2
application will remain with the default login page.
We have edited the default script in the default HTML page to look like this:
<script>
// Decode utf8 characters properly
var config = JSON.parse(decodeURIComponent(escape(window.atob('@@config@@'))));
config.extraParams = config.extraParams || {};
var connection = config.connection;
var prompt = config.prompt;
var languageDictionary;
var language;
if (config.dict && config.dict.signin && config.dict.signin.title) {
languageDictionary = { title: config.dict.signin.title };
} else if (typeof config.dict === 'string') {
language = config.dict;
}
var loginHint = config.extraParams.login_hint;
var logo;
var color;
if(config.clientID === 'iV2lnrgSBw64uzf1x0MN3svQTYQYcBl2') {
logo = 'https://upload.wikimedia.org/wikipedia/commons/5/54/Emojione_1F60E.svg'
color = 'green'
}
var lock = new Auth0Lock(config.clientID, config.auth0Domain, {
auth: {
redirectUrl: config.callbackURL,
responseType: (config.internalOptions || {}).response_type ||
config.callbackOnLocationHash ? 'token' : 'code',
params: config.internalOptions
},
assetsUrl: config.assetsUrl,
allowedConnections: connection ? [connection] : null,
rememberLastLogin: !prompt,
language: language,
languageDictionary: languageDictionary,
theme: {
logo: logo,
primaryColor: color
},
prefill: loginHint ? { email: loginHint, username: loginHint } : null,
closable: false,
// uncomment if you want small buttons for social providers
// socialButtonStyle: 'small'
});
lock.show();
</script>
Notice the if(config.clientID === 'iV2lnrgSBw64uzf1x0MN3svQTYQYcBl2')
statement. When this client ID is used to log in, we simply change the logo and color scheme used by Auth0 Lock:
var logo;
var color;
if(config.clientID === 'iV2lnrgSBw64uzf1x0MN3svQTYQYcBl2') {
logo = 'https://upload.wikimedia.org/wikipedia/commons/5/54/Emojione_1F60E.svg'
color = 'green'
}
Here is the result:
If you are planning to support more than one social login option, or you are planning to enable more login options in the future, we strongly advise that you use Auth0 Lock. Removing Auth0 Lock implies handling each social login provider manually or with the help of a library such as Auth0.js but allows for 100% custom code.
Conclusion
Centralized logins are safer than embedded login widgets or pages. Relying on the OS's browser allows special security features to be used for your application to prevent credentials theft, and also allows password managers and single sign-on solutions to work across different applications. Furthermore, centralized login pages can be customized for a better user experience and to match the design guidelines of your application. Auth0 Lock can be used as the solution for centralized logins by having the authorization server use it during authentication, further reducing the amount of work that needs to be done for custom and 100% functional login solution. On the iOS side, the Auth0.swift library makes it a breeze to support as many social login providers and login options as required, all with just a few lines of non-invasive code! Sign up for a free Auth0 account today and start working on your iOS apps by focusing on what matters: the logic, not the login widget.
Published at DZone with permission of Sebasti%|-1584275889_1|%n Peyrott, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments