Swiftpack.co - schibsted/account-sdk-ios-web as Swift Package

Swiftpack.co is a collection of thousands of indexed Swift packages. Search packages.
See all packages published by schibsted.
schibsted/account-sdk-ios-web 3.4.2
Schibsted account SDK for iOS
⭐️ 3
🕓 2 weeks ago
iOS
.package(url: "https://github.com/schibsted/account-sdk-ios-web.git", from: "3.4.2")

Schibsted account iOS SDK

Build Status GitHub release (latest by date) Platform License: MIT

New implementation of the Schibsted account iOS SDK using the web flows via ASWebAuthenticationSession.

API documentation can be found here.

Getting started

To implement login with Schibsted account in your app, please first have a look at our getting started documentation. This will help you create a client and configure the necessary data.

Note: This SDK requires your client to be registered as a public_mobile_client in Self Service (see getting started documentation for more help).

Note: If you have implemented the Old Schibsted SDK in your app, and want these users to remain logged in, do not forget to add the SessionStorageConfig on instantiating your Client, Client(configuration:sessionStorageConfig:httpClient:). The function Client.resumeLastLoggedInUser(completion: @escaping (User?) -> Void) will then handle upgrading the user old SDK credentials.

Requirements

  • iOS 12.0+

Installation

Swift Package Manager: .package(url: "https://github.com/schibsted/account-sdk-ios-web")

CocoaPods pod 'AccountSDKIOSWeb', '~> 2.2.0'

Usage

Login user and fetch profile data

let clientConfiguration = ClientConfiguration(environment: .pre,
                                              clientId: clientId,
                                              redirectURI: redirectURI)
let client = Client(configuration: clientConfiguration) 
let contextProvider = ASWebAuthSessionContextProvider()
let asWebAuthSession = client.getLoginSession(contextProvider: contextProvider, withSSO: true, completion: { result in
    switch result {
    case .success(let user):
        print("Success - logged in as \(String(describing: user.uuid))")
        self.user = user
    case .failure(let error):
        print(error)
    }

    user.fetchProfileData { result in
        switch result {
        case .success(let userData):
            print(userData)
        case .failure(let error):
            print(error)
        }
    }
})

asWebAuthSession.start()

Get notified on logout

let userDelegate: UserDelegate = MyUserDelegate()
user?.delegates.addDelegate(userDelegate)
self.userDelegate = userDelegate // Needs to be retained

class MyUserDelegate: UserDelegate {
    func userDidLogout() {
        print("Callback will be invoked when user is logged out")
    }
}

Notes on using custom URI schemes

When using custom URI as redirect URI, the OS handles opening the app associated with the link instead of triggering the ASWebAuthenticationSession callback. It results in the ASWebAuthenticationSession view not being closed properly, which instead needs to be done manually:

  1. Get a reference to ASWebAuthenticationSession and start it:

    func handleLoginResult(_ result: Result<User, LoginError>) {
        switch result {
        case .success(let user):
            print("Success - logged-in as \(user.uuid)!")
            self.user = user
        case .failure(let error):
            print(error)
        }
    }
    
    let contextProvider = ASWebAuthSessionContextProvider()
    asWebAuthSession = client.getLoginSession(contextProvider: contextProvider, withSSO: true, completion: handleLoginResult)
    asWebAuthSession.start() // this will trigger the web context asking the user to login
    
  2. Handle the response as an incoming URL, e.g. via your app's delegate application(_:open:options:):

    func application(_ application: UIApplication,
                     open url: URL,
                     options: [UIApplicationOpenURLOptionsKey : Any] = [:] ) -> Bool {
        client.handleAuthenticationResponse(url: url) { result in
            DispatchQueue.main.async {
                asWebAuthSession.cancel() // manually close the ASWebAuthenticationSession
            }
            handleLoginResult(result)
        }
    }
    
  3. When implementing Swedish BankID authentication the parent app must catch the redirect URI and return with no action. Please make sure that handleAuthenticationResponse is not called for the BankID redirect. The URI scheme that is used to redirect back to the parent app from BankID will have the following format: {app_uri_scheme}:/bankId. Find below a code example:

    func handleOnOpenUrl(url: URL) {
        if url.pathComponents.contains("bankId") {
            return
        }
        
        client.handleAuthenticationResponse(url: url) { result in
            DispatchQueue.main.async {
                asWebAuthSession.cancel() // manually close the ASWebAuthenticationSession
            }
            handleLoginResult(result)
        }
    }
    

Obtaining tokens externally

Tokens can be obtained externally and injected into SDK for the already created users. This can be useful in the case of a test scenario. To do this, first you need to start the web login flow with the request as follow:

GET "${BASE_URL}/oauth/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=openid%20offline_access&state=${state}&nonce=${nonce}&code_challenge=${CODE_CHALLENGE}&code_challenge_method=S256&prompt=select_account"

where: BASE_URL - base URL of Schibsted Account environment client_id - public mobile client id redirect_uri - redirect URI for given client state - A string value sent by the client that protects end user from CSRF attacks. It's a randomly generated string of 10 characters (both letters and numbers) nonce - A string value sent by the client that is included in the resulting ID token as a claim. The client must then verify this value to mitigate token replay attacks. It's a randomly generated string of 10 characters (both letters and numbers) code_challenge - PKCE calculated from code_verifier

