CocoaPods trunk is moving to be read-only. Read more on the blog, there are 19 months to go.
TestsTested | ✓ |
LangLanguage | SwiftSwift |
License | MIT |
ReleasedLast Release | Nov 2016 |
SwiftSwift Version | 3.0.1 |
SPMSupports SPM | ✗ |
Maintained by Philipp Ebner.
Depends on: | |
Locksmith | ~> 3.0 |
JWTDecode | ~> 2.0 |
JSONWebToken | ~> 2.0.1 |
7Pass iOS SDK is a Swift library for interacting with the 7Pass SSO service. You can use this library to implement authentication for your app and take advantage of the already existing features that 7Pass SSO offers.
To run the example project, clone the repo, and run pod install
from the Example directory first.
SevenPassSDK is available through CocoaPods. To install it, simply add the following line to your Podfile:
source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!
target 'MyApp' do
pod 'SevenPassSDK'
end
To demonstrate the functionality of the library, there's a sample application available. The application is configured to run against the QA instance of 7Pass and uses test credentials (Example/SevenPassSDK/SsoManager.swift). Feel free to use these credentials while testing but you need to obtain real credentials before releasing your app.
To obtain the real credentials, you first need to contact the 7Pass Tech Team.
Once you have the credentials available, you can go ahead and type
pod install
in Example
directory, open SevenPassSDK.xcworkspace
project in XCode,
select SevenPassSDK-Example
build configuration and run it.
The sample application should now start within the configured device (or the emulator) and should provide several tabs each implementing a feature you might want to use in your app.
You are strongly encouraged to go over the sample application to see how the API should be used.
If you're starting the development, it's always a good idea to work against a non live instance of the 7Pass SSO service. In this case, we'll use the QA environment. Don't forget to switch to the production one before you release your application to the public.
First, let's initialize the library with sample configuration:
let configuration = SevenPassConfiguration(
consumerKey: "56a0982fcd8fb606d000b233",
consumerSecret: "2e7b77f99be28d80a60e9a2d2c664835ef2e02c05bf929f60450c87c15a59992",
callbackUri: "oauthtest://oauth-callback",
environment: "qa"
)
let sso = SevenPass(configuration: configuration)
The library offers several ways of logging in the user. The result of
every login is eventually an instance of TokenSet
. A TokenSet
represents the three different token types the server will return:
Access token - This token proofs the identity of the user and is thus included in almost every remote call the library performs. Every access token is valid just for 2 hours. In cannot be used after that.
Refresh token - This token can be used to get a new TokenSet
with a fresh access token. Its expiration time is set to 90 days
and its prolonged every time you use it. If however the token
expired, you need to ask the user to login again.
ID token - This token contains information (claims) about the logged in user. You can for example get the user's ID, name, email etc.
You don't generally need to worry about the current TokenSet
and how
it's used but you need to make sure it's valid before use:
sso.authorize(
scopes: ["openid", "profile", "email"],
success: { tokenSet in
// tokenSet.accessToken?.isExpired()
// tokenSet.refreshToken?.isExpired()
},
failure: { error in
print(error.localizedDescription)
}
)
If that access token is fresh, you can use the token set to perform API calls. After that, you can use that TokenSet to initialize an API client:
let accountClient = sso.accountClient(tokenSet)
Otherwise, you need to refresh it, using a refresh token.
let refreshTokenString = tokenSet.refreshToken!.token
sso.authorize(refreshToken: refreshTokenString,
success: { tokenSet in
// Do some stuff
},
failure: errorHandler
)
Of course, you need to make sure that the refresh token itself is fresh. If it's not, you cannot get a fresh access token and need to ask the user to log in again. If you're using the Web view flow and the user has an active session on 7Pass, chances are he/she will come back immediately without having to fill in the credentials.
Since the same token set can be used in the span of multiple days, you should store it instead of forcing the user to re-login every time. There's a utility class you can use to save the token set into the keychain.
let tokenSetCache = SevenPassTokenSetCache(configuration: sso.configuration)
// Load token set from a keychain
let tokenSet = tokenSetCache.load()
// Store token set in the keychain
tokenSetCache.tokenSet = tokenSet
tokenSetCache.save()
// Delete token set
tokenSetCache.delete()
The most basic way of logging in the user is using the Web view.
sso.authorize(
scopes: ["openid", "profile", "email"],
success: { tokenSet in
// Do some stuff
},
failure: errorHandler
)
The code will open the provided Web view which will navigate to the 7Pass's login dialog. From there, the user has several options, he/she can use his/her credentials directly or use Google/Facebook.
Once the process is done, the web view will automatically close and the result will be provided in the callback.
Once the process is successfully finished, we can use the obtained
tokenSet
to instantiate API client.
In case you want to provide more native experience for the user, the library offers logging in using the user's 7Pass login and password (grant_type = password). This way, you get to design the login form yourself using the iOS widgets.
sso.authorize(
login: login.text!,
password: password.text!,
scopes: ["openid", "profile", "email"],
success: { tokenSet in
// Do some stuff
},
failure: errorHandler
)
In situations when the user is already logged in using some other
service (currently supported services are Facebook or Google), you can
use the social
flow.
In this flow, you provide an access token you've received from the other service and 7Pass will make sure to create a new 7Pass account (with all of the user details) or identify an existing 7Pass account.
sso.authorize(
providerName: "facebook",
accessToken: "foobarbaz",
scopes: ["openid", "profile", "email"],
success: { tokenSet in
// Do some stuff
},
failure: errorHandler
)
In case, that you already have valid TokenSet
(fe. from password or social login) or a valid autologin_token
and you want to create user session in the WebView, you can utilize autologin
method.
By default this method sets response_type = "none"
In the app's perspective, a user is logged in when you have a fresh
TokenSet
. In order to log the user out, all that's required is to
"forget" the tokens. Optionally, you can destroy the user's session in WebView as well.
To use it, just call
sso.destroyWebviewSession(failure: errorHandler)
It's important to note that if the user hasn't accepted all of the necessary consents for the client or the service the client belongs to, the login through Username & Password or Social method might fail and it's necessary to handle this situation in your error handling callback.
func errorHandler(error: NSError) {
// Let autologin handle interaction_required errors
if let errorMessage = error.userInfo["error"] as? String where errorMessage == "interaction_required" {
let autologinToken = error.userInfo["autologin_token"] as! String
self.sso.autologin(
autologinToken: autologinToken,
scopes: ["openid", "profile", "email"],
params: ["response_type": "id_token+token"],
success: { tokenSet in
// Do some stuff
},
failure: errorHandler
)
}
// Handle other errors
}
TokenSet has to include valid access_token
and id_token
sso.autologin(tokenSet,
scopes: ["openid", "profile", "email"],
rememberMe: false,
success: { tokenSet in
// Do some stuff
},
failure: errorHandler
)
Used for example when interaction_required
error is returned from the server.
sso.autologin(
autologinToken: "AUTOLOGINTOKEN",
scopes: ["openid", "profile", "email"],
params: ["response_type": "id_token+token"],
success: { tokenSet in
// Do some stuff
},
failure: errorHandler
)
Now that you have an account's TokenSet
, you can already identify the user and
proceed to your actual app. You can, however, request further details about the
user. Each method call corresponds to an endpoint available on 7Pass, you're
encouraged to go through the
documentation.
let accountClient = sso.accountClient(tokenSet)
The simplest remote call you can make is to request the account's details.
accountClient.get("me",
success: { json, response in
print(json)
},
failure: errorHandler
)
Note that you might not need to request the additional user details as the most
basic ones are already present in the ID Token as part of the TokenSet
. It
generally depends on your app's requirements.
tokenSet.idTokenDecoded
Account client is an instance of SevenPassRefreshingClient
which handles refreshing of the tokens for you seamlessly.
Optionally callback can be supplied as an argument to accountClient
method:
let accountClient = sso.accountClient(
tokenSet,
tokenSetUpdated: { tokenSet in
// Save new tokens
tokenSetCache.tokenSet = tokenSet
tokenSetCache.save()
}
)
A credentials client can be used to perform various administrative tasks not bound to a particular account. For example, you can verify whether an email address is unused or whether a password is of sufficient quality and others. Getting this kind of client doesn't require any interaction from the user, it's issued based on your client's credentials.
Same as with the Account client you will receive a valid TokenSet
, however,
the token set will not contain anything but an access token and its validity
will be limited to just 15 minutes. Since the token set doesn't have a Refresh
token, it's necessary to request a new one after the 15 minutes have passed if
required.
sso.authorize(
parameters: [
"grant_type": "client_credentials",
],
success: { tokenSet in
// Do some stuff
},
failure: errorHandler
)
Once you have the token set available, you can get the Credentials client and invoke the available methods.
let credentialsClient = sso.credentialsClient(tokenSet)
Validates the provided email address and returns whether it's available for use. You can use this method to give immediate feedback to users (i.e. during a registration process). See more information in the documentation.
deviceClient.post("checkMail",
parameters: [
"email": login.text!,
"flags": [
"client_id": sso.configuration.consumerKey
]
],
success: { json, response in
if let error = json["data"]?["error"] as? String {
// E-Mail is invalid
}
},
failure: errorHandler
)
The response also contains a suggested email address so that you can easily provide the "did you mean x?" functionality in case the user has made a typo in the address.
As a next step in a registration form you might want to provide a feedback regarding the validity of the provided password. You can find all of the requirements and the response codes in the documentation.
deviceClient.post("checkPassword",
parameters: [
"password": password.text!
],
success: { json, response in
if let errors = json["data"]?["errors"] as? [String] {
// Password is not valid, got array of errors
}
},
failure: errorHandler
)
Finally, you can create a brand you account directly. The only mandatory parameter is a valid email address and a password. If you don't want to force your users to type in the password, you can request an auto generated password (in which case only the email address is required).
deviceClient.post("registration",
parameters: [
"email": login.text!,
"password": password.text!,
"flags": [
"client": [
"id": sso.configuration.consumerKey, // Associate with a service
"agb": true, // Accept ToS consents (user should given permissions beforehand)
"dsb": true, // Accept privacy policy consents (user should given permissions beforehand)
"implicit": true // Accept implicit optins
]
]
],
success: { json, response in
// Account creation status returned in json constant
},
failure: errorHandler
)
Create your own custom class implemeting SevenPassURLHandlerType
protocol and pass that instance to SevenPass
init.
let sso = SevenPass(configuration: configuration, urlHandler: YourWebViewController())
This library comes bundled with custom fork of OAuthSwift library, that can be downloaded and builded using Carthage, to rebuild it, run:
carthage update --platform iOS
SevenPassSDK is available under the MIT license. See the LICENSE file for more info.