Logo

BirID iOS SDK Documentation

1.2.15

The BirID SDK provides an API to facilitate the authorization process through KapitalBankʼs BirBank mobile application or via a web view if the BirBank app is not installed on the device or if the user has not registered in the BirBank app.

App2App and App2Web Flows

When a client initiates the authorization flow, the BirID SDK firstly attempts to use the BirBank application for the authorization process. If the BirBank application is not installed on the device or if the user is not registered within the BirBank application, the BirBank app redirects the user to the client app where the BirID SDK is located. The SDK then opens its web view to continue the process on the web page. After receiving the authentication code, either from the BirBank app or from the web page, the BirID SDK provides the received authentication code to the client app.

Installation

Package installation

To install the BirID package, go to File → Add Package Dependencies and paste the link provided for installation via email into the search field.

Code setup

Creating BirIDAuthManager

The BirID authentication process is handled by the BirIDAuthManager. To enable BirID authentication, firstly SDK should be configured with the client credentials, properly.

The configuration process should be completed before starting the BirID authentication process - it is recommended to do this during app startup (in AppDelegate or SceneDelegate). The configuration process looks like this:

  1. Create a BirIDConfigurations instance with client-specific credentials.
  2. Set up BirIDAuthManager with these credentials.
// Create BirIDConfigurations instance
let configurations = BirIDConfigurations(
    clientID: "your_client_id",
    redirectURI: "your_client_redirect_uri",
    clientIcon: yourAppIconUImage,
    tokenProvider: tokenProviderInstance,
    appInstanceID: appInstanceID,
    environment: .production // or .development
)

// Set up a new BirIDAuthManager instance with these client-specific configurations
BirIDAuthManager.setConfigurations(configurations)

BirIDConfigurations's initializer parameters:

  1. clientID: you specific client ID provided by the bank.
  2. redirectURI: the redirect URI that will be used to redirect to your application from BirBank after completing the process with failure or success.
  3. clientIcon: icon image of your application. This icon will be shown in loading screen before starting the BirID authentication process.
  4. tokenProvider: the token provider is an optional parameter of type conforming to BirIdTokenProvider protocol. It is used by the BirID SDK to retrieve the latest valid access token from the client app. This token is required to fetch user profile information and display the profile settings web view. If the client app needs to utilize the BirID profile info button component, providing this parameter is mandatory. Conversely, if the client app does not require the profile info button component, you can pass nil as the value of this parameter. ⚠️ Important: The BirID SDK does not maintain a strong reference to the BirIdTokenProvider instance to prevent potential memory leaks. Therefore, it is the responsibility of the client app to ensure that the BirIdTokenProvider instance remains accessible and is not deallocated while the BirID SDK uses it.
  5. appInstanceID: This parameter is used by the BirID SDK for analytics. A valid app instance ID from the Firebase SDK should be provided (refer to the Firebase documentation for instructions on retrieving the app instance ID). If the client app does not use the Firebase SDK, nil should be passed instead. Any other values will be ignored.
  6. environment: this parameter defines in which environment App2Web flow will work. It has 2 possible values:
    1. production: this is default value, by default BirID SDK works in prod environment
    2. development: by setting this value, App2Web flow will work with test environment, and also the profile settings web view will open the test URL. Also, in development environment, the BirID SDK enables logging.

Example for a type conforming to BirIdTokenProvider protocol

final class BirIDTokenProviderInstance: BirIDTokenProvider {
    
    func refreshBirIdToken() async throws -> String {
        // Your flow to get the latest valid access token
        // ...
        
        return your_valid_token
    }
}

Important: Keep in mind that calling the static BirIDAuthManager.setConfigurations(_: BirIDConfigurations) method results in the creation of a new BirIDAuthManager instance. For this reason, this method should be called only once.

After properly configuring BirIDAuthManager, a client can access the BirIDAuthManager instance from anywhere in the application like this:

import BirID

let birIDAuthManager = try BirIDAuthManager.getAuthenticationManager()

The static method BirIDAuthManager.getAuthenticationManager() can throw an error if it's called before setting up credentials with the BirIDAuthManager.setConfigurations(_: BirIDConfigurations) method.

BirIDAuthManager.getAuthenticationManager() returns an already configured BirIDAuthManager instance and can be called as often as needed.

Handling redirections from the BirBank app with BirIDDeeplinkManager

BirIDDeeplinkManager handles deeplink redirections from the BirBank application. It provides only a single method handleBirBankDeeplink(url: URL). The client should pass to this method the received deeplink URL from the BirBank redirection inside the AppDelegate or SceneDelegate.

To get BirIDDeeplinkManager instance, BirIDAuthManager provides a static getDeeplinkManager() throws -> BirIDDeeplinkManager method.

Important: At the moment of calling this method, BirIDAuthManager should already be configured, otherwise this method will throw an error of type BirIDAuthorizationError.couldNotIntializeBirIDDeeplinkManager.

In the SceneDelegate, redirection from the BirBank should be handled inside scene(_ scene: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) by calling handleBirBankDeeplink(url: URL) method.

// SceneDelegate

func scene(_ scene: UIScene, willConnectTo: UISceneSession, options: UIScene.ConnectionOptions) {
    guard let _ = (scene as? UIWindowScene) else { return }
    
    if let urlContext = connectionOptions.urlContexts.first {
        let url = urlContext.url
        
        // Get the BirIDDeeplinkManager instance
        if let birIDDeeplinkManager = try? BirIDAuthManager.getDeeplinkManager() {
            // Pass the URL to the method
            birIDDeeplinkManager.handleBirBankDeeplink(url: url)
        }
    }
}

In AppDelegate handleBirBankDeeplink(url: URL) method should be called inside application(_ application: UIApplication, continue: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool

// AppDelegate

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
    guard userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL else {
        return false
    }
    
    // Get the BirIDDeeplinkManager instance
    if let birIDDeeplinkManager = try? BirIDAuthManager.getDeeplinkManager() {
        // Pass the URL to the method
        birIDDeeplinkManager.handleBirBankDeeplink(url: url)
    }
    
    return true
}

BirID authorization process implementation

Authorization

BirIDAuthManager offers 3 APIs for authorization:

1. authorize(codeChallenge: String, state: String, viewController: UIViewController, loginHint: String?) async -> BirID.BirIDAuthorizationState with async/await syntax.

import BirID

Task {
    let authenticationStatus = await birIDAuthManager.authorize(
    codeChallenge: "your_code_challenge", 
    state: "you_staste_string",
    viewController: viewControllerToPresentWebViewOn,
    loginHint: "994123456789"
    )
    switch authenticationStatus {
    case let .completedSuccessfully(authCredentials):
        // authenticationCode.result contains the received authentication code
        print(authCredentials.result)
    case let .completedWithFailure(authorizationError):
        print(authorizationError)
    case .inProgress, .notStarted:
        break
    }
}

Parameters:

  • codeChallenge: This is the code challenge string that is created by you before starting the authorization process
  • state: State string should be created by you before starting the authorization process
  • viewController: If the authorization will continue in web view, then a web view will be presented on top of this view controller.
  • loginHint: This parameter is used in App2Web flow. If this parameter is not nil, web page will not show phone number input and directly will use the phone number that was passed to this parameter. Please, take into account that phone number should be exactly in this format: "994123456789" - should not be + or any additional character.
  • useOnlyWebFlow: This optional parameter determines whether the authorization process should be restricted to a web view only. The default value is false.

This method returns a value of type BirIDAuthorizationState. Read "Authorization state - BirIDAuthorizationState" section below for more information about BirIDAuthorizationState type.

2. startAuthorization(codeChallenge: String, state: String, viewController: UIViewController, loginHint: String?) using Combine publisher.

This method initiates the authorization process and returns immediately. The client should subscribe to the authorizationState publisher property of the BirIDAuthManager instance to receive authentication status updates.

import BirID

birIDAuthManager.startAuthorization(
    authorizationLevel: .finalAccessToken(codeChallenge: "your_code_challenge", 
    state: "you_staste_string", 
    viewController: viewControllerToPresentWebViewOn,
    loginHint: "994123456789"
)

birIDAuthManager.authorizationState.sink { _ in
    // authorizationState publisher never completes
} receiveValue: { authenticationStatus in
    switch authenticationStatus {
    case let .completedSuccessfully(authCredentials):
        // result contains received final access token
        print(authCredentials.result)
    case let .completedWithFailure(authorizationError):
        print(authorizationError)
    case .inProgress, .notStarted:
        break
    }
}
.store(in: &cancellables)

Important note: authorizationState never emits completion, and for that reason a client always should observe new values inside receiveValue closure.

Parameters

  • codeChallenge: This is the code challenge string that is created by you before starting the authorization process
  • state: State string should be created by you before starting the authorization process
  • viewController: Web view will be presented on this view controller.
  • loginHint: This parameter is used in App2Web flow. If this parameter is not nil, web page will not show a phone number input and directly will use the phone number that was passed to this parameter. Please, take into account that phone number should be exactly in this format: "994123456789" - should not be + or any additional character.
  • useOnlyWebFlow: This optional parameter determines whether the authorization process should be restricted to a web view only. The default value is false.

authorizationState emits values of type BirIDAuthorizationState. Read "Authorization state - BirIDAuthorizationState" section below for more information about BirIDAuthorizationState type.

3. Authorization using the BirID button provided by the BirID SDK

BirIDAuthManager also provides a UI button (as a BirIDLoginButton type, which is an UIView) and the client can use this view in the app directly.

This button itself starts the authorization process when a user taps on button, and BirIDLoginButton's authenticationStatusHandler closure property should be used to observe authentication status changes. Values of type BirIDAuthorizationState are passed to authenticationStatusHandler. Read "Authorization state - BirIDAuthorizationState" section below for more information about BirIDAuthorizationState type.

To get a new button, use makeBirIDLoginButton(viewController: UIViewController, loginHint: String?) method of the BirIDAuthManager instance. Default value of loginHint parameter is nil.

Client also can set login hint dynamically, after creating BirIDLoginButton: use setLoginHint(loginHint: String) method of BirIDLoginButton to set login hint before starting the authorization process.

Before starting an authorization process, BirIDLoginButton should be configured with the proper client credentials using the method setAuthorizationCredentials(codeChallenge: String, state: String). If the process will start before setting credentials, the process will not start and the authenticationStatus will contain an error of type BirIDAuthorizationError.clientCredentialsHaveNotBeenConfigured.

import BirID

// Initialize login button
let button = birIDAuthManager.makeBirIDLoginButton(viewController: viewControllerToPresentWebViewOn, loginHint: "994123456789")

// Set authorization credentials
button.setAuthorizationCredentials(codeChallenge: "your_code_challenge", state: "you_staste_string")

// Implement status handler here.
// This status handler closure will be called in case of any status change
button.authenticationStatusHandler = { authenticationStatus in
    switch authenticationStatus {
    case let .completedSuccessfully(authCredentials):
        print(authCredentials.result)
    case let .completedWithFailure(authorizationError):
        print(authorizationError)
    case .inProgress, .notStarted:
        break
    }
}

// UI related work
view.addSubview(button)
button.frame = .init(origin: .zero, size: .init(width: 300, height: 50))
button.center = view.center

BirIDLoginButton itself manages the title. BirID SDK provides texts for all 3 languages: Azerbaijani, English and Russian.

By default BirIDLoginButton implicitly sets its title according to the client app's current locale. But if client application does not manages its language through Settings app of iOS then you can explicitly ask BirIDLoginButton to set its title for a specific language (Azerbaijani, English or Russian). BirID SDK provides setTitleFor method for BirIDLoginButton.

import BirID

// Initialize login button
let button = birIDAuthManager.makeBirIDLoginButton(viewController: viewControllerToPresentWebViewOn, loginHint: "994123456789")

button.setTitleFor(language: BirIDConfigurations.Language.az)

Parameters

  • language: You can pass .az, .en or .ru
  • useOnlyWebFlow: This optional parameter determines whether the authorization process should be restricted to a web view only. The default value is false.

BirID user profile information UI component

BirID SDK provides an UI component to show / edit user's profile information. Profile component uses BirIdTokenProvider to get the latest valid BirID access token from the client app and fetch user's information.

To create a profile UI component, call makeBirIDProfileSettingsComponentView(token:, viewController:) method of BirIDAuthManager:

import BirID

// Get profile info component view
let profileInfoComponent = birIDAuthManager.makeBirIDProfileSettingsComponentView(viewController: self)

// Set `profileInfoComponent` constraints as an ordinary UIView
view.addSubview(profileInfoComponent)
// Other UI related work

Parameters

  • viewController: Web view will be opened on top of this view controller

The makeBirIDProfileSettingsComponentView(viewController:) method returns BirIDProfileSettingsComponentView, which automatically fetches the user's information upon initialization.

BirIDProfileSettingsComponentView provides AsyncStream property called profileInfoErrorStream - it streams errors type of BirIDCustomerProfileInfoError and client app can observe this stream to handle errors which occurs during getting profile information (when profile info buttons initializes, after closing the profile settings web view or when updateCustomerInfo() async method called by the client app).

As noted above, BirIDProfileSettingsComponentView provides the updateCustomerInfo() async method, allowing manual fetching of the profile information. If an error occurs during this process, it will stream an error type of BirIDCustomerProfileInfoError. By default, the component handles profile info fetching automatically when needed (for example, after closing the profile information page), but this method enables re-fetching of the data when required by the client app's custom flow.

import BirID

// Get profile info component view
let profileInfoComponent = birIDAuthManager.makeBirIDProfileSettingsComponentView(viewController: self)

Task {
    for await error in profileInfoComponent.profileInfoErrorStream {
        print("error: \(error)")
    }
}

When the user taps on the profile info UI component, a web view is opened, allowing clients to edit their information. After closing the web view, the profile info component automatically reloads (re-fetches) the data to display the updated information.

Status and error types

Authorization types

Authorization state - BirIDAuthorizationState

As an authorization state type is used BirIDAuthorizationState enum. It has 4 cases:

  1. notStarted: This is a default status.
  2. inProgress: This value is set after initiating an authorization process.
  3. completedSuccessfully(BirIDAuthCredentialsResult): After the authorization process is successfully completed, this value is emitted, containing the received authentication data.
  4. completedWithFailure(BirIDAuthorizationError): If the authorization process fails, this value is emitted along with the corresponding error.

BirID authorization result - BirIDAuthCredentialsResult

After completing the authorization process successfully, a client receives BirIDAuthCredentialsResult instance and its result property contains the final authentication code.

BirID authorization errors - BirIDAuthorizationError

During the BirID authorization process, the BirID SDK returns errors of the BirIDAuthorizationError type.

BirIDAuthorizationError has the following error cases:

  • clientCredentialsHaveNotBeenConfigured
  • couldNotStartBirIDAuthorizationProcess
  • couldNotReceiveValue
  • couldNotCreateDeeplinkURL
  • responseCredentialsAreInvalid
  • couldNotIntializeBirIDDeeplinkManager
  • presentingViewControllerIsNil
  • unknownError

BirID profile information types

BirID profile info errors - BirIDCustomerProfileInfoError

  • couldNotFoundTokenProviderInstance
  • couldNotExchangeToken
  • couldNotGetTokenFromTokenProvider
  • couldNotFetchCustomerProfileInfo

Changelog 1.2.15

#Changed

  • Updated signing certificate

Troubleshooting

  • In development mode, the BirID SDK logs every step of its workflow. These logs include all warnings and errors that occur.
  • couldNotFoundTokenProviderInstance - this error occurs when the BirID SDK is unable to find the token provider instance. This typically happens when the client application does not maintain a strong reference to the token provider, causing it to be deallocated. Read more about token provider parameter here.