On the finish, web flow returns URL with query parameters state and code. Tokens can be obtained with the following request:

curl {BASE_URL}/oauth/token \
   -X POST \
   -H "X-OIDC: v1" \
   -d "client_id={client_id}" \
   -d "grant_type=authorization_code" \
   -d "code={code_from_login_flow}" \
   -d "code_verifier={code_verifier}" \
   -d "redirect_uri={redirect_uri}"

where code_verifier is the same which was used for calculating code_challenge. It can be a randomly generated string of 60 characters (both letters and numbers)

Configuring logging

This SDK uses SwiftLog, allowing you to easily customise the logging. The logger can be modified, for example to change the log level, via the following code:

SchibstedAccountLogger.instance.logLevel = .debug

How it works

This SDK implements the best practices for user authentication via an OpenID Connect identity provider:

  • It uses ASWebAuthenticationSession. This allows for single-sign on between apps, with the user being recognized as a returning user to Schibsted account via cookies. On iOS 13 and above this behavior can be disabled, which also removes the extra user prompt about allowing to use Schibsted account for login, using withSSO: false in Client.getLoginSession(withMFA:loginHint:extraScopeValues:withSSO:completion:).
  • After the completed user authentication, user tokens are obtained and stored securely in the keychain storage.
    • The ID Token is validated according to the specification. The signature of the ID Token (which is a JWS) is verified by the library JOSESwift.

    • Authenticated requests to backend services can be done via AuthenticatedURLSession.dataTask(with: URLRequest, completionHandler: ... The SDK will automatically inject the user access token as a Bearer token in the HTTP Authorization request header. If the access token is rejected with a 401 Unauthorized response (e.g. due to having expired), the SDK will try to use the refresh token to obtain a new access token and then retry the request once more.

      Note: If the refresh token request fails, due to the refresh token itself having expired or been invalidated by the user, the SDK will log the user out.

  • Upon opening the app, the last logged-in user can be resumed by the SDK by trying to read previously stored tokens from the keychain storage. This will be handled by once invoking Client.resumeLastLoggedInUser(completion: @escaping (User?) -> Void) upon app start.

Simplified Login

Configuring Simplified Login

Prerequisite: Applications need to be on the same Apple Development account in order to have access to the shared keychain.

  1. In your application target, add Keychain Sharing capability with keychain group set to com.schibsted.simplifiedLogin.
  2. Creating client, pass additional parameter appIdentifierPrefix. It is usually the same as team identifier prefix - 10 characters combination of both numbers and letters assigned by Apple.
let client = Client(configuration: clientConfiguration, appIdentifierPrefix: "xxxxxxxxxx") 
  1. Create SimplifiedLoginManager and call getSimplifiedLogin method anytime you want to present SL to user.
    let context = ASWebAuthSessionContextProvider()
    let manager = SimplifiedLoginManager(client: client, contextProvider: context, env: clientConfiguration.env) { result in
            print("Catch login result \(result)")
    }
    manager.requestSimplifiedLogin("Your brand name visible on UI") { result in
        switch (result) {
        case .success():
            print("success")
        case .failure(let error):
            print("Catch error from presenting SL \(error)")
        }
    }

If you want to present Simplified Login UI on a specific UIWindow, you need to pass the optional parameter window calling requestSimplifiedLogin method.

Tracking

The Account SDK does some internal tracking (mostly for the Simplified Login) and allows a TrackingEventsHandler to be set during the Client's initialization. To fulfill this, you can either implement it yourself or use one which is already implemented.

Internal: There is an internal Schibsted Tracking implementation for the identity SDK available here It integrates the latest Account SDK with the latest Pulse Tracking SDK for iOS.

Localization

Simplified Login comes with the following localization support:

  1. 🇳🇴 Norwegian Bokmål
  2. 🇸🇪 Swedish
  3. 🇫🇮 Finnish
  4. 🇩🇰 Danish
  5. 🇬🇧 English (Default)

Releasing

  1. Make sure all changes going in the release have been merged to master branch.
  2. Update new SDK version number in both Version.swift and AccountSDKIOSWeb.podspec files. Commit this change to the master branch.
  3. Create a new release via GitHub.
    1. Enter the version number as the tag name and include the changes in the release description.
  4. Publish the pod by running pod trunk push AccountSDKIOSWeb.podspec from your local machine.
    1. To successfully call pod trunk you need to first setup pod trunk on your computer and be added as a contributor to the library. See https://guides.cocoapods.org/making/getting-setup-with-trunk.html

GitHub

link
Stars: 3
Last commit: 35 seconds ago
jonrohan Something's broken? Yell at me @ptrpavlik. Praise and feedback (and money) is also welcome.

Release Notes

3.4.2
2 weeks ago

What's Changed

  • 101 Update readme with information about handling BankID redirect
  • 87 Handle cancel redirect URL in the authentication response

Full Changelog: https://github.com/schibsted/account-sdk-ios-web/compare/3.4.1...3.4.2

Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics